[
  {
    "path": ".gitignore",
    "content": "INSTALL\ntest-driver\ntest/test-suite.log\ntest/test_all.sh.log\ntest/test_all.sh.trs\npo/nip2.pot\nnip2-*.tar.gz\n*.o\n.*.swp\nTAGS\ntags\nMakefile\nscan\nMakefile.in\nconfig.*\nautom4te.cache\naclocal.m4\nm4/\ncompile\nconfigure\ndepcomp\ninstall-sh\nlibtool\nltmain.sh\nmissing\nmkinstalldirs\nnip2.desktop\nnip2.spec\npo/POTFILES\nfred\npo/Makefile.in.in\nsrc/.deps/\nsrc/gtksheet-marshal.c\nsrc/gtksheettypebuiltins.c\nsrc/lex.c\nsrc/nip2\nsrc/parse.c\nsrc/parse.h\nstamp-h1\ntest/test_all.sh\nylwrap\ndoc/html/\ndoc/pdf/\n"
  },
  {
    "path": "AUTHORS",
    "content": "Authors of nip2\n\n\tJohn Cupitt \n\tJoe Padfield\n\tHans Breuer\n\tRich Lott\n\tLeo Davidson\n\nPlus helpful comments and suggestions from many others.\n"
  },
  {
    "path": "COPYING",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n                            NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.\n"
  },
  {
    "path": "ChangeLog",
    "content": "started 8.9.2 22/11/23\n- fix a lockup with comment characters in REPL [MvGulik]\n\nstarted 8.9.1 15/2/23\n- fix build with --std=c99 [Schamschula]\n\nstarted 8.9.0 10/4/20\n- add find_trim\n\nstarted 8.7.1 13/11/18\n- fix uint status bar pixels >2**31 [Rob Erdmann]\n- fix crash on redhat [bgilbert]\n\nstarted 8.7.0 22/5/18\n- added vips7compat.h include for libvips 8.7\n- more output for -V to help debugging CLI mode\n- revised Text widget\n- added Canny\n- Sobel uses the new vips_sobel() operator\n- add mitchell kernel\n- add 8.6 compat \n\nstarted 8.6.1 1/5/18\n- better enum display in header\n\nstarted 8.6.0 16/8/17\n- add scRGB support\n- improve radiance support\n- add composite to alpha menu\n- add Image / Select / Fill \n- add combine mode to indexed histogram\n- better compat handling\n\nstarted 8.5.1 22/1/17\n- fix a crash bug\n- make separate Image / Alpha menu, add Add, Extract, Drop\n\nstarted 8.5 24/1/17\n- add max_slope to lhist\n- gaussnoise goes via vips8 now\n- add snake option to array join [Joe Padfield]\n- parse_float was broken for numbers starting \"0.\"\n- add alpha section to Image / Band menu ... Flatten, Premultiply,\n  Unpremultiply, Blend\n- add Entropy to hist menu\n\nstarted 8.4.1 25/9/16\n- simplify nip2-icon.rc build, bgilbert\n\nstarted 8.4\n- added Perlin and Worley menu items\n\nstarted 8.3.1 on 19/5/16\n- disable debug by default, thanks Benjamin\n- configure changes to help win64\n- improve middle-drag in ws and image view\n- be more careful about the name of the image file we remove on close\n- simpler system for positioning new columns\n- rename boostrap.sh as autogen to help snapcraft\n\nstarted 8.3.0 on 28/3/16\n- move path search stuff into _convert from _magick\n- added autotrace menu item\n- resize now uses vips_resize() behind the scenes\n- added Kernel type for picking interpolators\n\nstarted 8.2.1 on 4/12/16\n- tiny improvement to idle handling\n- added R2 to linreg and linregw\n- fixed vips_call for image array args\n- changed default unsharp settings to be less brutal and to ban -ve sharpness\n\nstarted 8.2 on 4/11/15\n- version bump to match vips\n- fix icc_import with RGBA images\n- added mapim and Image / Transform / Map\n- added Filter / Coordinate Transform ... polar and rect in there\n\nstarted 8.0 on 3/5/15\n- version bump for vips-8.0 release\n- fix a race in Makefile.am, thanks nieder \n- get rid of run-nip2.sh, mostly useless, thanks nieder \n\nstarted 7.42.1 started 30/12/14\n- add fftw3 configure\n- fix gvc configure\n\nstarted 7.42.0 started 4/11/14\n- removed the non-nip2 bits of the test suite, they are in vips now\n\nstarted 7.41.0 8/10/14\n- remove greyc stuff\n\nstarted 7.40.5 17/9/14\n- improve .desktop file\n- fix Lch -> Yxy conversion\n\nstarted 7.40.4 19/8/14\n- swap the HP printer profile for a freer one\n- swap lena for a PD sample\n\nstarted 7.40.3 4/7/14\n- fix compile with older libvipes, now goes back to at least 7.30 \n- fix more bash-isms to help freebsd\n- don't test IM by default, in case it's not installed\n- get graph display working again with latest libgvc\n\nstarted 7.40.2 30/6/14\n- fix quoting in magick commands\n- auto-fallback to gm if no convert found\n- use libxml2 pretty-printer\n\nstarted 7.40.1 24/6/14\n- update copyright date\n- larger max size for dialog text\n- fix popen()pclose() warnings on win\n\nstarted 7.40.0 23/6/14\n- version bump\n\nstarted 7.39.0 28/1/14\n- add optional libgsf dependency\n- added export-to-file to plotwindow\n- added graph_export_image\n- added .to_image to Plot\n- added .caption / .xcaption / .ycaption options to Plot\n- added caption / xcaption / ycaption options to Plot_object\n- added snibgo's much better ImageMagick menu items\n- added test_magick.ws to make check\n- added series_captions option to Plot_object\n- support imagevec as a vips_call argument\n- added system2 and system3\n- added Magick.version detector\n- better image cache menu item\n- added hough_line and hough_circle \n- removed tear-off menus, gtk+ has deprecated them\n\nstarted 7.38.4 23/6/14\n- fix memccpy() in tool.c, thanks khindenburg\n\nstarted 7.38.3 16/5/14\n- fix tiny timeout error\n\nstarted 7.38.2 21/1/14\n- fix a tiny mem leak\n\nstarted 7.38.1 20/1/14\n- fix scRGB display\n\nstarted 7.38.0 18/1/14\n- version bump\n\nstarted 7.36.6 9/1/14\n- fix some clang warnings\n- add some brackets to find_colour-calib, seems to help clang builds with\n  optimiser, strangely\n\nstarted 7.36.5 19/12/13\n- add \"merge into ws\" item to rmb tab gutter menu\n- oops, progress feedback was accidentally disabled\n- error boxes were accidentally supressed\n\nstarted 7.36.4 18/10/13\n- fix bootstrap warnings\n- use g_mkdir()\n- better load of workspaces with closed columns\n\nstarted 7.36.2 8/10/13\n- add --profile option\n- fix + button on wsgv\n\nstarted 7.36.1 7/10/13\n- better ^Q behaviour, thanks MvGulik\n\nstarted 7.36.0 3/10/13\n\nstarted 7.35.0 9/8/13\n- removed old thing to show API docs (thanks Benjamin)\n- measure now lets you pick the area to measure, and draws sample patches\n- new column now goes to right of current column, not alphabetically\n- detect doubleclick on ws tab label background\n- tabs can be locked\n- tabs have error indicators\n\nstarted 7.34.1 28/6/13\n- fix build on older gtk, thanks Joe\n\nstarted 7.34.0 7/6/13\n- version bump\n- drag col to far left to insert\n- fix compat warning text\n- fix prefs revert to default\n- reenable scroll-wheel slider change in paintbox and conversionview\n- insert new columns in alphabetical position\n\nstarted 7.33.0 14/3/13\n- add tabs\n- get_* work on Groups\n- columns snap to a grid\n\nstarted 7.32.2 12/3/13\n- add a test for seq mode \n\nstarted 7.32.1 7/3/13\n- remove \"fred\" from dist\n- license updates, thanks Benjamin\n\nstarted 7.32.0 22/1/13\n- added colour temperature to colour and colour to colour temperature\n- removed gtksheet, broken on windows, no future on anywhere\n- added histogram invert\n- much better Matrix / New items\n\nstarted 7.31 3/9/12\n- don't show tooltips for toolkit menu items with submenus (thanks MvGulik)\n- better definition of foldr1\n- better definition of to_group (thanks MvGulik)\n- better defintion of scan, renamed as scanl\n- don't clear def browser filter on text buffer ::changed in program window\n- update program window filter on cursor move\n\nstarted 7.30.2  24/12/12\n- small fix for OS X ML\n\nstarted 7.30.1  7/8/12\n- update rectangle select (thanks Joe)\n- group save was broken (thanks John VV)\n\nstarted 7.30.0  20/7/12\n- update for new version\n\nstarted 7.29.0  20/6/12\n- added skew and kurtosis\n- added Definition Browser to program window, shows stuff as you program\n- program window cleanups\n- Find calib is much faster and handles linear float input better\n- Find calib optionally leaves brightness untouched\n- Apply calib handles linear float input better\n- add a 7.28 compat area\n\nstarted 7.28.5, 8/5/12\n- change keybinding for Delete to ctrl+bsp to work around a GTK bug\n- rewrite filenames on workspace load, file selection and file drag-drop\n\nstarted 7.28.4, 6/5/12\n- added bigtiff save option\n\nstarted 7.28.3, 17/4/12\n- up max size of user defs, lets you work with larger groups\n\nstarted 7.28.2, 10/4/12\n- complex constant divided by real constant was wrong\n- more self-tests\n- disable the libvips operation cache, it doesn't know about invalidate and\n  breaks various things\n\nstarted 7.28.1, 12/3/12\n- oop, add Array to private Type decoder (thanks MvGulik)\n- new version of Draw / Scale (thanks Joe)\n\nstarted 7.28.0, 30/1/12\n- bump for new stable version\n- better \"make check\"\n- disable asserts and cast checks in production builds\n- much faster draw_rect\n- remove background stipple from image display (helps win32)\n- Draw / Rect lets you adjust line thickness\n- added Draw / Scale (thanks Joe)\n- added VipsStats test (thanks Rebecca)\n\nstarted 7.27.0, 23/8/11\n- bump for new cycle\n- add raw load/save test\n- test fits load/save\n- better image header display, now on right-click rowview menu\n- search image header\n- rmb popup menu on imageview windows\n- popup menu button widget\n- added \"vips_call\" builtin to call any vips8 operation\n- added Matrix / New / Series\n- added Matrix / Sort\n\nstarted 7.26.5, 31/12/11\n- fix possible security thing in yyerror(), thanks Jay\n\nstarted 7.26.4, 14/9/11\n- better error messages for print-main\n\nstarted 7.26.3, 15/8/11\n- tidier cancel messages\n- disable dump.c debug\n\nstarted 7.26.2, 10/8/11\n- update threading test for fixed benchmark\n- fix blocking in progress update (thanks M. v. Gulik)\n- search returns empty list for file not found rather than throwing an\n  exception\n- magick_command tries to use $VIPSHOME/bin/convert.exe, if it exists\n- magick_command tries quotes filenames\n\nstarted 7.26.1, 28/7/11\n- much better threading test, based on im_benchmarkn()\n\nstarted 7.26.0, 26/7/11\n- version bump\n\nstarted 7.25.0, 7/1/11\n- version bump\n- oop spelling \n- fix a crash with resizing dirty matrices\n- minor fix to vips_call error messages\n- more tests in \"make check\"\n- moved vips_cache and vips_call out of the vips_ namespace\n- added approx. option to blur/sharpen\n- added Matrix / New Circular / Square / Identity\n- removed the splash screen, all machines are fast enough now\n- added EXEEXT env var\n- better \"bad superclass\" error\n- changed order of args for Option_enum\n- added Option_list\n- added a simple Magick menu\n- better compat handling\n- added a 7.24 compat dir\n- removed the \"already open for read\" error on save, too annoying for the\n  small amount of safety it gave you\n- test pfm load/save\n- also test cmyk jpeg/tif load/save\n- allow file modes in filenames, so \"nip2 wtc_pyr.tif:2\" works\n- show main window much sooner during workspace load and startup\n- better progress feedback\n- added Image / Select / Rectangle\n- added Image / Draw menu\n\nstarted 7.24.0, 30/11/10\n- bump for 7.24\n- fix build without graphviz\n- much faster colour atlas menu item\n- fix make check, again\n- fix debug everywhere\n- fix a va_args problem on Windows\n\nstarted 7.23.0, 2/8/10\n- fix a crash in thumbnail preview with large images\n- doublelick while painting with a rect (eg. text) would crash (thanks\n  M.v.Gulik)\n- drag multiple workspaces to the mainw could get stuck (thanks M.v.Gulik)\n- find-again before find would crash (thanks M.v.Gulik)\n- open multiple ws in file browser would crash\n- added filemodel_set_window_hint() and filemodel_get_window_hint() to help ^Q\n  display popups on the right window\n- split vips_call.c to vips_call / vips_cache\n- added IM_TYPE_RW support to vips_call.c: you can call paintbox operations\n  directly now\n- gtk_window_present() parents when we show children in iwindow.c\n- fix a crash with win32 and two PRESS on a window while in rect mode \n  (thanks M.v.Gulik)\n- fix a crash with duplicate Colour (thanks M.v.Gulik)\n- fix an occasional crash with ^Q in imageview\n- added high-quality thumbnail option (thanks Martin)\n- set lib env var more carefully (thanks Jay)\n- configure tests for libgvc, the graphviz library\n- added \"Workspace as graph\" view option\n- better \"segment\" menu item\n- \"value\" menu item\n- rename stuff to avoid name clashes with cfitsio\n- \"make check\" runs twice, with and without vector stuff\n- better infobar behaviour\n- test_conv.ws tests convolution carefully\n- nib radius slider replaces the old 1-10 dropdown, nibs above radius 0 are\n  anti-aliased\n- changes to help rhel5\n- oop, could delete vips files accidentally\n- better file search \n\nstarted 7.22.2, 5/7/10\n- show nthreads in space free tooltip\n- fix win32 button order, again\n- fix duplicate workspace\n- added ^Q, for quit nip2, to all windows\n- rename gtk_entry_*() to gtk_item_entry_*() in gtkitementry.c, thanks Adam\n\nstarted 7.22.1, 13/6/10\n- relax tolerances in test_colour.ws, thanks Peter\n- improve region repaint during drag, thanks Ruven\n- test relational constants\n- test load / save in various file formats\n- test threading system\n- removed malkovich locale, oops\n\nstarted 7.22.0, 12/5/10\n- version bump\n- gtksheet sizing changes, again\n- plot window destroy cleanup\n\nstarted 7.21.0, 8/12/09\n- 7.16 ws load could fail (thanks Jim)\n- \"make check\" tests the example workspaces too\n- nip2-cli.c improvements (thanks Leo)\n- leak test improvements\n- set double-click time from the system\n- don't copy to file for paintbox, it makes dangling pointers if you use it in\n  complex workspaces\n- thumbnail updates on paint actions, woo\n- rect and text tools have a working preview box\n- safer handling of missing exprs in formula\n- handle im_invalidate() in paintbox ourselves\n- much faster and smarter image window repaints, especially with the paintbox \n  active\n- #CPUs in prefs defaults to zero, meaning autodetect\n- works without GtkInfoBar \n- better show/hide behaviour for paned\n- progress feedback for paintbox open\n\nstarted 7.20.5, 27/11/09\n- fixed up GtkInfoBar support\n- oop, help was rather broken\n\nstarted 7.20.4, 26/11/09\n- removed 'browse thumbnails' button from filesel\n- added 'preview' widget to file open\n- added some basic GtkInfoBar support\n\nstarted 7.20.3, 25/11/09\n- argh, button order error in dialogs on win32\n- updated help index\n- initial window size was too large\n\nstarted 7.20.2, 11/11/09\n- make GRegex optional so we can work with older glibs\n- fix a crash with \"-p\" and Managedstring\n\nstarted 7.20.1, 11/11/09\n- add \"convf\" operator\n- default number of CPUs bumped to 4\n- plot.c can work with goffice-0.7.15\n\nstarted 7.20.0, 9/11/09\n- version bump\n- \"make dist\" fixes\n\nstarted 7.19.0\n- remove deprecated use of GtkList in option edit ... needs replacing\n- dropped in new Joe defs (thanks Joe)\n- reverse dialog button order on win32\n- fix memleak with IMAGEVEC args to VIPS\n- _check_all etc. no longer chain up, for a slight speed increase\n- fix crash with \"\" as LHS for various copy operations, eg. (\"\" ++ \"a\")\n- add test_snip.def to test language features\n- replace-from-file marks a workspace as modified\n- Arrow and Mark grab handles improved\n- \"don't attach a profile\" option for jpeg save\n- fixes for gtkdoc merge\n- set TMPDIR on startup to help im_system()\n- add RAD as a coding type (thanks Roland)\n- add Filter / Morphology / Segment menu item\n- much faster meanze for 8 & 16-bit unsigned images\n- added a \"rotate\" option to custom convolution\n- added Histogram / Find / Indexed\n- Cache defaults to 128x128 tiles\n- use libgoffice to display plots\n- use new gtksheet widget, fall back to treeview if we can't build it\n- better regexp searching in Program window (now full PCRE)\n- oop horrible tree_map() bug with uops caused a variety of strangeness\n- group image save now sets image save options (thanks Joe)\n- sum and product now work for any object\n- don't set non-existant properties in vips_object_new\n- faster constant image maker with im_embed()\n- added \"join image array from list\", thanks Joe\n- phew, label backgrounds are back\n- added raw import (thanks Jim)\n\nstarted 7.18.0\n- bumped version numbers\n- added 7.16 compat mode\n- revised manual\n- added snohalo1 wrapper\n- dropper did not update inkwell picture\n- better button colour changes\n- fix examples\n\nstarted 7.17.2\n- added progress.[hc] for a better progress/cancel system (again)\n- splash screen uses new progress system\n- added list delete, difference, \"--\" operator\n- fixed a bug with startup recomps not happening (it was trying to do them \n  in the background, argh)\n- buildlut makes Plot, not Image\n- much faster gaussian mask build for large masks\n- \"Size To\" has a \"break aspect ratio\" option\n- better error message for \"[1, 2] < [3, 4]\"\n- support RAD coding\n- added Radiance menu\n\nstarted 7.17.0\n- merged 7.16 branch back into trunk\n- bumped version number\n- manual version number was wrong\n- removed vips8 link, we've started moving that stuff into vips7 now\n- patches for ubuntu 8.10\n- added yafr interp\n- rotate etc. now have an interp param\n- revised \"resize\" to use new modes\n- transform menu items have inter options\n- configure fails if bison is not found\n- fix the filesel filter after a filename change\n- nicer message on cancel\n- new VipsFormat stuff\n- LEXLIBS->LEXLIB (thanks Adam)\n- added Managedstring, removed old static string system\n- caption columns can be null, display \"doubleclick to edit ..\" message if\n  they are\n- added vipsobject builder from old call8 code\n- added vips_object_new builtin\n- moved BufInfo down into vips\n- added IM_INTERPOLATE to vips_call\n- added Interpolate class and Interpolate_picker\n- error window output no longer truncates on symbols with many errors\n- renamed 'Recover After Crash' as 'Search for Workspace Backups'\n- better Scale alignment in display\n- regions and scales default to live dragging\n- better image display defaults (no ruler, no display bar etc.)\n- thumbnails are transparent when you drag them\n- side panes have titlebars and close buttons\n- block attempts to OK on directories in file dialogs\n- we have a copyright symbol! nicer 'about' box too\n- better region label positioning\n- double images ignored rgb16/grey16 hints\n- configure dies if flex/lex not found\n- Managedgobject.\"property\" works\n- added (dir gtype), (dir gobject) \n- oops, rank filters were off by one by default\n\nstarted 7.16.3\n- fixed cancel system (again)\n\nstarted 7.16.2\n- argh, \"-o\" was broken\n- oops, some left over code for function overloading in the parser\n- init builtins earlier, so we can spot accidental redefinition\n- added a NULL type, Group now uses it to indicate an empty slot\n- another stab at fixing the order of startup actions\n\nstarted 7.16.1\n- better pointer set\n- fixed a couple of notify snafus\n- use g_assert() instead of assert() to avoid abort() death\n\nbranch for 7.16 \n- bumped version\n- grey16/rgb16 not always set on colour space conversion\n- revamped test system\n- set GValue strings as refstrings\n- try to transform gvalues we get to strings, if we can\n- added Joe's shrink within macro\n- removed the last of the fade stuff for faster repaint\n- open multiple now makea a group, so we can process more files at once\n- revamped 'make check', much nicer and more useful\n- better file type guessing\n- better progress feedback\n- revised image write code gives better feedback\n- better group-save, again\n- fixed a problem with recalc backtracking\n\nstarted 7.15.0\n- fixed segv with making tools for non-toplevels \n- expand the heap if more than 50% full after a GC (was 70%)\n- added nip2-cli.c (thanks Leo)\n- updated README\n- more HIGgy titlebar text in mainw/program\n- refactor: IWINDOW_TRUE/_FALSE renamed to _YES/_NO\n- adjustable panes in image header view\n- histdif was broken for unsigned image types\n- fix memleak in compile_lcomp()\n- better --help text\n- get rid of intltool\n- use g_idle_add() instead of GAsyncQueue for render notify\n- fix a segv in imageview destroy\n- == did not always find the best method\n- better time debugging in symbol recalc\n- added $var for string constants\n- added s => v syntax\n- fixed recursive invocation bug in vips_call.c\n- much better hashing of vips calls\n- configure shows a summary at the end\n- syntax change :-( lcomps now use [expr :: generators] to reduce ambiguity\n  the old syntax failed for things like [a || b | a <- [true]; b <- [false]]\n- added --test, so we can check test_toolkits automatically\n- added --prefix, so we can run without installing\n- added \"make check\" support\n- got rid of the annoying progress popup, it's back in the status bar now\n- status bar tells you which sym it is computing\n- revised busy system does all busy feedback\n- configure switch to stop update of desktop database (thanks Adam)\n- vips_call hashing improvements\n- images are GCd after 60s of inactivity, rather than immediately, giving\n  the call cache a chance to revive them ... speedup in some cases\n- added a 7.14 compat area\n- join_lr/_tb args swapped \n- check_args now does not recurse up a class, instead all _check members have \n  to chain up ... a bit quicker\n- watch \"invalidate\" in vips_call.c cache ... so paint actions now decache\n  indirect results as well\n- added Math / Cluster, though it needs a bit of work\n- insert now format-alikes\n- another go at removing refresh flicker ... region dragging flickers a bit\n  instead\n- added Image / Header / Get / Custom\n- recurse for save groups of groups\n- added Image / Cache menu item\n- merged loadable-formats branch\n\nstarted 7.14.0\n- updated docs\n- added 7.12 compat\n- check for update-mime-database and friends (thanks Tom)\n- more leak fixes\n- updated examples and prefs workspaces\n- break _Object.def out of _types.def\n- better \"if image then constant else constant\" behaviour\n- fixed segvs with IMAGE lifetime and progress dialogs\n- use xdg-open to show help pages, if available\n- fixed segvs with IMAGE lifetime and progress dialogs\n- fixed segvs with outdated iimage change callbacks\n- some tweaking of the toolkits menu\n- fixed another lcomp bug\n- intercept from greyscale option in find_calib\n- removed unnecessaary assert() from parser\n- recomp all on startup even in batch mode fixes some strange bugs\n- apply calib works for groups of images\n- renamed Error as iError to help windows\n- more small windows fixes\n- more small os x fixes\n\nstarted 7.13.3\n- save image was broken, weakrefs were not being updated\n- wrongly setting vips-7.8 region compat mode on all old WS load\n- \"Close\" in ws defs pane menu was not working\n- removed image window / plot window transient-for behaviour, we lost maximise\n  buttons :(\n- block ungroup of things larger than 100 elements\n- allow +/- for zoom in and out shortcuts\n- mainw rmb menu has open/merge items\n- merge ws doesn't add extra space\n- added LHS patterns, eg. \"[a, b] = fred 12;\"\n- better spacing in merge ws / load ws\n- added is_list_len and friends ... faster then len for long lists\n- compile on demand, saves 25% of startup time\n- now bison only, we won't work with yacc (will package deps need updating?)\n- added lcomp patterns, eg. \"[x*y|[x,y]<-zip2[1..10][11..20]]\"\n- use LHS patterns in defs\n- oop, dist typechecking could segv\n- split trace.c to make log.c, base class for logging windows\n- added error ... error logging window\n- added destory_if_destroyed() and done some cleanups\n- oop, im_and_image etc. refs remaining in compat\n- disallow const-only LHS patterns, eg. \"12 = fred;\" \n\nstarted 7.13.2\n- remove Application from nip2.desktop.in\n- revised progress system ... works for \"max\" now!\n- fix reporting of parse errors in inner scopes\n- lcomps now nest correctly ... try \"Matrix [[x*y|x<-[1..10]]|y<-[1..10]]\"\n- workspaces loaded from stdin with -w save more sensibly\n\nstarted 7.13.1\n- you can type \"fred = 12\" into a columnview, woo\n- gah, lcomps had \"undefined\" set on various members because of trimming off\n  parser temps\n- more visible arrow dashes\n- added pane.[hc]\n- added a left pane to mainw to hold ws-local defs\n- ws-local defs sort-of work\n- added workspacedefs.[hc]\n- print all workspace mains on exit too\n- renamed lor/land as any/all, in line with Haskell\n- added INTVEC and DOUBLEVEC output\n- added greyc filter\n- added \"--set\" command-line option\n- better left/right pane widget\n- resize tk browser search box with pane\n- nicer widget colour change ... use \"*xx*\" in style file rather than setting\n  names and contained names\n\nstarted 7.13.0\n- woo, fork for new development version\n- started cleaning up parse.y\n- simpler DOT syntax ... A1.\"poop\" works now\n- added lambdas ... \\x x + 1\n- added listcomp syntax ... [x | x <- [1..]; x > 12]\n- recomb was broken for >3 band images (thanks km)\n- lambdas were not being marked as locals correctly, oops\n- added listcomp code generator\n\nstarted 7.12.5\n- tiny win32 cleanups\n- nicer formula widget, better view switching\n- better file filter lookup\n- oops, min and max only worked for rectangular lists\n\nstarted 7.12.4\n- cleaner Makefile.ams\n- transform was only working for [[real]] :-( (thanks Mikkel)\n\nstarted 7.12.3\n- added right click / save for plot widgets\n- remove .svn dirs from dist\n\nstarted 7.12.2\n- added support for TIFF predictor\n- added Tasks / Capture / Plot Bands\n\nstarted 7.12.1 9/5/07\n- custom convolution of Plot no longer loses Plot wrapper\n- better plot colours\n- better spacing in plot status bar\n- added histogram differentiate, zero crossings\n- better ifthenelse on groups\n- added \"expr.(expr)\" form, removed builtin get_member\n- larger sensitive area for arrow crosshairs\n- added region-on-image-from-region, again\n- minpos/maxpos work for lists\n- Math / List works for Groups\n- maxpos/minpos return -1 for []\n- max/min error for []\n- stricter about the empty matrix being [[]]\n- image/Image ==/!= list was broken\n- empty groups were broken\n- remove special case for assemble on groups ... you now need to group->list\n  first\n- [] as a group member means no-value\n- better Group insides\n\nstarted 7.12.0 28/4/07\n- fix up 7.10 compat mode\n- more fixes to the convert.sed script\n- small fixes to 7.12 toolkits for test_toolkits.ws\n\nstarted 7.11.18 10/3/07\n- added plotwindow, floatwindow\n- duplicate plot was broken\n- floating plots have stuff\n- gtkplotcanvas.c only swallows motion/buttonpress events it handles\n- gtkplotcanvas.c no longer tries to do focus handling\n- plotwindow status bar\n- added plotmodel.[hc], plotpresent.[hc]\n- plotview has a caption, displays class name\n- better captions for real/group/vector in heapmodel\n- gtk_plot_canvas_destroy() was not unreffing the pixmap (thanks Simon)\n- added next error stock item\n- better clock value display\n- added keep-child-windows-in-front pref (thanks Rachel)\n- gtkplotcanvas.c has new cursor handling stuff to help nip do cursor changes\n  for middle-drag scrolling\n- lots of toolkit tweaks\n- revised the manual\n- ooop, increment_filename fix, it was putting the number at the start of the\n  filename if there was no number there\n- better batch mode error messages, added -V flag for verbose messages\n- oop, variable name from filename was a bit broken\n- started revising the examples\n- increment on save and browse thumbnails were broken by gtk-2.10, gah\n- removed debugging menus\n- bump for 7.12! w00t\n\nstarted 7.11.17 26/1/07\n- snap hdrag of columns to make lining up easier\n- better CSV import\n- added zero-excluding mean and deviation to Math\n- better set-workspace-name on ws load\n- started a ws background popup menu\n- grey ramp orientation swaps w/h \n- better display control bar scale/offset for HDR XYZ/Lab/etc. images \n- possible fix for intermittent fail to recomp on edit bug\n- fix for image * group\n- paste in gtkplot sources (we will probably need to hack it about a little)\n- added plot/plotview\n- oop, memleak in icontainer\n- added a temporary Plot menu for testing\n- set plot tick step to avoid mad mallocs on large ranges\n\nstarted 7.11.16 21/12/06\n- look for release on rulers as well as press\n- adapt for new Hist system\n- use im_concurrency_set()\n- add im_get_option_group() \n- oop, recursive invocation gah\n- slightly better error messages\n- better mainw title bar text\n- added 'splits'\n- better trace / profile / leak options\n- more robust find chart calib \n- only interpret RGB16 for display for int formats\n- change im_histgr args\n- oops, paintbox could set delete-on-close sometimes\n- custom blur has many more controls\n- better inter-workspace \"depends on ...\" messages\n- chop/assemble image arrays now work on groups of groups, not list of lists\n  so you can process the chopped up image\n- added 7.11 toolkit_tester, plus a little sed sscript to update old workspaces\n\nstarted 7.11.15 6/12/06\n- tiny fixes to startup code\n\nstarted 7.11.14 6/12/06\n- Vector arithmetic fix\n- Vector display class\n- more Matrix fixes\n\nstarted 7.11.12 8/9/06\n- Image Rank no longer rounds up\n- only obey IM_CONCURRENCY pref in GUI mode\n- added GVALUE input/output args\n- added set_header, Set Metadata\n- use LC_ALL rather then LC_MESSAGES (thanks Simon)\n- better range == 0 check in conversionview\n- re-added make-named-column action\n- better textview reset during background recomp behaviour\n- added LUT from scatter\n- added AC_CHECK_TOOL to configure to find tools for cross-compilation. \n- added map_nary, Crop now loops on all args\n- test for glibtoolize during configure\n- added tag image as hist, set type, image->matrix more flexible\n- added get header field\n- added Real displayer\n- reordered Image menu\n- optionview refresh was a bit broken\n- ruler resize was a bit broken\n- map_nary recurses\n- make image windows children of the mainw ... so they can't pop behind\n- \"mean\" can do lists of images etc.\n- move ->parent from idialog into iwindow\n- revised to_list behaviour, added to_Group\n- show save prefs automatically on save\n- removed broken scroll on focus code in columnview \n- map_*ary no longer loop over lists ... they often represent compound\n  objects, eg. \"mean [1, 2, 3]\"\n- new preferences viewer\n- kill parent of nested dialog now kills dialog as well\n- more JPEG save prefs\n- CSV save prefs\n\nstarted 7.11.11 18/7/06\n- small polishes from gtkdisp3\n- tweak for im_init_world() changes\n- better behaviour for scale == 0 in conversionview\n- better original-filename handling\n- use im_msb() for GREY16/RGB16 images\n- csv2vips wrapper update\n- added parse_time\n- fontname defaults to \"Sans\" ... stops a warning on load\n- set window title less often\n- update i18n infrastructure\n\nstarted 7.11.10 23/6/06\n- sync CVS again\n- oop, selected closed columns caused kb grab confusion\n- added call8.[hc].. vips8 interface\n- new builtins vips_image_new, vips_call\n- reworked doc build again, seems to work in dapper now\n- added missing .br to man page\n- allow '_' in environment variables in \"expand\"\n- mainw tooltip reports operation cache size\n- upped default memoisation cache max to 10000\n- better caption for Group objects\n- oop, mac os x detect was broken\n- GSL error handler\n- more work on vips8 interface\n- add gcc attributes for varargs and noreturn\n- mac build fixes\n- keep prefs in ~/Library on mac\n- vips8 interface done\n- more tweaking for vips_call for robustness\n- quick stab at background recomp in workspaces ... some stability problems\n- tiny Toolitem fixes\n- \"Calculating ...\" appears in status bar during a background recomp\n- is_image builtin says yes to vips8 images too\n- added Analyze and Vips8 menus\n- added vips8_get_header builtin\n- better ifthenelse behaviour for image/constant mixes\n\nstarted 7.11.9 15/5/06\n- reverse order of decls in image_name etc. to sensibleify Change Header\n  options\n- better HIST preserving\n- bug in complex display control bar (thanks Jean) \n- use gtk_disable_setlocale() to preserve LC_NUMERIC setting (thanks Peter)\n- more g_ascii_strtod() and friends for double parse/print\n- disallow vips funcs with no input args\n- gtksheet was freeing pixmaps with g_free(), not g_object_unref()\n- better matrix type guesser\n- optional link to vips8 for testing\n- CSV load/save\n- strict reduction of vips_call arguments prevents GC during argument gather\n  and dangling pointers\n- oop, problem in Transform in Image.def\n- added \"dir\" builtin\n- always grab focus for bottom entry widget on column select\n- even more test view reset tweaks\n- added \"objects in workspace\" count to main status tooltip\n- limit number of cursor shape updates\n\nstarted 7.11.8  22/4/06\n- added gravity, Find Projections now shows centre\n- added project\n- added OpenEXR read support\n- fewer int/void* tricks to help x64\n- call im_existsf() more sanely\n- better Group caption\n- don't save/load ->name automatically ... better 7.10 compat\n- better pointer printing\n- added support for RGB16 and GREY16 image types\n- workspace window size is saved in ws file and overrides the global default\n- some edit dialogs now done with member automation\n- fixed NO_SPLASH\n- fixed scroll to row on error, for closed columns\n\nstarted 7.11.7  11/3/06\n- allow complex constants of the form \"12j\", cf. python (also allow i)\n- optionally display complex as \"x + yj\"\n- ifdef'd out some more debugging code .. saved 30kb!\n- new Managed class abstracts out code for GC/C managed objects\n- Imageinfo now sits on this\n- Managedfile object replaces the thing we had for read\n- split trims trailing fails too\n- scrapped ELEMENT_IMAGE .. we just have managed objects now\n- added managedgobject\n- added experimental Clock class\n- moved some views into modelview.c \n- delay showing the hglass for 0.2s\n- change clock to seconds, subclass off Real\n- modelview now has a right-button menu\n- disable tile fade animation for thumbnails\n- model _get()/_set()/_load()/_save() now automated\n- sort column jump widget\n- better scroll-to-column behaviour\n- column jump is tear-off-able\n- column jump is sorted by column name and name length\n- added geometric mean\n- added sum, product\n- added linear regression\n- fixed assert( 0 ) for VIPS operations with an implicit DISPLAY param\n- added optional dependency on GSL, added gammq builtin\n- print_base was broken for some argument combinations\n- shift + mwheel scrolls left-right in workspaces\n- update thumbnail on falsecolour / type changes in display bar\n- matrix now uses member automation\n- main uses GOption command-line parser\n- make sure we don't clear dirty on rows coontain errors\n- optionview only rebuilds the menu on change\n- 7.10 compat defs updated\n- itextview/clock fixes to make editing members easier\n- added -o cmdline switch\n- scrapped print-last mechanism ... printing main from an associated .def file\n  is much better\n- always set argv, allow save of Image, split save to file and print value\n- save Matrix as well with -o\n- added -e option\n- revised man page\n- added Find Projections\n- raised default memoisation cache size and heap size\n\nstarted 7.11.6  18/2/06\n- custom morph was broken, grid was broken (thanks Dave)\n- Matrix_file now uses \"search\"\n- reorganised morph menu slightly\n- added Format / CSV import\n- better handling of display of very long strings\n- added lazy (read \"filename\") builtin\n- \\n was missing in expr_info error report\n- removed \"save successful\" info box for great HIG-ness\n- added is_prefix, is_suffix, is_substr\n- Pathname widgets add to session path\n- widgets like Group, Toggle, etc no longer add annoying stuff to tooltips\n- readded \"auto-recalc\" menu item\n- renamed Slider as Scale and added a caption field\n- oops, string constant \"\\\\\" failed\n- drag from konqueror might work now\n- added hist_thresh, added threshold items to Image / Levels menu\n- prettier Scale display, better display of multiline class member formula\n- added correlate, correlate_fast, Filter / Correlate\n- added \"jump to column\" menu item, handy for navigation in large workspaces\n\nstarted 7.11.5  15/2/06\n- added \"search\" builtin\n- (c) line changed\n- itextview mouse enter/exit now does help/highlight\n- itextview insensitive in noedit mode\n- tweak formula to stop resize with clearlooks theme\n\nstarted 7.11.4 18/11/05\n- added tile fade pref for Kirk ... it is a bit slow on win32\n- fix compiler crash for [1..2] (thanks Jay)\n- automatically add an icon to the win32 .exe\n- added -main_load_args switch ... just a temp hack\n- better -main printing\n- added \"path_separator\" ... either '/' or '\\\\' depending on platform\n- better char constant parsing\n- better char constant display\n- added path_relative/_absolute/_parse\n- prefs now switch between / and \\ automatically\n\nstarted 7.11.3 26/9/05\n- display original filename only for iimage which really were loaded from a\n  file\n- ppm read uses direct open, rather than converting to vips\n- fixed used-before-set problem in option ... could cause segvs when\n  displaying rows built from .defs containing errors\n- added Filter / Blend / Alpha Blend (thanks rich)\n- added Edit / Info (Ctrl-I) to mainw, some stuff there now, space for more to\n  go in\n- removed nip2-7.11.ebuild now that nip2 is in gentoo portage\n- desktop integration binds .v files to nip2 (thanks Ruven)\n- align cols marks the ws as modified\n- configure.in magic stolen from pango ... we now automatically disable\n  gobject cast checks in production builds\n- display formula rather than value if there's a visible graphic\n- falsecolour and type applied to thumbnails\n- fix gcc4 warnings\n- use g_mem_profile()\n- plot slice can now plot along any arrow\n- oop, some filters inadvertantly overrode width/height\n- fix isclass is_class confusion\n- itextview only shows value for non-class rows ... we assume members /\n  graphic will show the value, so we show the formula\n- don't apply scale/offset displaybar controls to histograms / fourier images\n  if Interpret Types is on\n- better initial kb focus for file load/save dialogs\n- better tooltip for iimageview\n- tooltips on demand function added\n- colourdisplay, ... adapted to new dynamic tooltip API\n- use input-only eventboxes for spinbuttons\n- better rowview tooltip\n- oops, buf_appendc() was a bit broken, fixed in vips too\n\nstarted 7.11 (1/6/05)\n- view image header now shows meta fields too\n- does INTVEC args to vips\n- now in CVS\n- added Analyze format\n- added name2gtype, gtype2name builtins\n- added get_header, grid, matrix lr/tb join\n- slice into tiles was broken for case tile size == image size\n- removed led.[hc], now uses stock system\n- always define our own strcasestr\n- icc import offers to use embedded profile\n- added 7.10 compat mode\n- \"reset\" in display bar resets to workspace default, not to 1/0\n- column titlebars reorganised\n- reenable gtksheet support now gtkextra-2.0 is out\n- original-filename tracks name loaded at\n- bumped version to 7.11.2\n- oop, fixed a nasty refresh bug\n- configure now adds LEXLIB to link line\n- pasted gtksheet code in so we can hack it\n- added matrix area selects\n- added Matrix / Extract / Area\n- slightly better default widget handliing in dialogs\n\nstarted 7.10.11\n- docs no longer contain absolute nav links\n- increment filename on save works again\n- hide closed columns in NOEDIT mode\n- install a .desktop file for GNOME (thanks Denis)\n- group, right click, ungroup, no longer pops a spurious error dialog\n- new pref lets you not use the crosshair in image display windows ... some\n  desktop themes have very annoying crosshair cursors\n- call libMagick less to reduce segvs from the file open dialog with broken\n  ImageMagick libs\n- show args in vips history\n- fixed a rounding bug in image resize which sometimes made it miss by a\n  pixel\n\nstarted 7.10.10\n- fixed crash in vips_call with repeated calls to fns with large image vectors\n- fixed crash replacing a region with an image\n- fixed exit if temp area was missing (thanks Denis)\n\nstarted 7.10.9\n- allow filenames containing ':' chars\n- uses im_render_fade() for prettier image display\n- added CCITTFAX4 compression mode for TIFF save\n- oops, image save options were being ignored :-(\n- fix 64-bit compiler warnings\n- fixed problem with very long filenames\n- recover-after-crash no longer messes up recent menu\n- \"Jump to\" in program window was broken\n- fixed a crash with very large objects (thanks David)\n- swap shift/control scroll modifiers to match HIG\n- rotate matrix works for any size matrix\n- rotate quadrants works for matrix as well as image\n- added recalc after reload start stuff\n- use auto label wrap\n- firefox is now the default HTML viewer on *nix\n- limit matrix display size to 10x10 unless we have gtksheet\n- small startup speedups\n- destroy views when a column is folded away to save some memory\n- added Image Rank\n- band join is much faster at joining many bands\n- safer empty temp area\n- added cute column open/close animation\n- fixed a couple of problems with region dragging in compatibility mode\n- removed column name dialog (thanks Joe)\n- program window now lets you collapse the current kit\n- allow \\r in .def files (so we work with DOS edited files)\n- added Image / Tile / Chop Into Tiles\n- added 'Open Examples'\n\nstarted 7.10.8\n- explicit gthread dependency makes us work even if vips is built without\n  threads\n- tiny .def fixes\n- \"-time_save\" switch turns on image save timer for benchmarking\n- mainw, trace, imageview, program now use gtkaction / gtkuimanager\n- mainw and imagewindow 'view' settings now update prefs for you\n- trace window uses new gtk_text_buffer/view widget\n- image header uses GtkTextView for history display\n- program window uses GtkTextView / GtkTreeView\n- windows remember their size and pane positions\n- fix a crash for edit defs of live widgets in prog window\n- removed default file type pref ... now remembers last image and matrix file\n  type\n- added \"Set As Workspace Default\" to conversion bar\n- mnemonics for more popups \n- fixed a crash if you quit mainw with an image window open (thanks Jay)\n- new default cursor for imageview windows (thanks Jay)\n- regions only update when grabbed\n- now passes distcheck\n- use g_setenv(), g_mkstemp(), IM_FREE*(), g_set_application_name(),\n  g_set_prgname()\n- better cursor change layering\n- better initial toolkitbrowser size\n- absoluteize & canonicalize VIPSHOME (so we work with a relative path for\n  VIPSHOME)\n- better time-to-go text\n- more fixes to help compiles on 64-bit systems\n- invalidate operation cache on paintbox actions ... makes paint on FFT work\n  again\n- save settings in APPDIR on win32 rather than a dotfile\n- added SAVEDIR environment variable\n\nstarted 7.10.7\n- tiny build fixes\n- added \"_\" builtin function for i18n of toolkit menus\n- softer 'unpainted' checkerboard (thanks Kirk)\n- added \"-i18n\" command-line switch ... outputs constant _() strings and quits\n- compiled string constants are automatically shared between all defs\n- (_ \"kjh\") substituted at compile time\n- started marking up .defs for i18n\n- trace_args() was printing backwards\n\nstarted 7.10.6\n- uses fftw3 if available\n\nstarted 7.10.5 19 oct 04\n- removed \"beta\" from version\n- perspective distort works on groups (thanks Joe)\n- added get_left/get_top\n- chaneg and tag colourspace now have option boxes\n- new enum class and option builder cleans up some stuff\n- fixed crash for display control bar scale on black image (thanks Mikkel)\n- fixed image windows appearing off screen for workspaces made on large\n  displays being used on small displays (thanks Mikkel)\n- un-offset regions during create in compatibility mode (thanks Rachel)\n- fixed a race in vips history memo-isation (thanks Joe)\n- speedups to vips function call history too\n\nstarted 7.10.4 4 oct 04\n- always include formatted html in dist, and install on install\n- enable line crawl on win32\n- prefs now autolayout, so look sensible even with font changes\n- added Image/Bands/Extract|Insert|Delete\n- linear match now works for groups\n- prefs were not always saving automatically\n- white_balance now takes two args: uses band ratios in small image to\n  fix large image ... makes using one image to fix a group of images much\n  easier\n- also, works in XYZ, has adjustable white point target\n- new icon (also used in About)\n- LabQ and LabS conversions were broken\n- check for strcasestr in libc\n- display symbolic names in iimage caption\n- oops, custom rank menu item was broken\n- use a dumber sort algorithm for row recomp order ... glib was skipping too\n  many tests\n- thumbnail convert settings update is smarter\n- much faster display convert bar\n- Joe's .defs are in\n- image blend is smarter about reordering args\n- small win32 fixes\n- oops, did not remove all temp files if debugging was turned off\n\nstarted 7.10.3 13 sep 04\n- to_real now works for toggle & bool\n- Rubber menu items were b0rked (thanks Joe)\n- Rubber scale removed (rubber transforms now automatically rescale)\n- fixed crash if you gave a number as a superclass (thanks Joe)\n- win32: block log output to prevent annoying console window appearing\n- shared model for toolkits menu and toolkitbrowser for big speed-up on main\n  window build and better update behaviour\n- tk browser columns are reorderable (thanks Joe)\n- better image type guessing (thanks Joe)\n- thumbnails now use Type hint (thanks Joe)\n- added simple number base conversion\n- compound unary ops on Rect now work on width/height rather than left/top ...\n  so abs(Arrow) now gives the expected result\n- repaint regionview immediately for better feedback\n- group save can save unboxed images and will iterate over nested lists\n- added trace VIPS operations, including cache hits/misses\n- small menu polishing\n- better 'revert to defaults' in prefs (thanks Jay)\n- documentation revised\n- fixed dependency tracking inside zero-arg hidden classes (thanks Joe)\n- help system updated\n\nstarted 7.10.2 23 aug 04\n- convert bar settings now affect thumbnails too (thanks John VanVliet)\n- show hglass cursor more often\n- free rotate is now -180 to 180 (thanks Jay)\n- added 'toolkit browser'\n- work on docs\n- small toolkit fixes\n- better mainw decoration handling\n- minor main window menu rearranging\n\nstarted 7.10.1 28 july 04\n+ top-bottom 2 point mos was broken (thanks Joe)\n+ added aliases for resample and estpar to help compat mode rubber sheet\n+ colour ops on LABQ were broken by the alpha channel stuff\n+ larger default max heap size (thanks Mikkel)\n+ added ebuild (thanks Ruven)\n+ oop, fftw includes missing from IP_CFLAGS\n+ added Expression widget\n+ suppress unneeded textview in NOEDIT mode\n+ better textview layout\n+ indent subcolumns in NOEDIT mode\n+ better regionview text layout\n+ Image/Format reamed to Image/Number Format (thanks Joe)\n+ prelight for rows, expressions and spinbuttons\n+ better row label layout\n+ menus reworked (again) for Expression class\n+ oops, resample renamed as transform_search\n+ win32 build fixes\n+ added \"Align Columns To Grid\"\n+ better focus handling in imageview (thanks Mikkel)\n\nstarted 7.10.0 21 june 04\n+ toolkit menu is now built dynamically from heap ... you can write functions\n  that generate menus\n+ menu items can have tooltips, icons and labels\n+ reorganised all menus\n+ added \"scope\" keyword ... helps remove \"root\" from toolkits and makes them\n  relocatable\n+ added \"solarise\" filter for fun\n+ added \"diffuse glow\" filter for fun\n+ slight improvement to references to non-local members in deeply nested\n  classes\n+ ungroup will now also unpack lists\n+ fixed segv if option menus were rebuilt while posted\n+ added vips function call cache ... memoisation!\n+ added prefs for #cpus and #memoise\n+ gah, had forgotten to add several new widgets to model_base_init(), so they\n  were not loading correctly if used in prefs\n+ put tearoffs back and fixed accels\n+ added empty-temps yesno on startup\n+ -main can output many images correctly\n+ display control bar false colour works on RGB images\n+ regionviews are offset in compatibility mode\n\nstarted 7.9.7 1 jun 04\n+ enable broken for gtk all the time in program.h (thanks Ruven)\n+ now uses im_text() to paint paintbox text (imageinfo.c:2185)\n+ better zooming from menu items (imageview.c, imagepresent.c, imagepresent.h)\n+ extra recalc on startup to build classes before we load args (main.c)\n+ set_output() was missing an \"!\" before imageinfo_file (graph.c)\n+ saner startup error logging (main.c)\n+ expr_error_print_all() now goes to a buffer (expr.[hc])\n+ program.c has an error lister\n+ main.c knows about new error lister\n+ prefs.ws had max_undo broken by precedence change\n+ String now interprets and expands C escape chars (eg. \\n)\n+ fixed close program window with selected text crash\n+ fixed edit of row with error itext crash \n+ added tile and Tile (replicate/mirror ... using im_replicate)\n+ leak testing only in DEBUG builds\n+ binary and unary operators now track the function they were called from, for\n  slightly better error messages\n+ Number spots trailing characters\n+ shadow and text paint work on labq\n+ added resize longest axis mode to Shrink_to\n+ fixed up menu dumper\n+ don't track load/save progress in command-line mode (thanks Joe)\n+ arithmetic and relational ops now work on images with a mixed number of\n  bands\n+ UI polish suggestions from Joe are in or noted on the TODO\n+ better update of visible hints in imagedisplay\n+ new menu item system with \"action\" member lets you have icons, mnenonics\n  and i18n for toolkits\n+ compatibility system for 7.8 workspaces\n+ better recent menu\n\nstarted 7.9.6 8 mar 04\n+ added Group class\n+ .def files rewritten for Groups, also many enhancements\n+ oops, imageview=>file=>view header was broken\n+ prefs option for 1 bit TIFF write\n+ scale in display control bar was broken (thanks Ruven)\n+ removed on-demand compile, caused strange recomp problems :-(\n+ value display no longer decompiles class args\n+ tracks lineno for tools\n+ better \"not defined\" error message\n+ better \"bad parent class\" error message\n+ better error messages from calling VIPS functions\n+ better \"link report\" error message\n+ relaxed the restriction on superclasses ... you can now have anything as a\n  superclass, including a full constructed multi-arg class\n+ detects redefinition of syms within a single parse action\n+ precedence change: \"?\" and \".\" now the same precedence, like C\n+ better \"member not found\" error message\n+ spots nested comments\n+ visualise image can handle labq hist\n+ case ignored for class names in ws save files \n+ SHIFT-mwheel now zooms in and out, like gimp-2.0; CTRL-mwheel scrolls \n  left-right\n+ autosave does not back up system workspaces (eg. prefs) (thanks Joe)\n+ raised arrow/region create threshold\n+ optionmenu swapped for gtk-2.4's combobox\n+ now gtk 2.4 only, gah! too annoying to have lots of ifdefs\n+ uses GtkFileChooser\n+ oops, String/Number did not implement load/save \n+ much polishing\n+ row.c no longer tries to recomp all rows that ref \"this\", was causing\n  confusion ... so, much faster, but will change row recomp order in some cases\n+ hmm, trace was a bit broken\n+ auug, instanceof_exact was broken for deeply nested classes, must have been \n  like that forever\n+ fixed a nasty and long-standing bug with shared classes ... we now always \n  copy code rather than trying to cache it\n+ ruler menus now have mm and offset setting\n+ got rid of all xoffset/yoffset stuff, what a pain it was\n+ Rect (and hence Arrow, Point, etc.) now behaves (roughly) like a complex for\n  arithmetic\n+ better select behavior on thumbnail drag\n+ renamed Point as Mark, Point is now a subclass that lets old nip workspaces\n  load\n+ added Fontname widget\n+ colour picker can be pinned up\n+ better image thumbnail in workspace sizing\n+ renamed Filename as Pathname and added a caption \n+ all menus items rewritten for new batch system\n\nstarted 7.9.5 6 feb 04\n+ Rotate_fixed now has an option menu for the angle\n+ imagearray_chop was broken\n+ image thumbnail drags no longer embed the workspace name (unless they have\n  to)\n+ merge workspace now shows an error dialog on failure\n+ statusview does not display more than 8 bands\n+ workspace saves view mode in files, and mainw knows about it\n+ now uses pkg-config to find vips\n+ splash does not focus \"remove\" toggle by default\n+ oop, hourglass was broken\n+ better hourglass animation\n+ select/extend select now works on image thumbnails again\n+ PRINT_LAST now done in workspace _dispose()\n+ drag image thumbnail to background to make a new column and put in a link\n+ compile now delayed until value needed ... saves 10% on startup time\n+ value pointers only registered for GC if necessary .. saves another 3%\n\nstarted 7.9.4 9 dec 03\n+ removed last gtk_timeout*()s\n+ fixed some memleaks\n+ views now _sink() their child views, so even if views don't ever get added\n  to containers (eg. toolview, rowview), they still get freed properly\n+ niprc now sets gtk-can-change-accels ... no one will discover this otherwise\n+ added Custom_blur, dropshadow now uses a gaussian blur\n+ some better error messages\n+ Toolkits=>New items for filename, number, string\n+ usage and About have version info\n+ row delete now asks for confirmation\n+ faster and more comprehensive common subexpression removal ... removed the\n 'optimise' option, might as well have it on always\n+ better session path behaviour \n+ much better open recent menu\n+ better graphic save/replace scheme ... image filenames now change in a much\n  more sensible way\n+ better iimage/iregion/iarrow caption scheme\n+ can now drag from image thumbnails, cool drag icons\n+ progress feedback on non-vips saves, and you can cancel too (!)\n+ added extract_row, extract_column, extract_band, join_lr join_tb\n+ extract_area now works for matricies too\n+ better ruler tracking at high magnifications\n+ defines HAVE_FFTW so we actually save and load wisdom now\n+ \"pos_changed\" signal stops all the suprious imageinfo changed signals\n+ \"file_changed\" signal lets iimage know when files are swapped about\n+ better vips_call error messages\n+ image cache is on mtime as well as filename, so loading changed files gets\n  the new version\n+ auto-reload on file change preference\n+ reorganised main window menus and scrapped \"Insert\"\n+ done a simple splash screen with some startup feedback\n\nstarted 7.9.3 20 oct 03\n+ better welcome message\n+ command-line mode with -main/-script/-workspace/-benchmark flags\n+ better middle drag scroll \n+ fixed the annoying race condition in repaint\n+ fixed annoying rounding problems with colour drag\n+ added TRUE/FALSE as synonyms for true/false\n+ better image zoom shortcuts\n+ more HIG-y layout in NOEDIT mode\n+ added String/Number types\n+ windows have icons, yea\n+ fixed browse icons window\n+ message internationalisation done\n+ en_GB translation file \n+ more higgy Stringset class\n+ better help system for dialog boxes\n+ paintbox now has buttons for tool select\n+ cursor shape change in subwindows\n+ load and save accelerators\n+ configurable accelerators on the toolkit menu\n+ more HIGgy dialogs for sliders, regions and matricies\n+ basic \"Open Recent\" thing on workspace file menu\n+ better keyboard nav for workspaceview\n+ reworked image viewer for more model-view-ness\n+ unified image view state\n+ hmm, row_new_heap had a double paste, wonder how long that's been there ...\n  should be a bit faster at recomps\n\nstarted 7.9.2 (30 sep 03)\n+ toolbar accelerators done\n+ image display, colour display, region display all reworked for gtk2-ness\n\nstarted 7.9.1\n+ HIG-ified (I hope)\n+ broken into SDI interface\n+ prefs dialog\n+ toolbar in mainw\n+ progress dialogs for image load/save\n+ new error message system\n+ live watch system\n\nstarted 7.9.0 (1 aug 03)\n+ compiles with gtk2!\n+ lots of cleaning up\n\nstarted 7.8.11 (30 jul 03)\n+ better run-nip.sh start script\n+ tiny fix to Calibrate_chart, thanks haida\n+ big LED stolen from mozilla, just one of them now\n+ add \"%s\" to existsf() calls for filenames with % in, thanks Clare\n\nstarted 7.8.10 (22 may 03)\n+ icc profile JPEG save option\n+ \".\" now on end of datapath in prefs\n+ fixed a race condition in regionview ... could crash during paint on slow\n  machines\n+ better vector/image ops \n+ D65 <-> D50 conversions improved\n+ added d50 macbeth data file\n+ added \"measure\" to _stdenv\n+ added \"insert\", \"extract_area\" to _stdenv\n+ \"recomb\" now works on matrix, vector etc.\n+ more use of extract_area\n+ mark_tree() is now iterative, so no stack overflow on large heaps\n+ reduce_spine() is (slightly) less stack-hungry\n+ recomp_row() will not rebuild models for rows with errors ... is this the\n  best way to stop it though?\n+ calib_chart now works on 16 bit images\n+ bumped version to 7.8.10 to match vips ... less confusing\n+ changed doc builds so that we can include formatted documentation in the\n  make dist\n+ fix to drag-n-drop code on winders (thanks Jim)\n+ fix to incorrect error message in file info view\n+ blocked dash crawl on winders, does nothing but flicker\n+ \"config\" help option (thanks Kirk)\n+ columns resize on close \n+ middle-drag in workspace scrolls\n+ new version of Joe's x-ray stuff\n+ spec/ now has RPM .spec file\n+ added a \"run-nip.sh\" startup script\n+ moved reload to program window\n+ drag column and workspace gets a + cursor\n+ added \"Match\" to Image menu\n+ added \"Tone_for_print\" to Print menu\n+ new macos icon, thanks denis\n\nstarted 7.8.7 (10 feb 03)\n+ added set of relative constructors for point/region/arrow/etc.\n+ used in various places to fix problems with dialogs on images with displaced\n  origins\n+ _vislevel member sets default visibility level\n+ updated widget menu items to set vislevel\n+ added has_member, get_member builtins\n+ add \"%s\" to everror() calls so we can have \"%\" in error messages safely\n+ better if-then-else overloading\n+ add \".\" to the end of the default search path\n+ added \"Area\", a non-resizeable region\n+ option.c was not initing value edit correctly\n+ better initial size for option edit dialog\n+ added orderlist_scan()\n+ better title for region edit dialog\n+ better row_save_test() means member ordering does not get lost on clone of\n  edited rows\n+ imagedisplay_link() no longer makes conversion for you ... change to\n  iimageview.c _init() in step (removes redundant create/destroy pair)\n+ imageview_new_area() could pick shrink == -1 in some circumstances (thanks\n  Joe)\n+ drag file to imageview or thumbnail does replace-image\n+ Region can now never fail (thanks Clare)\n+ better feedback during paint image creation\n+ better imageview File=>New=>* for images with displaced origins\n+ added Edit_header to Image menu\n+ catch errors from libxml2\n+ Image == Vector was broken\n+ Overlay has a \"lock size\" toggle\n+ added Image=>Insert\n+ renamed \"Clear edits\" as \"Reset\"\n+ saves/restores fftw wisdom for first fft speedup\n+ snap-to-* on region drag could resize region for zoom != 1\n+ statusbar gave bad numbers for FFT and histogram images\n+ use im_invfftr() for speedup\n+ better ruler display at high magnification\n+ oops, program=>find was broken\n+ pin-up now part of dialog\n\nstarted 7.8.6 (23 dec 02)\n+ swapped list for hash table in heap set of managed pointers ... startup time\n  fallen from 2.4s to 1s!\n+ much better heap-full reporting\n+ knows about png\n+ patch from Hans Breuer:\n\t+ paintbox sort-of hacked back in \n\t+ fixes to file selector on win32 \n\t+ misc. win32 #include fixes \n+ OK buttons in dialogs now verbs\n+ knows about magick\n+ oops, Colour_chart_from_matrix and New_CRT_test_chart were broken in 7.8.5\n+ new heap_is*() function style handles eval errors better\n+ paintbox rewritten ... now paint bar\n+ snap to guide added\n+ much smarter region repaint system now does true xor animation\n+ dash lines crawl in the background\n+ Rect/Region/Arrow etc. can now have float args and won't barf on images with\n  strange offsets\n+ default image file format preference\n+ colour temperature conversions sorted out (thanks Haida)\n+ fourier transforms now work with optical transform, rather than having\n  optical built into visualisation (helps paintbox)\n+ removed use of g_mem_chunk() \n+ new colourdisplay class for displaying swatches of flat colour\n+ drag-n-drop colours\n+ tries to detect C stack overflow in reduce_spine()\n+ new trace system reduces C stack usage during reduction\n+ fixed a few memleaks\n+ copy-on-write for member edit slightly reduces overcomputations and makes\n  changes feed forward more gracefully\n+ scale column coordinates with changes in font size\n+ Tilt_brightness now works with n-band images\n+ nativize paths\n+ drag URIs to main window to load files (thanks Hans)\n+ load any file type from command line arguments\n+ small menu fixes\n+ added RPM .spec files to distribution\n+ help launcher for mac os x\n\nstarted 7.8.5 (12 nov 02)\n+ added a bunch of \"%s\" to allow percent in tooltips\n+ rearranged reduce_spine() to trim stack usage ... should reduce C stack\n  overflow segv on deep recursion\n+ added IR sample images to data dir\n+ added rachel.con IR sharpen matrix\n+ added Join.Array to build an image array\n+ added Rubber stuff to Image\n+ removed auto column switch on row select\n+ added New to imageview window\n+ finished-ish docs\n+ >3 band images now display as RGB, 2 band images as mono ... helps \n  display of imported RGBA/GA tiffs\n+ better update of toolkit menus on tool change with zero-param classes\n+ better positioning in toolkit menus with hidden items\n+ default vid crop fixed\n+ added Overlay to Image menu (thanks Joe)\n+ added Calibrate_chart and Calibrate_image to Capture menu  (thanks Joe)\n+ help buttons linked to html manual display \n+ can now load workspaces from win machines on *nix, and vice versa (tries\n  both types of dir separator)\n+ added Joe's Xray menu \n+ present menus and rows in definition order rather than reference \n  dependence order\n+ added Browse_multiband (thanks Joe)\n+ can now pop up help viewer on win32 as well\n+ knows about new im_LabS2Lab() and im_Lab2LabS() funcs\n+ junk Hist on load to lessen balance confusion\n+ more helpful save/replace file dialog titles\n+ longer doubleclick time\n+ sub-menus tear-offable\n+ settable default image window size in prefs\n+ optional auto-popup of new image rows\n+ gtkfilesel2 knows not to select something twice\n+ larger default max heap size\n+ ws save files are prettyprinted and uncompressed by default for greater\n  portability\n\nstarted 7.8.4 (8 nov 02)\n+ fixed recover workspaces (thanks Joe)\n\nstarted 7.8.3 (31 oct 02)\n+ acinclude.m4 fixes for mac os x\n+ set extension on get_filename if none set and not showing All\n+ added Mosaic_force ... no tie-point refining, ever\n+ only save edited sub-trees on workspace save ... shrinks ws files to about\n  1/3 their previous size\n+ setlocale for numeric conversions to \"C\" to avoid \",\" as decimal point\n  madness\n+ escape C sequences in filenames (eg. \"\\n\" etc)\n+ vips functions and builtins now linked via main symbol table, rather than an\n  extra lookup on \"undefined\"\n+ pseudo-toolkits group VIPS packages and builtins\n+ display help text on pseudo-tools in program window\n+ \"go to def\" for program window\n+ auto-expand for rows in program window\n\nstarted 7.8.2 (27 oct 02)\n+ set $HOME on win32\n+ WinMain on win32 for non-cmdline start\n+ -mwindows flag to stop command.com starting for non-command line start \n  on w32\n+ lots of hacking on gtkfilesel2 for win32 compat\n+ Matrix_file \"\" \n+ New_mark.Region etc. menu item\n+ more robust row recalc on .def edit\n+ zero-arg local classes of classes sometimes recomped in the wrong order\n  (thanks Joe)\n\nstarted 7.8.1 (18 oct 02)\n+ d'oh, matrix constructors have to be classes for is_instanceof to work\n+ much better change/refresh/scan behaviour for gtk_sheet\n+ uses IM_DIR_SEP* for some win compat\n+ many configure fixes for mingw\n+ use gtk_fixed for workspace layout for gtkwin compat\n+ rename Text -> iText to stop windows breakage\n+ woohoo, fixed the grab problem in regionview\n+ more robust workspace load\n+ polishing\n\nstarted 7.7.23 (23 aug 02)\n+ bug in history tracking\n+ better filename select\n+ OK buttons in multi-select fsbs turn on and off\n+ supress \"super\" iimages for region/arrow displays\n+ rulers and status bar know about Xoffset/Yoffset\n+ regionview uses IMAGE cods, converts to model cods and back on\n  refresh/update\n+ defs adapted to origin stuff ... including Mosaic!\n+ region create is ctrl-left\n+ save-as-TIFF traps errors\n+ done Plot and Resize, phew ... all menus finished (the ones I did anyway)\n+ added namespaces to XML save file, prettyprint disabled, compression on\n+ tooltips for toolkit menu items\n+ \"Name param1 param1: \" string automatically prepended to help text\n+ preferences for mainw start window size\n+ menus reorganised to be more logical (I hope)\n+ Separator class for submenus\n+ column save adds enclosing workspace \n+ drag in program window was broken\n+ #dialog back in again, with an edit dialog\n+ \"menu item from column\" thingy\n+ refcount bug for long image load fixed\n+ iDialog can autopopdown for represented obj destroy\n+ toggle MB free/cells free\n+ use gtk_sheet for text matrix display\n+ configure detects gtk+extra for gtk_sheet\n+ iimage caption displays name of most derived class\n+ relaesed as 7.8.0 ! yea!\n\nstarted 7.7.22 (15 july 02)\n+ started Print menu\n+ added \"expand\" builtin ... expands environment variables in a string\n+ filesel history fixed\n+ reconstruction from overridden constructor in oo removed ... now just there \n  for edits\n+ done Colour menu, started Morphology\n+ done Morphology menu, started Filter\n+ if_then_else is now an overrideable binop\n+ use (double) for image size calc to avoid int overflow\n+ logical_and and logical_or can be overloaded ... still shortcut for plain\n  types, so not quite like other overloads\n+ done Filter menu, started Freqfilter (will become part of Fourier)\n+ done freqfilter, started Histogram\n+ sliders no longer each have a continuous member ... set with a watch\n  directly from prefs\n+ histogram visualisation\n+ better trace will never evaluate graph unexpectedly\n+ Real widget ... just draws a real number\n+ better row name set system gets less confused \n+ can now edit superclass constructors\n+ better recovery after error in row recomp\n+ better region caption\n+ better scroll to new object for main window\n+ \"<\", \"<=\" work on strings\n+ started Image menu\n+ small fixes for large files\n+ image window title bar update fixes\n+ auto select 1st matching file on load if no file specified\n+ rename Patch -> Colour to fix class name / gtk type name confusion\n+ classmodel_class_instance_new() now uses CLASS_new in preference, if defined\n  ... lets you have separate behaviours for _type object creation and OK\n  in edit dialog\n+ Xoffset/Yoffset added to header view\n+ default class == thing, class != thing operations in _Object\n+ class params no longer have subcolumns ... stops O(n**2) increase in\n  complexity with workspace size!\n+ multiple select for for fileselect ... load many images/matricies/etc at\n  once\n+ on load, objects renamed to the filename they were stored in\n+ better workspace scroll on new object\n\nstarted 7.7.21 (21 june 02)\n+ override Pixel constructor in Colour and Generate_colour.widget\n+ rename ... ivector -> iarrow\n+ new op type for colour-through-image operations\n+ better expr->err update on link clean\n+ convolution matrix display now shows scale & offset\n+ Matrix is now the base class, Matrix_vips etc. inherit from that\n+ tags now decompile for better error messages\n+ better graphic rebuilds for sub/super classes\n+ better member-not-found error message\n+ better new column positioning\n+ rotate menu started\n+ convert menu started\n+ segv on CTRL-S on local objects fixed\n+ flash help on row buttons\n+ suppress display of superclasses with a leading '_'\n+ better auto new workspace name\n+ better column rename on ws merge\n+ better scroll-to-visible for columns\n+ row just uses \"name\" property now ... no \"sym\"\n+ toolkit list now scrolls down RHS of main window ... no more resize probs\n+ parent/child relationships shown with colour changes in rowview\n+ removing column with an error resets error state properly\n+ x2 speed up for recalc with fancy heap node serial number system, heh\n+ better regionview create/destroy/link fixes occasional bad casts\n+ better auto workspace scroll on load\n+ scrapped .hd/.tl etc., too hard to overload ... builtins now\n+ '' chars are now unsigned, signed chars are numbers in [-128, 127], chars\n  default to unsigned (now unlike int, short)\n+ regions/arrows/etc. now defined on Image, not image\n+ better trace system does not confusingly interleave prints\n+ small filesel fixes\n+ Complex, List, Fourier menus\n+ display control bar knows about fourier images\n+ display control bar menu resets properly\n+ bits of Arithmetic broken out into Log and Trig menus\n+ Filename widget ... should help make an ICC profile chooser\n\nstarted 7.7.20 (17 may 02)\n+ redone configure system ... data files now go in share/nip, not\n  share/vips/nip\n+ fixes to Pixel class and Generate menu\n+ -image is now *-1, not im_invert()\n+ separate '!' and '-' operators for better C-style semantics\n+ better toggle/extend select for thumbnails\n+ Yxy display\n+ ops on Matrix class done\n+ stats menu added\n+ removed matrix size limit\n+ errors -> ierrors to please mac os\n+ keep local edits on reload\n+ oops, classes as parameters were broken\n+ member edit of local classes was broken\n+ class arg checks inherited\n+ view header dialog in imageview\n+ colour menu\n+ nasty bug killed for discovered dynamic references to dirty symbols\n+ Colour widget shows a swatch and lets you gtkcolorsel for edit\n+ rowview menu on subrows too, plus select/extend-select\n+ ceil/floor added as builtins\n+ lots of small polishes\n\nstarted 7.7.19 (10 apr 02)\n+ it's now (c) 2002 :)\n+ better LED spacing\n+ \"stop\" sign toned down\n+ split Expr to static stuff (Compile: parse/compile logic) and dynamic\n  stuff (called Expr still ... reduce stuff)\n+ Exprs can share Compiles if we know they will have the same code\n+ copy-on-write for edits\n+ 100s of times faster for large workspaces: load ws with 270 images = 7s\n+ oops, temp files now unlinked properly\n+ icon browser refreshes in idle handler, plus better cancel behaviour\n+ destroy callback added to iDialog, popdown_cb memleaks plugged\n+ memleak in model rewrite plugged\n+ all class instances in hierarchy have the same \"this\" ... simplifies OO\n  stuff a lot\n+ removed heap_gc() from REDUCE_CATCH_START() for big speed up (d'oh)\n+ smarter row dependency finder \n+ leak plugged in get_image_info, plus more informative\n+ reset menu item on graphic edit objects\n+ ooop, added '\\'' as a constant\n+ C-style hex constants, better real constants\n+ even fancier operator overloading scheme does builtins too, and is\n  extensible for other user funcs\n+ abs/max/min/etc. can be overloaded\n+ lots of menus done!\n+ newimage dialog removed\n+ classes with supers don't display as pull-rights in toolkits\n+ updated vips.m4 for IRIX\n+ top level dirties now say what they're blocked on in tooltip\n+ cast to int type now behaves as C (no more round to nearest)\n+ reload toolkit works better\n+ smarter image cache dependency tracking fixes occasional segv\n+ _animate() in class build for greater interruptibility\n+ \"++\" is lazier for list args\n+ image ++ [] allowed\n+ builtins can be overloaded\n+ tidies to reduce/action\n+ dmalloc support\n+ better column/row select behaviour\n+ better event handling in image windows\n+ scroll wheel in image windows\n+ class typecheck delayed until first reference for great speedup\n+ lots of polishing\n+ Mac OS X fixes:\n  - change include order in ip.h for mac os x\n  - test for mount.h, util.c, ip.h changes for space free display on mac os x\n  - file size stuff changes\n  - small include order changes\n  - temp_name() fixes for duff mkstemp()\n  - ignore GDK warnings (eg. locale not known)\n+ changeable max print length, dynamic buffers\n+ Pixel[] class\n+ ontop no longer saved for workspaces\n+ text values display left justified\n\nstarted 7.7.18 (1 mar 02)\n+ load images from command line\n+ new operator overloading system\n+ new check system allows check to be inherited\n+ nasty ii_destroy bug fixed\n+ new trace option for builtin functions\n+ nasty row destroy bug nailed\n+ much better busy/not busy handling, feels smoother\n+ more sensible workspace checkmarking, good speed improvement\n+ more info displayed in image status bar\n+ red error arrow not always unset ... eg failed file load\n+ try to load a damaged (eg. truncated) image file ... wrong err msg\n+ recover ws after crash fixed\n\nstarted 7.7.17 (23 jan 02)\n+ changed appearance order for subcolumn\n+ params and super start with vislevel 0\n+ '.' now binds more tightly than '\\'\n+ '\\' renamed to '?'\n+ '&&' and '||' split to separate logical and bitwise operators\n+ removed local function display\n+ better code generated for access to members across nested classes\n+ better preservation of sharing in class browser\n+ decompile makes loop labels\n+ non-row locals link back to enclosing row correctly\n+ inter-row dependencies via non-row locals spotted\n+ user def of default constructor banned\n+ nested classes with implicits refs now work\n+ operator overloading added\n\nstarted 7.7.16 (14 dec 01)\n+ delay GC to once per sec where possible\n+ ruler preferences\n+ rows only reset on enter, not on dirty\n+ graph.c indents prettily for easier debugging\n+ nasty GC bug nailed\n+ trace prefs options\n+ assert() on program forced close fixed, class redef bug fixed, program\n  window tracks filemodel->modified more closely\n+ region clone menu\n+ destroy regionviews on hide\n+ smarter and simpler layout resize\n+ final (I hope) precedence changes ... now just like C\n+ '<<', '>>', '~' and '@' (function compose) added \n+ row recomp refinement ... simpler and faster\n+ oops, menu items all done in imageview\n+ row locals with external refs were not adding to top level dirties correctly\n+ more rigorous backtracking for deducing recomp order\n+ fancy pantsy heapmodel_reset() system for great justice\n+ traced and optimised recomp ... seldom repeats itself now\n\nstarted 7.7.15 (16/11/01)\n+ rename workspace on top level load\n+ added workspace merge\n+ added column merge\n+ clone stuff done\n+ layout sizing done (tho' not very well)\n+ toggle select and range select for rows\n+ junked all old menus (now in scraps)\n+ fancy new view manager only creates views when required ... x2 speed up on\n  workspace load\n+ file browser lets you change the suffix by typing (eg. type \"fred.jpg\" into\n  save box while files-of-type is VIPS and you save JPEG)\n+ replace and save matrix and image graphics\n+ new Matrix class hierarchy\n+ .nip-x.x.x directory stuff added, \"Preferences\" workspace loaded on startup\n+ Watch class for getting pref settings quickly in C\n+ removed all .iprc code\n+ region drag now synchronous, so it can't lag\n+ max heap size scales with workspaces loaded\n+ duplicates automatically removed from paths, system files renamed to user\n  directory on auto load\n+ workspaces reorder correctly\n+ new row number layout scheme using on model pos layout\n+ row drag 'n drop reordering\n+ is_class predicate\n+ Abut.Left_right and Add menu items done as trials\n+ syntax changes to become more C-like:\n    and/or/eor/not keywords removed ... now &&/& ||/| ^ !\n    & (join) becomes ++ and does list cat too\n    ! (region extract) removed\n    ^ (raise to power) becomes **\n+ precedences changed to be more C-like ... `\\` now binds like array subscript\n\nstarted 7.7.14\n+ oop, about copyright line was wrong\n+ model now has child_add(), child_remove() methods\n+ child_add() child_remove() used for much init and cleanup ... nice!\n+ fewer typed parent/child pointers in models ... getters to cast model \n  parent/child instead\n+ parent_add(), parent_remove() methods in model\n+ XML prettifier does indenting in save files\n+ load/save moved to model from filemodel\n+ text now loaded too, new rhs child add system\n+ forward references in workspace load now work\n+ simplified _build_display() system with _link() method for view subclasses\n+ new iregiongroupview class for managing sets of region displays\n+ more intelligent naming of objects across workspaces\n+ workspace modified set for more actions ... reflected in mainw titlebar\n+ context pointers are back, but inited from _child/parent_add() system\n+ split to nip package\n+ reworks for new package structure\n+ row_recomp() sorts regeneration by row depth\n+ new scan/reset system\n+ Text now derives from Heapmodel, scrapped the last of the model_link() funcs\n+ _refresh_value() -> _update_model()/_update_heap() pair, with ->modified to\n  control behaviour\n+ _stdenv.def changes ... added is_space, split, splitl, split_lines,\n  parse_pint, parse_int, parse_float\n+ program window parses on popdown\n+ gtkutil has set-2-adjustments-at-once convenience function\n+ all tally models (subcolumn downwards) now derive from Heapmodel\n+ Heapmodel -> Heapmodel/Classmodel\n+ all widget models derive from Classmodel\n+ Text now delays parse/compile until recomp\n+ regenerate system now uniform between graphic and text representations\n+ new model_freeze()/model_thaw() system to reduce model_changed() emissions\n+ XML load/save done for all class widgets \n+ only save edited formula ... deduce others\n+ better target symbol naming for region/point/vector/guide create\n+ dialog boxes now have GNOME2 button ordering ... F1 binds to help\n+ old row_change() mechanism ditched ... much simpler and clearer now\n+ all class.c getters renamed\n+ _update_model() -> _update_model()/_new_heap() pair ... faster\n+ ditched base/derived instance vars, new rebuild from base system from new\n  unified model recomp system \n+ ditched remake-from-base system :-( can no longer do islider ... but much\n  cleaner and more intuitive behaviour\n+ tslider is now a proper widget\n+ better jumping region labels during scroll\n+ switch current column on row select\n+ region labels / image window titles change helpfully on workspace switch\n+ fantastically more complicated row_recomp() now deduces recomp order from\n  dependencies\n+ graphic displays only save and restore their settings if they've been edited\n+ text edit resets edits on sub rows \n+ don't make a display or RHS for system rows (eg. this, check, name)\n+ mainw_countdown_animate() now updates display again ... this may cause\n  problems, have to see :-(\n+ tslider has elaborate workaround for slider destroy during changed callback\n  problems\n\nstarted 7.7.12\n+ added program window\n+ reworked TODO list ... only 140 issues outstanding ... :-(\n+ toolkitgroup now emits \"changed\" on any tool/toolkit change\n+ find/find-next thing for program\n+ new info mechanism\n+ link report finds undefined symbols\n+ tree view maintains sort order\n+ model_child_add_before() to aid drag and drop reordering\n+ toolview does menu reordering \n+ popups pass down host widget\n+ general \"are you sure you want to remove\" for models\n+ destroying a tool now destroys associated symbol too\n+ destroying a toolkit destroys all contained tools\n+ destroying a top level row destroys the symbol\n+ symbol/filemodel/model destroy split to finalize as well\n+ stable owns a ref to syms it holds\n+ if destroy a sym, mark all parents as having \"not defined\" errors\n+ expr_error_set() now zaps compiled code to force recompile ... ensures user \n  fixes problems properly\n+ textview always recompiles lines which you hit return on\n+ better typecheck error messages for widget classes\n+ right button menu on rulers\n+ xml save\n+ load_text and save_text methods in filemodel.c for tool/toolkit load/save\n\nstarted 7.7.11\n+ added trace window\n\nstarted 7.7.10\n+ BI_CONS is lazier and faster\n\nstarted 7.7.9\n+ \"print\" builtin added\n+ oops, parse_function() was not passing sym down\n+ better checkargs function\n+ x-ray print menu patched, duh\n\nstarted 7.7.8\n+ browse now uses new image display code\n+ ooops, PPM/PGM/PBM read added\n+ conversion is now refcounted\n+ all old image/region code removed\n+ old window/dialog code removed\n+ paintbox/edit/magic/menu/calibrate/cursor/request/dragdrop also gone for now\n+ last of X11/Motif gone ... # of lines down 20k!\n+ iregion/iregionview added\n+ finally GNUified it\n+ fixed newimage dialog\n+ region redone as subclass of image\n+ ip class names now have initial caps\n+ better iwindow popdown behavious\n+ imagedisplay implements gtk focus model\n+ imageview key navigation: left-right-up-down-in-out, zoom to fit\n+ imagedisplay repaint probs fixed\n+ new expr_value_new()/_destroy() system to track images\n+ regionview added\n+ cursor manager added to iWindow\n+ jumping region labels!\n+ nasty reduce bug nailed ... heap corrupted if super-class constructor failed\n+ class construction errors handled gracefully\n+ rubberbanding regions on imagepresent\n+ point and vector display types added\n+ ivector/ivectorview added\n+ instance vars can be virtualised by heapmodel ... for code sharing between\n  iregion/ivector/etc. ... sort of a lame MI fudge\n+ regionview morphs between display types if unfrozen\n+ Region/Vector/Point/HGuide/VGuide classes added\n+ lists/image-bands index from zero\n+ mark spine stack on GC ... oops, sometimes broke for nested recomp\n+ reduce.c -> reduce.c/action.c\n+ new action_strict() interface handles nested reduce_spine() calls correctly\n  ... allows mutually recursive locals\n+ some reworking of reduce.c ... still not very pretty :-(\n\nstarted 7.7.7\n+ [] can have whitespace between the [s\n+ conversion.c added ... manages display conversion model and region/thread\n  display stuff\n+ _list.def and _stdenv.def reworked from Miranda 2 stdenv:\n\tfoldl function args reversed\n\tswap renamed as converse\n\tfoldl1, foldr1, map2, merge, replicate, scan, until added\n\tfaster sort (merge sort)\n+ option/optionview pasted back in\n+ image/option parts of sym->recomp scrapped\n+ tslider widget ... entry, plus slider\n+ conversionview ... display control bar\n+ tslider does non-linear sliders\n+ now uses 100%, 25%, 400% etc. to show magnification\n+ oops, mono to labq was broken\n+ statusview.[hc] added ... status bar!\n+ iimage now tracks derived image value as well\n+ better file_info display for JPEG/TIFF/PPM in file load\n+ iimage now just has vips_image as class param\n+ matrix/matrixview added, old mask stuff removed\n+ lots of memory leaks removed (thank you memprof)\n+ workspacegroup is a symbol ... workspaces are named root.Workspaces.blah\n+ matrix resize\n+ matrix load\n+ is_string now defined in _stdenv.def, rather than being built in\n+ vips_call knows about new matrix representation\n+ better scanning system for text widgets\n+ better uop/bop error messages with text_decompile()\n\nstarted 7.7.6\n+ decompile for parameter edit, value displays parameters (tho not secrets)\n+ save/save as/close added to model\n+ new workspace save done\n+ better notebook tabs\n+ new iWindowSusp stuff now allows composition of window funcs\n+ iDialog now allows multiple OK buttons\n+ Save/Don't save/Cancel on filemodel close \n+ nasty nested iDialog problem found and fixed\n+ close all filemodels on quit\n+ tookit.c -> tool/toolview/toolkit/toolkitview; toolkits are filemodels\n+ all sprintf()s gone\n+ empty/load/replace for filemodel done\n+ workspacegroup/workspacegroupview added\n+ toolkitgroup/toolkitgroupview added\n+ model -> view links removed, signals for 'changed' ... bit simpler n nicer\n+ views track parents and children\n+ scan set for auto re-reads of widgets\n+ reset/scrollto now signals too\n+ now called ip2\n+ gtkdisp imagedisplay/present/asynch code pasted in\n+ \"image\" builtin renamed as \"vips_image\"\n+ image class added\n+ iimage/iimageview added ... thumbnail display!\n+ new (smarter) behaviour for spin expand/shrink; affects rhsview visibility\n  as well as subcolumnview visibility\n+ threaded display code patched in\n+ imageview added\n+ image display rulers, magnification, titlebar wired up to menus\n\nstarted 7.7.5\n+ better centering of dialogs over their parents\n+ oops, silly bug in stable_resolve()\n+ new expr_resolve() sorts out static/dynamic scoping problems\n+ uses mkstemp() for temp image file names\n+ new mark dirty scheme\n+ small destroy bugfixes\n+ better tallyrow_recomp_rethink() code finds the right expr more often\n+ better binding to root for dynamic exprs\n+ expr_resolve() before expr_check()\n+ \"super\" member is a regular member, not a parameter\n+ about dialog, with easter egg :-)\n+ new code for recomputation of superclasses ... does \"this.x\" if any supers\n  change, tracks use of params in super construct\n+ warp focus to column bottom on column select\n+ ':' char banned in file names\n+ workspace load/save/save as/close done\n+ workspace tab menu and tooltip\n+ don't mark zombies dirty\n\nclean up of front end started\n+ Symbol extends GtkObject, Workspace extends Symbol\n+ Columnset renamed Workspaceview, members moved between it and Workspace\n+ Column split into Column and Columnview\n+ refresh_note() system added\n+ Model class underpins symbol/workspace/column etc.\n+ tallycolumn -> subcolumn/subcolumnview\n+ tallyrow -> row/rowview\n+ tallyitem -> view\n+ tallyrhs -> rhs/rhsview\n+ text -> text/textview\n+ Heapmodel class added to underpin slider/toggle/option/matpanel\n+ slider -> slider/sliderview\n+ toggle -> toggle/toggleview\n+ mono <-> sRGB gammas both ways now\n\nstarted 7.7.4\n+ reload $VIPSHOME/lib on menu and plugin reload\n+ no longer includes gtkintl.h\n+ better namecaption API\n+ better iwindow/idialog/namecaption build inheritance \n+ cleaned up naming in main.c\n+ gtkfilesel2 now inherits from idialog\n+ filesel now inherits from gtkfilesel2\n+ browse now inherits from idialog\n+ now builds cleanly on Sun cc\n+ found horrible gtkfilesel2 bug\n+ fileselect removed\n+ toggle/option/matpanel edit uses idialog\n+ secret optimisation supressed for tally display\n+ edit value (rather than source) for class params\n+ edit reset on column after ENTER\n+ asynch/menu bug fixes backported\n+ Histogram.def renaming\n+ -,/,* for realvec\n\nstarted 7.7.3\n+ secret now in terms of expr\n+ compile now in terms of expr, not sym\n+ bulletproof errors()/verrors()\n+ resolve_names now knows about tally scopes as well as symbol scopes\n+ linked global recompute and tallyrow recompute up\n+ new link object joins up topsyms for recomputation ... saves a search on\n  tallyrow dirty, makes multiple external refs work\n+ better slider edit dialog\n+ new code for '.' operator now records context in heap, so we can spot \n  dynamic dependencies\n+ improved link objects ... better handling of multiple links, more stuff\n  deduced, support for static and dynamic links\n+ dynamic dependency management\n+ class parameter edit\n+ new spin widget for class display open/close\n+ class member visibility table, controlled by spin widget\n+ new im_vipshome() startup code\n\nstarted 7.7.2\n+ ws error button colour fix\n+ big sym/expr/row relationship reorganisation\n+ better error handling\n+ better tally tooltips\n+ better toolkit flash help, plus flash for sub menus\n+ fixed some input_push/pop() problems\n+ reorganised main menus, better pull-right display rules\n+ automatic.c -> mainw.c ... lots of renaming and tidying up\n+ multiple workspaces linked to symbols, columnsets now make syms local to\n  their workspaces\n+ iwindow/idialog improvements, newcolumn/workspace dialog is now subclassed\n  off idialog\n+ countdown fixes\n+ another nasty tallyrow destroy bug\n+ error message display fixes\n\nstarted 7.7.1 ... 19/10/00\n+ another nasty destroy bug\n+ class browser looped for some classes containing errors\n+ default constructor now not displayed (unless overridden in an enclosing\n  class)\n+ recomp inside a class instance done\n+ abs in _stdenv.def failed for complex\n+ nasty gcc error in class_member() with -O2\n+ tallytext rhs handling broken out into tallyrhs ... tallytext is simpler\n  ... now have graphic/klass/text display\n+ new tallyitem_trigger system with better error propogation\n+ fold/unfold button for class instances\n+ button tooltip displays long messages \n+ tally => row rename\n+ recomp/refresh/refresh_value sequences optimised\n+ expr_clone() now works for function members of classes\n+ refresh_value no longer uses _trigger() propogation mechanism\n+ now tracks prhstext ... everything but the function name ... needed for\n  class edit of local functions\n+ class/super now properties of expr, not sym ... classes are expressions, \n  not symbols\n+ displays args to function members of classes\n+ sym_tab tracks insert order, used to order class members in tally\n+ table_find_child handles hidden children\n\nstarted 7.7.0 \n+ default constructors\n+ escape cancel in idialog\n+ 'root.' and 'workspace.' static scope references\n+ recalc dynamic dependencies on link\n+ super-class constructors are blocked from referring to locals (other than \n  params)\n+ class_member_base() stuff sorted out in slider.c ... usually need\n  non-overridden value\n+ display update block mechanism for tally stops widgets updating\n  themselves\n+ slider text value display redone\n+ fixed a couple of nasty destroy bugs\n+ 'Arithmetic.Add' now does sliders!\n+ released as 7.7.0\n"
  },
  {
    "path": "Makefile.am",
    "content": "SUBDIRS = \\\n\tsrc \\\n\ttest \\\n\tman \\\n\tshare \\\n\tpo \n\nEXTRA_DIST = \\\n\tautogen.sh \\\n\tdoc \\\n\tproj \\\n\tm4 \\\n\tscreenshot.png \\\n\tnip2.desktop.in \\\n\tnip2.xml \\\n\tnip2.appdata.xml\n\nnip2appdir = $(datadir)/applications\n\nnip2mimedir = $(datadir)/mime/packages\n\nnip2appdatadir = $(datadir)/appdata\n\nnip2app_DATA = nip2.desktop\n\nnip2mime_DATA = nip2.xml\n\nnip2appdata_DATA = nip2.appdata.xml\n\ninstall-exec-hook:\n\t-rm -rf ${DESTDIR}$(datadir)/doc/nip2 \n\t$(mkinstalldirs) ${DESTDIR}$(datadir)/doc/nip2\n\t-cp -r ${top_srcdir}/doc/html ${top_srcdir}/doc/pdf ${DESTDIR}$(datadir)/doc/nip2\n\t-rm -rf ${DESTDIR}$(datadir)/doc/nip2/html/CVS\n\t-rm -rf ${DESTDIR}$(datadir)/doc/nip2/pdf/CVS\n\nif UPDATE_DESKTOP\ninstall-data-hook:\n\t-$(UPDATE_MIME_DATABASE) ${DESTDIR}$(datadir)/mime\n\t-$(UPDATE_DESKTOP_DATABASE) ${DESTDIR}$(datadir)/applications\nendif\n\ndist-hook:\n# make sure we don't get any .svn dirs from EXTRA_DIST\n# also \"fred\" gets left around occasionally\n\t-find $(distdir) -name .svn -exec rm -rf {} \\;\n\t-find $(distdir) -name fred -exec rm {} \\;\n\nuninstall-hook:\n# make sure we have write permission for 'rm'\n\t-chmod -R u+w ${DESTDIR}$(datadir)/doc/nip2\n\t-rm -rf ${DESTDIR}$(datadir)/doc/nip2\n\t-$(UPDATE_MIME_DATABASE) ${DESTDIR}$(datadir)/mime\n\t-$(UPDATE_DESKTOP_DATABASE) ${DESTDIR}$(datadir)/applications\n"
  },
  {
    "path": "NEWS",
    "content": "\n"
  },
  {
    "path": "README.md",
    "content": "# nip2 --- a user interface for libvips\n\nWe now have a first public test release of nip4, a rewrite of nip2 for the\ngtk4 UI toolkit. If you have some time to try it, any feedback would\nbe very welcome:\n\nhttps://github.com/jcupitt/nip4/releases\n\n## nip2\n\nnip2 is a GUI for the [libvips image processing \nlibrary](https://libvips.github.io/libvips). It's a little like a spreadsheet:\nyou create a set of formula connecting your objects together, and on a change\nnip2 will recalculate. This makes it convenient for developing image processing\nsystems since you can watch pixels change as you adjust your equations.\n\nBecause nip2 uses libvips as the image processing engine it can handle very\nlarge images and only needs a little memory. It scales to fairly complex\nworkflows: I've used it to develop systems with more than 10,000 cells,\nanalyzing images of many tens of gigabytes. It has a batch mode, so you\ncan run any image processing system you develop from the command-line and\nwithout a GUI.\n\n![image](https://github.com/user-attachments/assets/aa2c3e0f-9f96-4594-9f1d-62ef770d0775)\n\n## Installing\n\nYou can probably install nip2 via your package manager. For\nWindows and OS X, you can download a binary from the [nip2 releases\npage](https://github.com/libvips/nip2/releases). If you have to build from\nsource, see the section below.\n\n## Documentation\n\nnip2 comes with a 50-page manual --- press F1 or Help / Contents in the\nprogram to view it.\n\n## Building nip2 from source\n\nIn the nip2 directory you should just be able to do the usual:\n\n```\n./configure\nmake\nsudo make install\n```\n\nBy default this will install files to `/usr/local`. Check the summary at the\nend of `configure` and make sure you have all of the features you want. \n\nIf you downloaded from GIT you'll need:\n\n```\n./autogen.sh\n```\n\nfirst to build the configure system. \n\nnip2 needs vips, gtk2 and libxml2 at runtime and flex/bison at compile time.\nIf you have fftw3, gsl, goffice, libgvc you get extra features.\n\n### snapcraft\n\nRebuild snap with:\n\n```\nsnapcraft cleanbuild \n```\n\nThough it's done automatically on a push.\n"
  },
  {
    "path": "THANKS",
    "content": "nip THANKS file\n\nnip is a rewrite of ip, so see the THANKS file for that package. \n\nWe've had very helpful funding from the European Commission and from\nHewlett-Packard.\n"
  },
  {
    "path": "TODO",
    "content": "- add tests for new stuff\n\n- seeing occasional \"rewind image with active regions\" message\n\n- should parse_float / _int etc. allow leading and trailing spaces?\n\n    (split is_space x)?0\n\n- how about adding\n\n\tzip2 10 [1..5] == [[10, 1], [10, 2], [10, 3], ..\n\n  should be harmless, and quite useful\n\n  same for zip3 etc. as well\n\n  check zip use, we probably have this code there already, in various places\n\n- sharpen should use new interface?\n\n- can we call affine from nip2 vips_call? do we need a double array?\n\n- hough_circle etc. don't get cached ... they use the vips8 API and the vips\n  cache only works for vips8\n\n  we can't turn on the vips8 cache since it does not know about invalidate\n\n- columns can move about on load in large workspaces\n\n- hide tabs if only one tab in window, though we'd need to allow tab drop \n  anywhere in window for that\n\n- Matrix / New / Laplacian\n\n  edit a cell, turns into a plain matrix\n\n  need to override edit method\n\n  same for gaussian\n\n  rather tricky, compared to square / circle etc. \n\n\n\n- breadcrumb trail for prog window, so you can get back to where you were?\n\n- lambdas don't pattern match?\n\n\t(\\[a, b] a + b)\n\n\n\n- load jpg, ^Q, no leaks\n  load jpg, paint bar, paint one dot, ^Q, no leaks \n\n  load jpg, extract area, paint bar, paint one dot, ^Q, leaks \n  load jpg, extract area, paint bar, paint one dot, ^Z, ^Q, leaks \n  load jpg, extract area, paint bar, paint one dot, close window, ^Q, leaks \n\n  seems to leak:\n\n  \toriginal image, \n  \tone large regions on that image (full width)\n\textract area operation\n\textracted image\n\tregion a bit bigger than paint action on that image\n\n0) VipsRegion (0x8b052a0)\nVipsRegion (object), base class VipsRegion: 0x8b052a0, im = 0x887aad0, left =\n192, top = 128, width = 45, height = 2 VipsRegion (0x8b052a0)\n1) VipsImage (0x887aad0)\nVipsImage (image), image class 237x202 uchar, 3 bands, srgb, partial VipsImage\n(0x887aad0)\n2) VipsImage (0x8016b30)\nVipsImage (image), image class 972x1296 uchar, 3 bands, srgb, openin VipsImage\n(0x8016b30)\n3) VipsRegion (0x8b05340)\nVipsRegion (object), base class VipsRegion: 0x8b05340, im = 0x8016b30, left =\n0, top = 30, width = 972, height = 283 VipsRegion (0x8b05340)\n4) VipsExtractArea (0x882a910)\nVipsExtractArea (extract_area), extract an area from an image - extract_area\n((VipsImage*) 0x8016b30) 142 158 237 202 VipsExtractArea (0x882a910)\n\n  something to do with vips_image_wio_input() and the way it rewinds a PARTIAL\n  image? called from im_rwcheck()\n\n\n- os x build reports missing jasper dylib?\n\n- draw_circle could extract, draw and insert for huge memuse reduction\n\n- section on compat mode for the docs\n\n  see mail to MvGulick for some notes\n\n- expose more of the tone funcs in nip2\n\n- quite a few hist operations have no GUI ... histspec, for example? \n\n- nip2 should use zooming support, if possible\n\n- the windows setup .exe install a bazillion .png icons we will never use,\n  then installs them all again as .svg, which we will certainly never use\n\n- add extract_volume, cf. \"grid\"\n\n  record tile_size in meta somewhere? grid could set it, save a parameter off\n  extract_volume\n\n  also extract_sequence to get volume over time\n\n- image + complex constant would be nice\n\n\n\n\n- ban parameters which are built-ins, eg. \"im\", \"re\" etc., you get nasty\n  crashes\n\n  see also notes below: a new parser could fix this\n\n  can only ban for new code? do we have duff code in compat?\n\n  argh yes there are at least 15 like this, fix them or fix the parser? also\n  need to disable this check for compat defs\n\n  better to fix the parser, it can't be that hard\n\n  need to fix up the list comp compiler too, sigh\n\n\n\n\n\n\n- we can't define local superclasses at the moment\n\n  eg. consider:\n\n  \tFred = class {\n\t  Jim a = class {\n\t    value = a + 12;\n\t  }\n\n\t  Jennie x = class Jim x {\n\t    value = 99;\n\t  }\n\t}\n\n  you can't do (Fred.Jennie 12) since Jim will have a secret 'this' param\n  (because it is a class member) and superclass constructors can't have\n  secrets\n\n  don't automatically give all members 'this' as a secret, check that they\n  make references to other class members that do need secrets first \n  \n- turn on GM in prefs, have to restart before _stdenv.def:magick sees the \n  change\n\n- try this:\n\n\tWorkspaces.untitled\n\thas_member \"A1\" A1\n\n  doesn't seem to work?\n\n\n\n- matrix_gaussian_blur could have an 'accuracy' or 'max error' param? expose\n  in custom blur etc.\n\n\n\n- oo_binary etc. needs revising, we don't search down branches as we should\n\n  for example, Matrix does:\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\n  which is stupid, we should not wire Real and Vector in there, it ought to be\n  something like:\n\n\t\t[this.Matrix_base (op.fn this.value x),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\n  ie. don't strip the .value off x and rely on op.fn to do that, but this\n  breaks in various ways\n\n  remove all of _Object and redo it, thinking about what we want operators to\n  look like and what we want types to look like. \n\n  Have a base class for operators that does most of the standard stuff\n\n  get rid of the operator types rewrap / arithmetic / relational etc. etc. \n\n\n\n\n\n\n\n\n- try\n\n\tpoint re\n\t\t= x\n\t{\n\t\t(x, y) = re;\n\t}\n\n  it's the 're' param, it stops x being bound to the\n  get-real-part-of-complex builtin\n\n  expands to\n\n\tpoint re\n\t\t= x\n\t{\n\t\t$$x = re;\n\t\tx\n\t\t\t= re $$x, is_complex $$x\n\t\t\t= error \"bad match\";\n\t}\n\n  add secrets\n\n\tpoint point.re\n\t\t= x point.re\n\t{\n\t\t$$1 $$1.re = point.re;\n\t\tx x.re\n\t\t\t= x.re ($$x point.re), is_complex ($$x point.re)\n\t\t\t= error \"bad match\";\n\t}\n\n\nx compiles to\n\nif_then_else (<symbol \"point.x.is_complex\"> (<symbol \"point.$$pattern_lhs78\"> <symbol \"point.re\">))\n <symbol \"point.x.re\"> (<symbol \"point.$$pattern_lhs78\"> <symbol \"point.re\">)\n <symbol \"point.x.error\"> <Managed* 0x37c5a80>\n\nabstracting point.re\n\nafter var abstract\n\n((S ((Sr (if_then_else <compileref \"point.x\">)) ((Sl ((Sr (&& <compileref \"point.x\">)) ((Sr <symbol \"point.x.is_complex\">) <symbol \"point.$$pattern_lhs78\">))) true))) ((Sl ((Sr SHARE0[(: <compileref \"point.x\">)]) ((Sr <symbol \"point.x.re\">) <symbol \"point.$$pattern_lhs78\">))) ((REF0 (<symbol \"point.x.error\"> <Managed* 0x3a55980>)) [ ])))\n\nreduce and get \n\nreduce_spine: (<symbol \"point.x.re\"> (<symbol \"point.$$pattern_lhs0\"> (I (1,2))))\nreduce_spine: (<symbol \"point.re\"> (<symbol \"point.$$pattern_lhs0\"> (I (1,2))))\nsym-param found, argh: point.re\n\n  maybe fix this when we revise the parser\n\n  would be a good time to add multiple definitions as well\n\n- redo name resolution in parser ... scrap the patch thing, instead have a\n  separate 'resolve' step that runs after parsing a top-level\n\n  don't create ZOMBIE symbols, instead make REF nodes in the tree\n\n  this binds local references, but leaves external refs dangling\n\n  we do a final link at load time when we copy into the heap\n\n  do we need zombies at all now?\n\n  make a fork for this\n\n\n\n- we have ws->window_width, can we use the one on Model now instead?\n\n\n\n- new inplace stuff needs a test suite\n\n- 'don't show this dialog again' on delete row dialog, also in prefs\n\n  box_yesno() could take a string which is the name of a pref to check for\n  ask-or-not\n\n\n\n- how about something that does:\n\n\t  im' = operation_list [a, b, c, d] im\n\n  it does a fold:\n\n\t  im' = d (c (b (a im)))\n\n  but the intermediate images are reused, so you can do in-place stuff with it\n\n  we could get rid of lineset!\n\n\n\n\n\n\n- mac binary has a broken im_text() argh\n\n- do we allow\n\n\t[r, g, b] = Image_file \"babe.jpg\"\n\n  since ? is band index and list index, it seems to make sense\n\n  we have \n\n  \timage ++ image\n  \timage ++ [] == image\n\n  for bandjoin, so that lines up too, I guess\n\n  hmm\n\n  \treverse image\n\n  to swap the bands over? heh need to be able to override hd and tl\n\n- Ackermann\n\n        http://shootout.alioth.debian.org/great/benchmark.php?test=ackermann&lang=all&sort=cpu\n\n        A x y\n                = y + 1, x == 0\n                = A (x - 1) 1, y == 0\n                = A (x - 1) (A x (y - 1));\n\n        correct test result: A 3 4 == 125\n\n  A 3 10 is benchmark test ... we fail with a \"C stack overflow\" error\n\n  A 3 9 == 4093 works OK\n\n  we could make this a lot quicker with some arithmetic streamlining\n\n  could we do tail-recursion elimination?\n\n  strictness analysis would help too\n\n- Fib\n\n        http://shootout.alioth.debian.org/great/benchmark.php?test=fibo&lang=all&sort=cpu\n\n        F x\n                = 1, x == 0\n                = 1, x == 1\n                = F (x - 2) + F (x - 1);\n\n  correct output F 32 == 3524578\n\n  cima is ~370s for this (!!)\n\n  work machine is about 50s\n\n  dell vostro laptop is 45s without optimiser\n\n- turn on DEBUG in heap.c, run the fibonacci benchmark\n\n  we heap_copy F every time it recurses! because when we heap_copy we don't\n  link recursive references\n\n  try fixing this ... but remember the problems we had with shared classes\n  when we did link-to-value rather than link-to-copy\n\n  we also have a huge amount of stuff in the heap, could we trim this down?\n  how does it all get pulled in? is it preferences?\n\n  in nip1, F is about 4x faster\n\nWONTFIX for 7.20\n================\n\n- look at:\n\nhttp://www.eggheadcafe.com/software/aspnet/35467981/programmatic-console-appl.aspx\n\n  possibly better than nip2-cli.exe\n\n- turning a column from Many Stats into a vector for doing arithmetic is very\n  tricky argh\n\n  add a matrix->vector converter? or maybe a one column or 1 row matrix should\n  also be a vector\n  \n- try:\n\n\t nip2 Workspaces.uniformshapes2.A1.start_line=21 uniformshapes2.ws \n\n  --set does not work for non-toplevels\n\n- try:\n\n\tA1 = [1]\n\tA2 = [x :: x <- A1]\n\n\tchange A1, A2 does not update, argh\n\n  we get:\n\n\tlink_expr_new: expr A2.$$lcomp0 references link->child = A1\n\n  so perhaps we are updating the local of A2, but not A2?\n\n  A2 is certainly being marked dirty ... on change of A1 we get:\n\n\trow_dirty_set_single: A1  clear_error = true\n\tsymbol_dirty_set: A1 (0x1a59480)\n\tsymbol_dirty_set: A2 (0x1a595a0)\n\tsymbol_recalculate_check: untitled.A1\n\trow_dirty_clear: A1 \n\trow_recomp_all: done row A1  - 0.000143873s\n\trow_dirty_set_single: A1  clear_error = false\n\trow_dirty_clear: A1 \n\tsymbol_dirty_clear: A1 (0x1a59480)\n\t\tsuccess: [2]\n\tsymbol_recalculate_check: untitled.A2\n\tsymbol_dirty_clear: A2 (0x1a595a0)\n\t\tsuccess: [1]\n\n  so maybe A2.something is being updated, but the row is not\n\n  we now mark a row dirty if a sub-expr is dirty. but in row_renerate(), we\n  don't build subexprs \n\n  should we mark the subexpr dirty? (or maybe we do?)\n\n  or should we always copy all subexprs when we copy an expr\n\n  or only subexprs with no row?\n\n  do we calc rows outside-in or inside-out? does this affect copying subrows?\n\n  when do we copy now, the first time a row is made?\n\n- we destroy and rebuild all links during recomp (eg. turn on DEBUG in\n  link.c), why is this? can't we only rebuild on a change of source text?\n\n- fix the FIXME in itext_clear_edited() or wherever it is\n\n- try:\n\n\tstart nip2\n\tdir untitled\n\tcreate A2, A3, etc.\n\tA1 does not update\n\n  when we add/remove a def to workspace, should we mark the ws dirty?\n\n- lambdas should allow patterns? eg.:\n\n\tmap (\\[x, y] x + y) [[1, 2], [3, 4]] == [3, 7]\n\n- OS X bundler:\n\n   http://sourceforge.net/apps/trac/gtk-osx/wiki/Bundle\n\n  test?\n\n- imageinfo_make_paintable() no longer copies to a file, since this used to\n  cause problems with dangling pointers because of the im_close()s we had to\n  do\n\n  however, this means we now do all painting in memory :-( do we need to add\n  API to change a memory image (eg. a \"p\") into a file?\n\n- test Joe's layout thing, compare to the thing we do in study2 to make the\n  diagnostic image\n\n- im_blend(), im_ifthenelse(), im_add() etc. now do bandalike/formatalike\n\n  where do we use our bandalike/formatalike stuff? remove our stuff, though\n  make sure we have equivalents in vips now\n\n- outline text example\n\n- needs a custom convol menu item which can loop over a group of matricies\n  with a single image\n\n  actually, we need to nail this down, otherwise when we pass in a list of\n  sample texts the loops don't nest\n\n- right-click menu on row button should have items for \"Jump to referrer / WC1\n  / JC1 ...\" and \"Jump to referred / ...\"\n\n- why didn't im_copy_file() work? mysterious\n\n- line colours are wrong, argh, very mysterious, see\n\n  \tplot_new_gplot()\n\n- gtk3.0 tests:\n\n\tbuild with\n\n\t#define G_DISABLE_DEPRECATED\n\t#define G_DISABLE_SINGLE_INCLUDES\n\t#define GDK_DISABLE_DEPRECATED \n\t#define GTK_DISABLE_DEPRECATED\n\t#define GDK_DISABLE_SINGLE_INCLUDES \n\t#define GTK_DISABLE_SINGLE_INCLUDES\n\n\tpaste into config.h, somehow\n\n  need to remove:\n\n\tGtkType\n\tgtk_type_new\n\tgtk_signal_connect\n\tGTK_SIGNAL_FUNC\n\tgtk_signal_handler_block_by_data\n`\tgtk_signal_connect_object\n\tGTK_CHECK_CAST\n\tGTK_CHECK_TYPE\n\tGtkSignalFunc\n\n- add Set menu to Math with mkset/union/intersection/difference ?\n\n  could do bit operations on images?\n\n- lcomps like:\n\n\targh = [x :: x <- poop]\n\n  the 'x' gets copied inside the lcomp, leaving a zombie 'x' attached to argh,\n  which Program / View / Errors then reports\n\n  fix: don't resolve names as we parse and junk the ugly patch list thing\n\n  instead, have a separate resolve stage that runs after we've moved scraps\n  of graph to their final home\n\n- if we want full VipsObject introspection we will need a lot more\n\n\tvips_object_arguments (name2gtype \"VipsInterpolateYafrsmooth\")\n\t\t-> [\"sharpness\"]\n\n  need some equivalent for GParamSpec / VipsArgument\n\n  \tVipsArgument name type .... = class {}\n\n  return a list of these from vips_object_arguments()?\n\n- heap_map_dict() should be reduce_map_dict(), since it does reduction, argh\n\n  redo heap_map_dict() in terms of reduce_map_dict()\n\n  actually, remove all the reduce_ stuff, it's daft to have a distinction\n\n  something to do when we break Snip out into libsnip\n\n- Plot window should have image header menu item?\n\n  not trivial, image header needs a conversion to watch\n\n  we'd need to make a conversion in plotmodel\n\n- filesel guess-file-type-from-suffix needs fixing\n\n  copy the vips model of having a user_name which is just \"Workspace\" or\n  somesuch, and making \"Workspace file (*.ws)\" string at runtime\n\n  use this to identity file types in util.c as well: get_image_info() needs it\n\n- for rows made by typing stuff, always show the formula as well as the value\n\n  by default anyway?\n\n  we'd need to always show the up/down arrows, not just for classes\n\n- drag from an image thumbnail to the ws background and you get a new column\n  with \"A2\" or whgatever in\n\n  does not work for plot thumbnails! how annoying\n\n- right-click on image background to get a context menu with\n  save/replace/header? same as row thumbnail context?\n\n- look at using goffice instead of gtkplot for graphs\n\n\thttp://ftp.gnome.org/pub/gnome/sources/goffice/\n\n  also in synaptic\n\n  there's also a new cairo-based gtkplot in SVN, apparently\n\n- try\n\n\tlast [1..]\n\n  then CTRL-W ... we can quit the app, but it's still evaling and the prompt\n  never comes back\n\n- Math / Cluster is a bit useless, will it work for complex numbers? vectors?\n  colours? groups?\n\n  what would we have to do to get it to work for these other types?\n\n- toolkit load is where compiled code would go in\n\n  need to make load / parse / compile self-contained ... the only output is a\n  list of symbols, each with code and sub-symbols; there are no toolkits or\n  whatever made\n\n  after load / parse / compile, we need to walk the symbol list building tools\n  and all that stuff\n\n  we do:\n\n  \tload toolkit:\n\t\tget filesize, date last modified, md5sum\n\t\tlook in ~/.nip2-7.x.x/cache for a file named with that md5sum\n\t\tif present, open and check first two fields: filesize and date\n\t\tif match, load compiled code\n\t\tif no match, load / parse / compile toolkit, then save compiled\n\t\t\tcode to ~/.nip2-7.x.x./cache\n\t\twalk symbol list building tools and all that stuff\n\n  how much time will this really save? can we easily get an estimate?\n\n  steps to follow:\n\n  1.\tmake load / parse / compile self-contained, with separate pass to\n  \tbuild tools etc.\n\n\tthis is a useful cleanup whatever else we do\n\n  2. \tnow we know exactly what the output of load / parse / compile is, we\n  \tshould be able to write to a file\n\n\tmake our own binary format, don't use XML ... we want speed\n\n  3. \ttry loading and benchmarking\n\n  4.\tif the benchmarks look promising, harden and polish\n\n\n- numbering of group of group save seems to skip one at end of line?\n\n- Math / Cluster is a bit useless, will it work for complex numbers? vectors?\n  colours? groups?\n\n  what would we have to do to get it to work for these other types?\n\n- segv in test_toolkits on laptop (inside fftw3) ???!? valgrinds cleanly on \n  work machine\n\n- try\n\n\tlast [1..]\n\n  then CTRL-W ... we can quit the app, but it's still evaling and the prompt\n  never comes back\n\n- configure no longers sets GMSGFMT, is this OK? test on OS X\n\n- for rows made by typing stuff, always show the formula as well as the value\n\n  by default anyway?\n\n  we'd need to always show the up/down arrows, not just for classes\n\n- drag from an image thumbnail to the ws background and you get a new column\n  with \"A2\" or whgatever in\n\n  does not work for plot thumbnails! how annoying\n\n- right-click on image background to get a context menu with\n  save/replace/header? same as row thumbnail context?\n\n- look at using goffice instead of gtkplot for graphs\n\n\thttp://ftp.gnome.org/pub/gnome/sources/goffice/\n\n  also in synaptic\n\nWONTFIX for 7.14\n================\n\n- quit while a thumbnail is painting: IMAGEs are leaked? seems esp. bad with\n  greyc, perhaps just because it's so slow\n\n- do we enforce no-args-to-LHS-pattern anywhere? try\n\n\t[a,b] a b = 12;\n\n- use destroy_if_destroyed() in more places? \n\n\tgrep destroy_ *.h\n\n- after pressing \"Process\" in the edit window, we always select last_sym,\n  which is often not what we want\n\n  make it jump less after a process ... eg. try editing something in the\n  middle of Image/Transform, very annoying\n\n- use compile->last_sym to spot chains of defs\n\n  multiple definitions of the same function are allowed, provided they all\n  multiple definitions of the same function are allowed, provided they all\n  have the same number of arguments, and provided only one of them has no\n  argument pattern matching\n\n  example:\n\n  \tfred [a, b, 1] = a * b;\n\tfred (Image x) = rot90 x;\n\tfred z = error \"what\";\n\n  any of these can have locals, those locals just apply to that one\n  definition\n\n  this compiles to:\n\n\tfred $$a4 \n\t\t= $$fred1, is_list $$a4 && len $$a4 == 2 && $$a4?2 == 1\n\t\t= $$fred2, is_instance_of \"Image\" $$a4\n\t\t= $$fred3\n\t{\n\t\t$$fred1 \n\t\t\t= a * b\n\t\t{\n\t\t\ta = $$a4?0;\n\t\t\tb = $$a4?1;\n\t\t}\n\t\t$$fred2 \n\t\t\t= rot90 x\n\t\t{\n\t\t\tx = $$a4;\n\t\t}\n\t\t$$fred3 \n\t\t\t= error \"what\";\n\t\t{\n\t\t\tz = $$a4;\n\t\t}\n\t}\n\n  so each pattern-matching definition generates a condition and an action\n\n  constants in patterns become part of the condition test\n\n  the action goes into a private function, the conditions are joined together\n  in the function wrapper\n\n  the no-pattern case (if present) becomes the action for the \"otherwise\"\n  clause in the wrapper\n\n  if not present, we generate (error \"pattern match failed\") or somesuch for \n  the default case\n\n  we will need to regenerate the wrapper function every time a definition of\n  fred is added or removed ... can we do this easily?\n\n  when are two definitions considered equal? should we warn about this? \"fred\n  x\" could occur in two files, for example\n\n  process:\n \n\t* we see a \"fred arg-list\" incoming\n\t* does the arg list contain any patterns?\n\t  yes:\n\t\t* do we already have a fred in this scope?\n\t\t  yes: \t\n\t\t\t* the existing fred must be the wrapper, this must be \n\t\t\t  a new possible RHS\n\t\t\t* check that the number of args matches\n\t\t  no:\n\t\t  \t* generate a fred to act as the wrapper\n\t\t\t* add args called $$arg1 etc. to the main fred\n\t\t* add this new fred as a $$fredn local to the current\n\t\t  fred\n\t\t* expand the patterns as local references to the main\n\t\t  fred's arguments\n\t\t* parse the rest of the def in that context\n\t\t* keep the pattern list around, we'll need it to generate the\n\t\t  ifs for the wrapper later\n\t  no:\n\t  \t* do we have a fred in this scope?\n\t\t  yes:\n\t\t  \t* check the previous fred was a pattern matcher\n\t\t  \t* check the number of args matches\n\t\t  \t* check there isn't already a default case\n\t\t\t* add as above\n\t\t  no:\n\t\t  \t* add as a regular non-pattern definition\n\n  issues:\n\n  \t* where do we store the pattern lists? we can't expand them at\n\t  parse-time, since we need them to make the wrapper (which we can't\n\t  make until we've seen all the candidate RHS)\n\t* when one of the RHS is changed, we need to regenerate the wrapper,\n\t  how do we do this? (could nuke the generated code in the compile\n\t  when we see a new RHS, then rebuild the wrapper in compile on the\n\t  next heap_copy?)\n\t* our current condition generator won't work ... we need to test\n\t  consts as well, and it'll be rather inefficient as we'll repeatedly\n\t  test the trunk as we loop over the leaves --- instead, walk the \n\t  pattern recursively top-down testing each node\n\n  process:\n\n  * see \"fred\" (as opposed to simple_pattern)\n  \t* is there already a fred in scope? \n\t  yes:\n\t  \t* was current_compile->last_sym also a \"fred\"?\n\t\t  yes:\n\t\t\t* another definition\n\t  yes:\n\t  \t* this must be an alternative definition\n\n\n- we put the 2nd fred in as a local of the first, but then the 2nd can see all\n  the stuff the first has as locals\n\n\t  z = 42;\n\t  fred 1 = 12 { z = 99; }\n\t  fred 2 = z;\n\n  \"fred 2\" will return 99 :(\n\n\n  we need to make \"fred 2 = z\" into another fred at the same level, eg\n\n  \t$$alternate42$fred 2 = z;\n\n\n  Nope, then how do we link the freds together for remove etc.?\n\n  Better:\n\n  \tsee a new sym (fred), create it\n\n\tparse args with simple names becoming params, patterns becoming\n\t$$arg42 plus a local $$patt42 holding the pattern source\n\n\texpand the pattern to an access def as well, so our children can bind\n\tto it\n\n\tat the = sign, test for any pattern args present .. if there are none,\n\tcarry on as before\n\n\totherwise, make a new local called $$alternate42 or whatever and parse\n\tthe RHS into that\n\n\tat the end of parse, need to resolve outwards twice, since we nest in\n\ttwice\n\n\tnow if we see another fred, check that the number of args matches and\n\tthen parse in as $$alternate99\n\n  what abut\n\n  \tfred 2 a = 12;\n\tfred 1 b = 32;\n\n  the first fred will make a top-level with\n\n  \tfred $$arg12 a\n\t\t=\n\t{\n\t\t$$alernate42 = 12;\n\t\t$$patt12 = 2;\n\t}\n\n  then when we parse the 2nd fred the name of the 2nd param is wrong :(\n\n\n  Even betterer:\n\n  \tuse GLR to split off the four cases for us\n\n\t\tident = \n\t\tpattern = \n\t\tident ident_list = \n\t\tident pattern_list =\n\n\tchange pattern syntax so that ident is not part of simple_pattern\n\n\tneed to change lcomp as well\n\n\tso we need to check why PARSE_PARAMS gets used: can we do without the\n\tparams part? yes, it's used so we can edit functions, but we no longer\n\tdo this\n\n\tthese days all we need is expr I think, but we'd need a small action\n\twrapper around it to wipe out any existing tree and locals\n\n\n\n        Find_item = class\n            Menuaction \"_Find\"\n                (\"find a transform which will map sample image onto \" ++\n                \"reference\") {\n            action reference sample = class\n                Transform b reference.width reference.height {\n                _vislevel = 3;\n\n                // controls\n                order = rubber_order;\n                interp = rubber_interp;\n                wrap = rubber_wrap;\n                max_err = Expression \"Maximum error\" 0.3;\n                max_iter = Expression \"Maximum iterations\" 10;\n\n                // transform\n                [a,b,c] = transform_search max_err max_iter order interp wrap\n                        sample reference;\n\n                transformed_image = Image a;\n                final_error = c;\n            }\n        }\n\n  fails with \n\n\tBad superclass.\n\n\tSuperclass constructor \n\t\"Image_transform_item.Image_rubber_item.Transform\"\n\tshould have no secret arguments.\n\n  but this:\n\n        Find_item = class\n            Menuaction \"_Find\"\n                (\"find a transform which will map sample image onto \" ++\n                \"reference\") {\n            action reference sample = class\n                _t {\n                _vislevel = 3;\n\n                // controls\n                order = rubber_order;\n                interp = rubber_interp;\n                wrap = rubber_wrap;\n                max_err = Expression \"Maximum error\" 0.3;\n                max_iter = Expression \"Maximum iterations\" 10;\n\n                // transform\n                [a,b,c] = transform_search max_err max_iter order interp wrap\n                        sample reference;\n\n                transformed_image = Image a;\n\t\t_t = Transform b reference.width reference.height;\n                final_error = c;\n            }\n        }\n\n  (ie. make the superclass constructor into a member) works fine\n\n\n\n- try using bison's location system\n\n\thttp://www.gnu.org/software/bison/manual/html_mono/bison.html#Locations\n\n- add something to Symbol:\n\n\tSymbol *access_for;\n\n  links generated access def to the $$thing4 which holds the RHS\n\n  handy for the program window, also maybe for lcomp code gen?\n\n  also for row edits\n\n- don't offer to clear temps if there's been a crash \n\n  need to be able to test for process-still-running by PID\n\n  try\n\n  \thttp://msdn2.microsoft.com/en-us/library/ms886766.aspx\n\n\tgboolean\n\tprocess_running( int pid )\n\t{\n\t\tHANDLE handle;\n\n\t\tif( (handle = OpenProcess( 0, FALSE, pid )) ) {\n\t\t\tCloseHandle( handle );\n\t\t\treturn( TRUE );\n\t\t}\n\n\t\treturn( FALSE );\n\t}\n\n- autoarrange after every column resize or move\n\n  animate movement, so columns slither out of the way and in to place when \n  you drop\n\n  duplicate column placement would be odd: maybe place duplicate below? also\n  new column? what about dropping an image on to the ws background?\n\n- there's some left-recursion in the parser, eg. comma_list, is this easily\n  fixable?\n\n- add (*) (operator sections) ... need a binup / uop production? can't\n  do this without losing precedence stuff, it'll need a separate production\n  for sections\n\n- magic definition maker could make a workspace-local def, rather cool\n\n- test classmodel_dict_new() ... part of classmodel member automation\n\n  need to implement member edit for OPTION groups\n\n\tclassmodel_done_member() ... read widget set -> model\n\tclassmodel_buildedit_member( ... model -> build widget set \n\n  part of the [[\"key\",value]] arg type\n\n- can we get VIPS errors reported in Error too?\n\n  we'd need to add logging to vips I think\n\n- toolkits / find doesn't find builtins on their name ... eg. search for\n  \"im_add\"\n\n  too hard to fix with the way searching is done now\n\n- turn on update regions during drag, fix the x pos, try dragging, horrible\n  flickering as we update twice, once after the drag motion and once after the\n  recomp\n\n  if you comment out the explicit vobject_refresh() in \n  regionview_model_update() the flickering goes, but region dragging is then\n  very unresponsive\n\n  fix this when we get fast recomp back again\n\n- have a test_types.ws ... test arithmetic on all combinations of _types?\n\n- panner would be cool\n\n- tooltips on Expression rows always show unedited formula\n\n  could special-case formula for things with expression RHS?\n\n- what about iimage, iregion, iarrow ... can we member automate these? why are\n  they different?\n\n- can't see error indications in noedit mode\n\n  should set a red background for display area as well as for rowview button?\n\n- need to be able to override cons to be able to make a List class :-(\n\n  see reduce.c:1710\n\n  this will change the strictness of cons ... how much breakage will this\n  cause? very unclear\n\n  try this as a quick hack\n\n  need to do this before we can finish List\n\n  need List to make gamma easy\n\n- unselected column headers are too like the bg colour on windows?\n\n- python uses z.real and z.imag to extract real/image, should we add this too?\n\n  we don't really have complex as a true class, so it would be rather odd\n\n  need to add \"[a].head\" etc as well\n\n- python blocks complex->real with casts ... insists you use .imag/.real or\n  abs()\n\n- if nip sees a IM_RW_IMAGE argument, it could automatically do this:\n\n\tint\n\tim_flood_blob_copy( IMAGE *in, IMAGE *out, int x, int y, PEL *ink )\n\t{\n\t\tIMAGE *t;\n\n\t\tif( !(t = im_open_local( out, \"im_flood_blob_copy\", \"t\" )) ||\n\t\t\tim_copy( in, t ) ||\n\t\t\tim_flood_blob( t, x, y, ink, NULL ) ||\n\t\t\tim_copy( t, out ) ) \n\t\t\treturn( -1 );\n\n\t\treturn( 0 );\n\t}\n\n  so it would turn a single IM_RW_IMAGE arg into a paired input and output\n  arg\n\n  could make im_lineset() into a regular inplace func and rely on nip to wrap\n  and unwrap\n\n  junk flood_blob_copy\n\n  nip could do this lazilly ... if we see the user doing\n\n     im_line (im_line ...) ...\n\n  then we could make one memory image and call im_line twice on it\n  destructively ... cool! we'd need to check refcounts to make sure the\n  intermediate wasn't being used anywhere else\n\n  hmm! might actually be very hard, we don't have true refcounts for things in\n  the heap\n\n  need to do it on read instead: \n\n    - for image i\n\n    - use as an IM_RW_IMAGE arg ... copy to a memory area and pass in memory\n      handle\n\n    - return memory area IMAGE j, and set a flag saying \"can operate on\n      destructively\"\n\n    - if we use j as an IM_RW_IMAGE arg, skip the copy and just pass memory\n      area in destructively ... we now have two ImageInfo sharing a single\n      IMAGE\n\n    - !!!!\n\n    - does ImageInfo allow IMAGE sharing? not sure it does\n\n    - maybe this needs to be a vips8 feature when we'll have refcounts on\n      IMAGE\n\n- tooltip on column says which other columns items in this column refer to,\n  and which columns refer to items in this column\n\n- how about a nip start folder common to all versions\n\n  so nip2-7.11.14 tries\n\n    .nip2-7.11.14/start\n    .nip2-7.11/start\n    .nip2-7/start\n    .nip2/start\n\n  or maybe\n\n    .nip2/7.11.14/start\n    .nip2/7.11/start\n    .nip2/7/start\n    .nip2/start\n\n  bit less cluttered\n\n  also, we could have\n\n    .nip2/tmp\n\n  and not have multiple nip2 tmp areas\n\n  workspace recover after crash could break though ... maybe keep ws saves in\n  .nip2/7.11.4/tmp?\n\n- think again about class arg checks \n\n  is there some way we can avoid the _check overhead? or at least check less \n  often\n\n- plotpresent/imagepresent could have a common base class with the focus stuff\n  in? also kb nav, zoom, drag-scroll\n\n  a bit difficult, because we want two different policies on window resize:\n  plot should change the object to match the window\n\n- photographic negative should also be in image/levels ?\n\n  no, it does ->sRGB, (255-) etc., so it's better as a filter\n\n- gtk+ 2.12 has a treeview widget with rectangular select and grid lines\n\n  use instead of gtksheet?\n\n- stop image flickering on clock recomp?\n\n  want background pattern to be a property of the image display widget, not\n  the image?\n\n  so we fade in tiles when that section of the image has never been displayed\n  before (eg. on scroll or zoom)\n\n  we don't fade when that section has been painted and we are just changing\n  the image (eg. on recalc)\n\n  if fadesteps == 1, only paint the sections of the tile for which mask == 255\n\n  this way we will never paint the bg pattern\n\n  need some hack for scroll/zoom ; test for mask == 255 would be slow :(\n\n"
  },
  {
    "path": "autogen.sh",
    "content": "#!/bin/sh\n\n# set -x\n\n# remove /everything/ ready to remake\nrm -f Makefile Makefile.in aclocal.m4 config.* configure depcomp\nrm -rf autom4te.cache\nrm -f install-sh intltool-* ltmain.sh missing mkinstalldirs\nrm -f src/*.o src/nip2 src/Makefile src/Makefile.in \n\n# glib-gettextize asks us to copy these files to m4 if they aren't there\n# I don't have $ACDIR/isc-posix.m4, how mysterious\nACDIR=`aclocal --print-ac-dir`\n\n# OS X with brew sets ACDIR to\n# /usr/local/Cellar/automake/x.y.z/share/aclocal, the staging area, which is\n# totally wrong argh\nif [ ! -d $ACDIR ]; then\n\tACDIR=/usr/local/share/aclocal\nfi\n\nmkdir -p m4\ncp $ACDIR/codeset.m4 m4\ncp $ACDIR/gettext.m4 m4\ncp $ACDIR/glibc21.m4 m4\ncp $ACDIR/iconv.m4 m4\ncp $ACDIR/lcmessage.m4 m4\ncp $ACDIR/progtest.m4 m4\n\n# some systems need libtoolize, some glibtoolize ... how annoying\necho -n \"testing for glibtoolize ... \"\nif glibtoolize --version >/dev/null 2>&1; then \n  LIBTOOLIZE=glibtoolize\n  echo using glibtoolize \nelse \n  LIBTOOLIZE=libtoolize\n  echo using libtoolize \nfi\n\naclocal \n# this produces a lot of benign but misleading output ... hide it and hope for\n# the best\nglib-gettextize --force --copy > /dev/null\ntest -r aclocal.m4 && chmod u+w aclocal.m4\nautoconf\nautoheader\n$LIBTOOLIZE --copy --force --automake\nautomake --add-missing --copy\n\n./configure $*\n"
  },
  {
    "path": "configure.ac",
    "content": "# Process this file with autoconf to produce a configure script.\n\nAC_INIT([nip2], [8.9.2], [vipsip@jiscmail.ac.uk])\n\n# foreign stops complaints about a missing README (we use README.md instead)\n# and missing INSTALL (the standard Gnu INSTALL is not very useful)\nAM_INIT_AUTOMAKE([-Wno-portability foreign])\n\nAC_CONFIG_HEADERS(config.h)\nAC_CONFIG_MACRO_DIR([m4])\n\ndnl\ndnl We do the version number components as m4 macros\ndnl so that we can base configure --help output off\ndnl of them.\ndnl\n\nm4_define([nip_major_version], [8])\nm4_define([nip_minor_version], [9])\nm4_define([nip_micro_version], [2])\nm4_define([nip_version],\n          [nip_major_version.nip_minor_version.nip_micro_version])\n\nMAJOR_VERSION=nip_major_version()\nMINOR_VERSION=nip_minor_version()\nMICRO_VERSION=nip_micro_version()\n\nAC_DEFINE_UNQUOTED(MAJOR_VERSION, $MAJOR_VERSION, [Major version number])\nAC_DEFINE_UNQUOTED(MINOR_VERSION, $MINOR_VERSION, [Minor version number])\nAC_DEFINE_UNQUOTED(MICRO_VERSION, $MICRO_VERSION, [Micro version number])\n\nAC_CANONICAL_HOST\n\nAC_MSG_CHECKING([for native Win32])\ncase \"$host\" in\n  *-*-mingw*)\n    nip_os_win32=yes\n    ;;\n  *)\n    nip_os_win32=no\n    ;;\nesac\nAC_MSG_RESULT([$nip_os_win32])\n\nif test x\"$nip_os_win32\" = \"xyes\"; then\n  AC_DEFINE(OS_WIN32,1,[native win32])\n\n  # makes gcc use win native alignment\n  IP_CFLAGS=\"-mms-bitfields $IP_CFLAGS\"\nfi\n\n# src/Makeile.am uses this to add an icon to the .exe\nAM_CONDITIONAL(OS_WIN32, test x\"$nip_os_win32\" = \"xyes\")\n\nAC_MSG_CHECKING([for Mac OS X])\ncase \"$host\" in\n  *-*-darwin*)\n    nip_os_darwin=yes\n    ;;\n  *)\n    nip_os_darwin=no\n    ;;\nesac\nAC_MSG_RESULT([$nip_os_darwin])\nif test x\"$nip_os_darwin\" = \"xyes\"; then\n  AC_DEFINE(OS_DARWIN,1,[native Mac OS X])\nfi\n\nAC_ARG_ENABLE(debug,\n  AC_HELP_STRING([--enable-debug=@<:@no/minimum/yes@:>@],\n    [turn on debugging @<:@default=debug_default()@:>@]),,\n  enable_debug=no)\n\nif test \"x$enable_debug\" = \"xyes\"; then\n  NIP_DEBUG_FLAGS=\"-DDEBUG_FATAL -DDEBUG_LEAK\"\nelse\n  NIP_DEBUG_FLAGS=\"-DG_DISABLE_CAST_CHECKS\"\n\n  if test \"x$enable_debug\" = \"xno\"; then\n    NIP_DEBUG_FLAGS=\"$GLIB_DEBUG_FLAGS -DG_DISABLE_ASSERT -DG_DISABLE_CHECKS\"\n  fi\nfi\n\nIP_CFLAGS=\"$NIP_DEBUG_FLAGS $IP_CFLAGS\"\n\n# we want largefile support, if possible\nAC_SYS_LARGEFILE\n\n# Checks for programs.\nAC_PROG_AWK\nAC_PROG_CC\nAM_PROG_CC_C_O\nAC_PROG_LEX\n# we must have flex or lex\nif test x\"$LEX\" = x:; then \n  AC_MSG_ERROR([lex/flex not found: $PACKAGE requires one of these])\nfi\nIP_LIBS=\"$IP_LIBS $LEXLIB\"\nAC_PROG_INSTALL\nAC_PROG_LN_S\nAC_CHECK_TOOL(WINDRES, windres)\nAC_CHECK_TOOL(DLLWRAP, dllwrap)\nAC_CHECK_TOOL(DLLTOOL, dlltool)\nAC_CHECK_TOOL(OBJDUMP, objdump)\nAC_CHECK_TOOL(RANLIB, ranlib)\nAC_CHECK_TOOL(STRIP, strip)\nAC_CHECK_TOOL(BISON, bison)\n# we have to have bison :-( maybe we could ship the generated .c/.h files? not\n# clear on their portability\nif test x\"$BISON\" = x; then \n  AC_MSG_ERROR([bison not found: $PACKAGE uses bison-only features])\nfi\nAC_CHECK_TOOL(AR, ar)\nAC_CHECK_TOOL(AS, as)\nAC_CHECK_TOOL(LD, ld)\nAC_LIBTOOL_WIN32_DLL\nAC_PROG_LIBTOOL\n\n# dmalloc option\nAM_WITH_DMALLOC\n\n# i18n\nGETTEXT_PACKAGE=nip2\nAC_SUBST(GETTEXT_PACKAGE)\nAC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, \"$GETTEXT_PACKAGE\",\n\t[The prefix for our gettext translation domains.])\n# ALL_LINGUAS=\"en_GB malkovich\"\nALL_LINGUAS=\"en_GB\"\nAM_GLIB_GNU_GETTEXT\n\n# check for flex ... nip needs to adjust itself a bit\nif test \"${LEX}\" = \"flex\"; then\n  AC_DEFINE(HAVE_FLEX,1,[using flex, rather than lex])\nfi\n\n# flex >= 2.5.36 uses a nonstandard type for yyleng\nAC_MSG_CHECKING([whether yyleng is yy_size_t])\ncat > conftest.l <<EOF\n%%\n%%\nyy_size_t yyleng;\nEOF\n$LEX conftest.l\nAC_COMPILE_IFELSE([AC_LANG_DEFINES_PROVIDED [`cat $LEX_OUTPUT_ROOT.c`]], [\n  AC_MSG_RESULT(yes)\n  AC_DEFINE(YYLENG_IS_YY_SIZE_T,1,\n    [Define to 1 if lex declares yyleng to be yy_size_t.])\n], [\n  AC_MSG_RESULT(no)\n])\nrm -f conftest.l $LEX_OUTPUT_ROOT.c\n\n# get packages we need\n# gtk before 2.4.9 crashes with the way we use combobox :-(\n# vips before 7.30 used \"vips-x.y\" as the pkg name\nPKG_CHECK_MODULES(REQUIRED_PACKAGES, \n  gmodule-2.0 gthread-2.0 gtk+-2.0 >= 2.4.9 libxml-2.0 vips >= 7.30)\nIP_CFLAGS=\"$REQUIRED_PACKAGES_CFLAGS $IP_CFLAGS\"\nIP_LIBS=\"$REQUIRED_PACKAGES_LIBS $IP_LIBS\"\n\n# gdk_window_set_opacity() was added in gtk 2.12\nPKG_CHECK_EXISTS(gtk+-2.0 >= 2.12,\n  [nip_set_opacity=yes],\n  [nip_set_opacity=no]\n)\n\nif test x\"$nip_set_opacity\" = x\"yes\"; then\n  AC_DEFINE(HAVE_SET_OPACITY,1,[define if you have gdk_window_set_opacity()])\nfi\n\n# GtkInfoBar was added in gtk 2.18\nPKG_CHECK_EXISTS(gtk+-2.0 >= 2.18,\n  [nip_use_infobar=yes],\n  [nip_use_infobar=no]\n)\n\nif test x\"$nip_use_infobar\" = x\"yes\"; then\n  AC_DEFINE(USE_INFOBAR,1,[define if you have GtkInfoBar])\nfi\n\n# notebook action widgets came in 2.20\nPKG_CHECK_EXISTS(gtk+-2.0 >= 2.20,\n  [nip_use_notebook_action=yes],\n  [nip_use_notebook_action=no]\n)\n\nif test x\"$nip_use_notebook_action\" = x\"yes\"; then\n  AC_DEFINE(USE_NOTEBOOK_ACTION,1,[define if you have gtk_notebook_set_action_widget()])\nfi\n\n# notebook group names widgets came in 2.24\nPKG_CHECK_EXISTS(gtk+-2.0 >= 2.24,\n  [nip_use_notebook_group_name=yes],\n  [nip_use_notebook_group_name=no]\n)\n\nif test x\"$nip_use_notebook_group_name\" = x\"yes\"; then\n  AC_DEFINE(USE_NOTEBOOK_GROUP_NAME,1,[define if you have gtk_notebook_set_group_name()])\nfi\n\n# GRegex was added in glib-2.14\n# we need it for regex searching in the program window\nPKG_CHECK_EXISTS(glib-2.0 >= 2.14,\n  [nip_use_gregex=yes],\n  [nip_use_gregex=no]\n)\n\nif test x\"$nip_use_gregex\" = x\"yes\"; then\n  AC_DEFINE(HAVE_GREGEX,1,[define if you have GRegex])\nfi\n\n# Check for the function strccpy in libgen\nAC_CHECK_HEADER(libgen.h, \n  AC_CHECK_LIB(gen, strccpy, \n    AC_DEFINE(HAVE_STRCCPY,1,[have strccpy() in -lgen]) \n    IP_LIBS=\"$IP_LIBS -lgen\" \n  ), \n)\n\n# Checks for header files.\nAC_HEADER_DIRENT\nAC_HEADER_STDC\nAC_HEADER_SYS_WAIT\nAC_CHECK_HEADERS(limits.h pwd.h fnmatch.h sys/statvfs.h sys/vfs.h sys/mount.h sys/resource.h sys/wait.h malloc.h sys/time.h sys/param.h unistd.h)\n\n# Checks for typedefs, structures, and compiler characteristics.\nAC_C_CONST\nAC_STRUCT_TM\n\n# Checks for library functions.\nAC_FUNC_ALLOCA\nAC_FUNC_FNMATCH\nAC_FUNC_VPRINTF\nAC_CHECK_FUNCS(geteuid getcwd getpwnam getrlimit getpwent getwd putenv regcomp strcspn strspn strstr)\n\n# need fftw so we load and unload wisdom on startup/shutdown\nAC_ARG_WITH([fftw3], AS_HELP_STRING([--without-fftw3], [build without fftw3 (default: test)]))\n\nif test \"x$with_fftw3\" != \"xno\"; then\n  PKG_CHECK_MODULES(FFTW3, fftw3,\n    [AC_DEFINE(HAVE_FFTW3,1,[define if you have fftw3 installed.])\n     with_fftw3=yes\n    ],\n    [AC_MSG_WARN([fftw3 not found; disabling fftw support])\n     with_fftw3=no\n    ])\n  IP_CFLAGS=\"$FFTW3_INCLUDES $FFTW3_CFLAGS $IP_CFLAGS\"\n  IP_LIBS=\"$FFTW3_LIBS $IP_LIBS\"\nfi\n\n# goffice needs libgsf to save plots to files\nAC_ARG_WITH([libgsf], AS_HELP_STRING([--without-libgsf], [build without libgsf (default: test)]))\n\nif test \"x$with_libgsf\" != \"xno\"; then\n  PKG_CHECK_MODULES(LIBGSF, libgsf-1,\n    [AC_DEFINE(HAVE_LIBGSF,1,[define if you have libgsf installed.])\n     with_libgsf=yes\n    ],\n    [AC_MSG_WARN([libgsf not found; disabling save plot to file])\n     with_libgsf=no\n    ])\n  IP_CFLAGS=\"$LIBGSF_CFLAGS $LIBGSF_INCLUDES $IP_CFLAGS\"\n  IP_LIBS=\"$LIBGSF_LIBS $IP_LIBS\"\nfi\n\n# optional ... use libgoffice to draw plots\n# pretty basic functionality, really, but we need to be able to build without\n# it for testing\nAC_ARG_WITH([libgoffice], AS_HELP_STRING([--without-libgoffice], [build without libgoffice (default: test)]))\n\nif test \"x$with_libgoffice\" != \"xno\"; then\n  PKG_CHECK_MODULES(LIBGOFFICE, libgoffice-0.8,\n    [AC_DEFINE(HAVE_LIBGOFFICE,1,[define if you have libgoffice installed.])\n     with_libgoffice=yes\n    ],\n    [AC_MSG_WARN([libgoffice not found; disabling plot display])\n     with_libgoffice=no\n    ])\n  IP_CFLAGS=\"$LIBGOFFICE_CFLAGS $LIBGOFFICE_INCLUDES $IP_CFLAGS\"\n  IP_LIBS=\"$LIBGOFFICE_LIBS $IP_LIBS\"\nfi\n\n# optional ... use libgvc to draw graphs of workspace dependencies\nAC_ARG_WITH([libgvc], AS_HELP_STRING([--without-libgvc], [build without libgvc (default: test)]))\n\n# gvc 2.30 is broken in a number of ways and we can't use it, see for example\n# http://lists.research.att.com/pipermail/graphviz-devel/2012/001544.html\n\nif test \"x$with_libgvc\" != \"xno\"; then\n  PKG_CHECK_MODULES(LIBGVC, libgvc > 2.30,\n    [AC_DEFINE(HAVE_LIBGVC,1,[define if you have libgvc installed.])\n     with_libgvc=yes\n    ],\n    [AC_MSG_WARN([libgvc not found; disabling workspace dep graph display])\n     with_libgvc=no\n    ])\n  IP_CFLAGS=\"$LIBGVC_CFLAGS $LIBGVC_INCLUDES $IP_CFLAGS\"\n  IP_LIBS=\"$LIBGVC_LIBS $IP_LIBS\"\nfi\n\n# optional ... we add some gsl funcs as builtins if available\nAC_ARG_WITH([gsl], AS_HELP_STRING([--without-gsl], [build without gsl (default: test)]))\n\nif test \"x$with_gsl\" != \"xno\"; then\n  PKG_CHECK_MODULES(GSL, gsl,\n    [AC_DEFINE(HAVE_GSL,1,[define if you have gsl installed.])\n     with_gsl=yes\n    ],\n    [AC_MSG_WARN([gsl not found; disabling extra numerical functions])\n     with_gsl=no\n    ])\n  IP_CFLAGS=\"$GSL_CFLAGS $GSL_INCLUDES $IP_CFLAGS\"\n  IP_LIBS=\"$GSL_LIBS $IP_LIBS\"\nfi\n\n# optional ... use this to open the help browser, if available\nAC_PATH_PROG(XDG_OPEN, xdg-open, no)\n\nif test \"x$XDG_OPEN\" != \"xno\"; then\n  AC_DEFINE(HAVE_XDG_OPEN,1,[define if you have xdg-open])\n  AC_DEFINE_UNQUOTED(XDG_OPEN, \"$XDG_OPEN\", [path of xdg-open binary])\nfi\n\n# optional ... use these to update desktop after install\nAC_PATH_PROG(UPDATE_MIME_DATABASE, update-mime-database, no)\nAC_PATH_PROG(UPDATE_DESKTOP_DATABASE, update-desktop-database, no)\n\nnip_desktop_update=no\nif test \"x$UPDATE_MIME_DATABASE\" != \"xno\"; then\n  if test \"x$UPDATE_DESKTOP_DATABASE\" != \"xno\"; then\n    nip_desktop_update=yes\n  fi\nfi\n\n# stop the DBs being updated: useful for packagers\nAC_ARG_ENABLE(update-desktop,\n  AC_HELP_STRING([--disable-update-desktop],\n    [disable update of desktop database]),\n  [nip_desktop_update=$enableval],)\n\nif test x\"$nip_desktop_update\" = \"xyes\"; then\n  AM_CONDITIONAL(UPDATE_DESKTOP, true)\nelse\n  AM_CONDITIONAL(UPDATE_DESKTOP, false)\nfi\n\n# we always need -lm\nIP_LIBS=\"$IP_LIBS -lm\"\n\nAC_SUBST(IP_CFLAGS)\nAC_SUBST(IP_LIBS)\n\n# needed by test/test_all.sh\n# :( what's a better way to do this, argh\nTOP_SRCDIR=$ac_pwd\nAC_SUBST(TOP_SRCDIR)\n\nAC_OUTPUT([\n\tnip2.desktop\n\tMakefile\n\tman/Makefile\n\tman/man1/Makefile\n\tshare/Makefile\n\tshare/nip2/Makefile\n\tshare/nip2/data/Makefile\n\tshare/nip2/rc/Makefile\n\tshare/nip2/start/Makefile\n\tshare/nip2/compat/Makefile\n\tshare/nip2/compat/7.8/Makefile\n\tshare/nip2/compat/7.9/Makefile\n\tshare/nip2/compat/7.10/Makefile\n\tshare/nip2/compat/7.12/Makefile\n\tshare/nip2/compat/7.14/Makefile\n\tshare/nip2/compat/7.16/Makefile\n\tshare/nip2/compat/7.24/Makefile\n\tshare/nip2/compat/7.26/Makefile\n\tshare/nip2/compat/7.28/Makefile\n\tshare/nip2/compat/7.38/Makefile\n\tshare/nip2/compat/7.40/Makefile\n\tshare/nip2/compat/8.2/Makefile\n\tshare/nip2/compat/8.3/Makefile\n\tshare/nip2/compat/8.4/Makefile\n\tshare/nip2/compat/8.5/Makefile\n\tshare/nip2/compat/8.6/Makefile\n\tsrc/BITMAPS/Makefile \n\tsrc/Makefile\n\ttest/Makefile\n\ttest/test_all.sh\n\tpo/Makefile.in\n\tnip2.spec\n])\n\n# generated script needs to be executable\nchmod +x test/test_all.sh\n\nAC_MSG_RESULT([\n* general build options\nnative win32:\t\t\t\t$nip_os_win32\nnative os x:\t\t\t\t$nip_os_darwin\nupdate desktop after install: \t\t$nip_desktop_update\ndebug: \t\t\t\t\t$enable_debug\n\n* optional packages and modules\nuse fftw3 for FFT: \t\t\t$with_fftw3\nuse gsl for numeric functions:\t\t$with_gsl\nuse libgoffice to show plots:\t\t$with_libgoffice\nuse libgsf to save plots to files:\t$with_libgsf\nuse libgvc to show ws dep graphs:\t$with_libgvc\n  (requires gvc > 2.30)\nuse gtkinfobar to show messages:\t$nip_use_infobar\n  (requires gtk+-2.0 >= 2.18)\nuse notebook action widget:  \t\t$nip_use_notebook_action\n  (requires gtk+-2.0 >= 2.20)\nuse notebook group name:  \t\t$nip_use_notebook_group_name\n  (requires gtk+-2.0 >= 2.24)\nallow regex searches: \t\t\t$nip_use_gregex\n  (requires glib-2.0 >= 2.14)\ndisplay help files with xdg:\t\t$XDG_OPEN\n])\n"
  },
  {
    "path": "doc/README",
    "content": "nip documentation\n\nType \"make install\" to rebuild html/ and ps/ directories with formatted\ndocuimentation. You'll need latex and tex4ht.\n\nThe Makefile.am in nip2-x.x copies the contents of the html/ and ps/ to \n$prefix/share/doc/nip2 during the main nip2 install process.\n\nOnce you have the docs installed, rebuild nip2's help index with:\n\n  cd nip2-x.x/src\n  make helpindex.h\n\nto index the HTML docs and link the HELP buttons in nip to the correct place\nin the formatted pages. \n"
  },
  {
    "path": "doc/doc-programmer/hierarchy.txt",
    "content": "class hierarchy\n===============\n\nGObject \n|\n+-iObject\n  |\n  +-Heap\n  +-Imagemodel\n  +-Toolviewitemgroup\n  +-iContainer\n    |\n    +-Compile\n    +-Expr\n    +-Imageinfo\n    +-Watch\n    +-Model\n      |\n      +-Conversion\n      +-Toolkitgroup\n      +-Workspacegroup\n      +-Filemodel\n      | |\n      | +-Tool\n      | +-Toolkit\n      | +-Column\n      | +-Symbol\n      |   |\n      |   +-Workspace\n      |\n      +-Heapmodel\n        |\n        +-Rhs\n        +-Subcolumn\n        +-iText\n        +-Row\n        +-Classmodel\n          |\n          +-Slider\n          +-Patch\n          +-Filename\n          +-Fontname\n          +-Expression\n          +-Number\n          +-Matrix\n          +-String\n          +-Option\n          +-Toggle\n          +-iRegiongroup\n          +-iArrow\n          +-iImage\n            |\n            +-iRegion\n \n\n\nGtkVBox\n\n  View\n\n    Textview\n    Workspacegroupview\n    Workspaceview\n    Toolkitgroupview\n    Toolkitview\n    Toolview\n\n    Graphicview\n\n      Toggleview\n      Sliderview\n      Patchview\n      Filenameview\n      Fontnameview\n      Optionview\n      iArrowview\n      Matrixview\n      Regionview\n      iImageview\n\n        iRegionview\n\n      Editview\n\n        Stringview\n\tNumberview\n\tExpressionview\n\n    Rhsview\n    Rowview\n    Subcolumnview\n    Spin\n    Columnview\n\n    iRegiongroupview\n\n  Imagepresent\n  \nGtkFrame\n\n  Conversionview\n  Statusview\n\nGtkDrawingArea\n\n  Imagedisplay\n\nGtkWindow\n\n  iWindow\n\n    Imageview\n    Program\n    Trace\n\n    iDialog\n\n      Namecaption\n      Find\n      Imageheader\n      Browse\n      Filesel\n\nGtkEventBox\n\n  Formula\n"
  },
  {
    "path": "doc/doc-programmer/imageview",
    "content": "imagemodel is the base model class ... imageview_new makes the imagemodel, then\nall the component widgets (imagepresent, statusview, paintboxview,\nconversionview, imageview) watch this for updates\n\nthe conversion from the real image to the display image is handled by\nconversion, a sub-model of imagemodel\n\nimageview holds the ref to imagemodel ... destroy this and everything goes\n"
  },
  {
    "path": "doc/doc-programmer/makeindex.pl",
    "content": "#!/usr/bin/perl\n\n# my labels = `grep '<A NAME=\"nip_label_' $VIPSHOME/share/doc/nip/html/*.html`;\nmy lab = `grep bel html`;\n\n# print $labels;\n\n\n"
  },
  {
    "path": "doc/doc-programmer/menu.txt",
    "content": "nip menu organisation\n\nhere's how it's currently arranged, all ideas for new arrangements welcome\n\nyou can change the name of any item, move between menus etc.\n\nonce we pick an arrangement, we're stuck with it forever :-(\n\ntop level menus are always sorted alphabetically, within each menu, you can\nhave any order you like\n\nI was thinking (for example) maybe there should be a \"Capture\" menu: we could\nput all the stuff you tend to do when acquiring images in there (eg. crop,\nwhite balance, New_video, etc.)\n\nArithmetic\n  Add\n  Subtract\n  Multiply\n  Divide\n  Remainder\n  -------\n  Absolute_value\n  Absolute_value_vector\t\tlike abs, but treat pixels as vectors\n  Sign\t\t\t\tunit vector in direction of value\n  Negate\t\t\tvalue * -1\n  Photographic_negative\t\t255 - value (255 == max value for type)\n\nBoolean\n  And\n  Or\n  Eor\n  Not\n  -------\n  Left_shift\t\t\tbitwise left/right shift\n  Right_shift\n  -------\n  If_then_else\n  Band_and\t\t\tand the bands of an image together\n  Band_or\t\t\tor the bands of an image together\n\nColour\n  Mono_to\n    Mono \n    XYZ \n    Yxy \n    Lab \n    LCh \n    UCS \n    RGB \n    sRGB \n    LabQ \n    LabS \n    Falsecolour \n  XYZ_to \n    Mono \n    XYZ \n    Yxy \n    Lab \n    LCh \n    UCS \n    RGB \n    sRGB \n    LabQ \n    LabS \n  etc. etc. ... every combination of the 10 colour spaces\n  -------\n  Recombination \t\tlinear recombination with editable matrix\n  -------\n  dE_ \t\t\t\tcalculate colour difference between two objects\n    CIELAB \n    UCS \n  -------\n  Tint_mono_image \t\tapply coloured tint to mono image\n  Colour_chart_from_matrix \tmake a synthetic colour chart from a matrix\n  Colour_from_image \t\tmake a colour from the average colour in image\n  Image_from_colour  \t\tmake a patch of pixels from a colour\t\t\n  Similar_colour \t\tfind similar colours\n\nComplex\n  Complex_extract \n    Real \t\t\textract real part of complex\n    Imaginary \t\t\textract imaginary part of complex\n  Complex_build \t\tcombine two reals to make a complex\n  -------\n  Polar \t\t\trectangular to (amplitude, phase)\n  Rectangular \t\t\tpolar to rectangular\n\nConvert\n  Decompose \t\t\tbreak up compound object \n  Compose \t\t\tcombine small objects to make a bigger one\n  -------\n  Cast_to \n    unsigned_8bit \t\tconvert numeric types\n    signed_8bit \n    unsigned_16bit \n    signed_16bit \n    unsigned_32bit \n    signed_32bit \n    float_32bit \n    float_64bit \n    complex_64bit \n    complex_128bit \n  Ceil \t\t\t\tround up\n  Floor \t\t\tround down\n  Rint \t\t\t\tround nearest\n  Scale_to_byte \t\t\n  -------\n  Convert_to_matrix \t\ttry to make a matrix from an object\n  Convert_to_image \t\ttry to make an image from a thing\n  -------\n  Falsecolour \n\nFilter\n  Blur \n  Sharpen \n  Median \n  Laplacian \n  Sobel \n  Linedet \n  Emboss \n  -------\n  Custom_rank \t\t\trank filter with editable params\n  Custom_convolution \t\tconvolution filter with editable params\n\nFourier\n  Fourier_transform \n  Fourier_inverse \n  -------\n  Ideal_fourier_filter \n    High_low \n    Ring \n    Band \n  Gaussian_fourier_filter \n    High_low \n    Ring \n    Band \n  Butterworth_fourier_filter \n    High_low \n    Ring \n    Band \n\nHistogram\n  Hist_find \n  Hist_map \n  Hist_cumulative \n  Hist_normalise \n  Hist_match \n  -------\n  Hist_equalise \n    Global \n    Local \n  Guide_slice \t\t\tgraph pixel values along a guide\n\nImage\n  Copy \n  -------\n  Adjust_scale_offset \n  Adjust_gamma \n  Custom_sharpen \n  White_balance \n  Light_correct_white_image \n  Smooth_image \n  Drop_shadow \n\nJoin\n  Abut\n    Left_right\n    Top_bottom\n  Crop\n\nList\n  Head \n  Tail \n  Init \n  Last \n  -------\n  Reverse \n  Sort \n  Make_set \n  Transpose_list \n  Concat \n  -------\n  Length \n  Subscript \n  Take \n  Drop \n  -------\n  Join \n  Cons \n  Zip \n\nLog\n  Exponential \n  Log_natural \n  -------\n  Log10 \n  Exponential10 \n  -------\n  Raise_to_power \n\nMorphology\n  Dilate8 \n  Dilate4 \n  Erode8 \n  Erode4 \n  -------\n  Open \n  Close \n  Clean \n  Thin \n  -------\n  Dilate \n  Erode \n  Dilate_multiple \n  Erode_multiple \n  -------\n  Custom_morphology \n  Find_profile \t\t\tsearch an image for edge profiles\n\nMosaic\n  Mosaic_translate \t\tthe two-point funcs\n    Left_right \n    Top_bottom \n  Mosaic_affine \t\tthe four-point funcs\n    Left_right \n    Top_bottom \n  -------\n  Mosaic_balance \n  Tilt_brightness \n    Left_right \t\t\n    Top_bottom \n  -------\n  Mosaic_rebuild \t\trebuild mosaic with different files\n\nNew\n  New_slider \n  New_toggle\n  New_option \n  New_matrix \n    Convolution \n    Recombination \n    Morphology \n  New_image \n  New_colour\n  New_video \t\t\tjust linux video at the moment\n  -------\n  New_eye \n  New_zone_plate \n  New_grey \n  New_xy \n  New_gauss_noise \n  New_fractal \n  New_CRT_test_chart \n  New_frequency_test_chart \n  New_checkerboard \n  New_grid \n  New_ideal \n    High_low \t\t\tthis set of items make fourier filter masks\n    Ring \n    Band \n  New_gaussian \n    High_low \n    Ring \n    Band \n  New_butterworth \n    High_low \n    Ring \n    Band \n  -------\n  New_CIELAB_slice \t\tslice through cielab\n  New_LAB_colour\t\tpick a colour with a poiont on a LAB slice\n\nPlot\n  Plot_scatter\t\t\t\n\nPrint\n  ICC_export \t\t\tPCS -> device\n  ICC_import \t\t\tdevice -> PCS\n  ICC_transform \t\tdevice -> device\n  ICC_ac2rc \n  -------\n  D65XYZ_to \t\t\tchange white point for measure/print\n    D50XYZ \n  D50XYZ_to \n    D65XYZ \n  D50XYZ_to \n    Lab \n  D50Lab_to \n    XYZ \n  -------\n  Sharpen_for_print \n  Morph_for_print \n\nRelational\n  Equal \n  Not_equal \n  More \n  Less \n  More_equal \n  Less_equal \n\nResize\n  Resize_image\t\t\tchange size by a scale factor\n  Resize_xy_image\t\tseparate xy scale factors\n  Resize_canvas\n  -------\n  Shrink_to\n    Quicklook\t\t\tshrink to smallest axis == 64 pixels\n    Icon\t\t\tshrink to smallest axis == 400 pixels\n\nRotate\n  Rotate_fixed \n    r90 \n    r180 \n    r270 \n    r45 \n  Rotate_free \t\t\trotate with a slider\n  -------\n  Flip \n    up_down \n    left_right \n  Transpose \n  -------\n  Straighten_arrow \t\trotate to get an arrow straight\n\nStatistics\n  Mean \n  Deviation \n  Stats \n  -------\n  Max \n  Min \n  Maxmin \n  Maximum_position \n  Minimum_position \n  -------\n  Count_set \n  Count_clear \n  -------\n  Measure_colour_chart \n  Statistical_difference \tmore of a filter really :-(\n  Count_lines \n\nTrig\n  Sin \n  Cos \n  Tan \n  -------\n  Asin \n  Acos \n  Atan \n  -------\n  Rad \n  Deg \n  -------\n  Angle_range \t\t\tis angle within arc ... clock arithmetic\n\n"
  },
  {
    "path": "doc/doc-programmer/regionview",
    "content": "how regionviews are built and maintained\n\n\n\niregion\t\t\t\tiregionview\n  end of parent_add, make\n  iregiongroup child\n\niregiongroup\t\t\tiregiongroupview\n  monitor object updates,\t  on iregiongroupview_refresh() create and \n  set and unset model->display\t  destroy regionview ... watches iregion model\n\n\nregionview_new( iregion, area, imagepresent )\n  does not view_link(), since it's not a true view ... adds own signal \n  handlers for \"changed\" and \"destroy\" on iregion/iarrow\n\n\n\n"
  },
  {
    "path": "doc/src/Example.def",
    "content": "/* Gamma im gam: correct\n */\n\nGamma A1 B7 \n      =\terror \"arg 1 is not image\", not is_image A1;\n      =\terror \"arg 2 is not number\", not is_number B7;\n      =\tConvert_to_unsigned_char B5\n{\n\tB4 = A1 ^ (1/B7);\n\tB5 = B4 * (255 / 255 ^ (1/B7));\n};\n\n"
  },
  {
    "path": "doc/src/html.cfg",
    "content": "% configuration file for output of nipguide as html\n\\Preamble{html} \n\\begin{document} \n\n% stop the mono font shrinkage we do for paper output\n\\renewenvironment{ctd}{\\begin{quote}\\tt}{\\end{quote}}\n\n% make a label\n% in html, write an extra label which we can link to nip's help system\n\\renewcommand{\\mylabel}[1]{\n\t\\label{#1}\n\t\\HCode{<a name=\"nip_label_#1\"></a>}\n}\n\n% supress \" on page xx\" if we're making HTML\n\\renewcommand{\\onpage}[1]{}\n\\EndPreamble\n"
  },
  {
    "path": "doc/src/infrared.tex",
    "content": "\\chapter{Assembling infrared mosaics}\n\\mylabel{sec:ir}\n\nVIPS has a package of functions designed to help join many small images\ntogether to make a single large image. They were originally designed to\nassemble infrared reflectograms but are general enough to be useful for\nother sorts of image as well, such as X-rays.\n\nThis chapter first introduces the mechanics of infrared imaging then\nexplains how to use \\nip{} to assemble the images you grab. Finally, it\nsuggests some printing techniques.\n\n\\section{Infrared imaging}\n\nMost museums use tube cameras (usually called Vidicons) for infrared\nimaging. Although they are relatively cheap they are not very stable\nand they suffer from (sometimes quite severe) geometric distortions.\nMore modern solid-state cameras are still expensive but are becoming\nmore widely used because of their greater stability. This\nguide assumes you are using a tube camera but almost all of it applies to\nsolid-state cameras as well.\n\nWhatever your camera there are three main sources of error which have to be\naddressed in order to be able to make successful mosaics:\n\n\\begin{enumerate}\n\n\\item\nTube cameras suffer very badly from distortions in the image, usually either\n`pin-cushioning' or `barrelling'. These distortions result in alignment\nerrors when sub-images are joined together.\n\n\\item\nThe sensitivity of the tube varies across its surface, causing some parts of\neach sub-image to be brighter than others. This is made worse by unavoidable\nvariations in illumination. When a lot of such images are joined together the\nresult is a `brick wall' effect.\n\n\\item\nThe sensitivity of the tube also varies between sub-images, partly as\nthe overall lightness in the field of view changes, and also because the\nelectronics in the camera change as the camera heats up. This leads to a\npatchy, unbalanced mosaic.\n\n\\end{enumerate}\n\nThe first two problems will be different in each Vidicon and will change\neach time a tube is replaced. All three problems need to be addressed to\ncreate successful infrared reflectogram mosaics.\n\n\\subsection{Setting up your system}\n\n\\subsubsection{Mechanical set-up} \n\nIt is vital that the optical axis of the Vidicon is at right-angles to the\npicture plane and that, whether it is the Vidicon or the painting that moves\nduring image capture, it remains perpendicular. Obviously, with a seriously\nwarped panel, this may not be possible. The lighting should be carefully\nadjusted so that the area of interest is lit as evenly as possible. If you\ncan, arrange for the lights to remain stationary with respect to the camera.\n\nAn easy way to test camera alignment is to image a piece of graph paper,\nmove the camera (either left-right or up-down) by 90\\% of the field of view,\nand see how features in the overlap area move.  First rotate the centre\naround the optical axis to get the centre line of the images lined up. Next\ncheck the corners and adjust camera pitch and yaw.\n\n\\subsubsection{Video set-up} \n\\mylabel{sec:vidpref}\n\nOn Linux, you can capture video directly into \\nip{} provided that your\ncapture card is compatible with v4l. You may need to adjust the \\nip{}\nvideo settings.  These settings can be found under the headings \\ct{Video\nfor linux} and \\ct{General video capture} in the \\ct{Preferences} window,\nwhich can be accessed by selecting \\ctr{Edit}\\ct{Preferences} from the main\n\\nip{} window.  The default settings, see \\fref{fg:vidpref}, are for the\nHauppauge PCI capture card and should be changed as required.\n\n\\begin{fig2}\n\\figw{3in}{scr21a.png}\n\\caption{Recommended video preference settings}\n\\mylabel{fg:vidpref}\n\\end{fig2}\n\nOnce you have set up your card, select \\ctr{Tasks}\\ctr{Capture}\\ct{Capture\nVideo Frame} to create a new video object, which will appear as a still\nimage in your current selected column.  The captured image can be updated by\nopening the image in a viewing window and then pressing Ctrl-C (a shortcut\nfor \\ctr{File}\\ct{Recalculate Image}).\n\nYou can create more than one video object: this can help you to get the\noverlaps right if you have two open at once (one showing the previous grab)\nwhen you are moving the camera around.\n\n\\subsubsection{Setting the crop and aspect}\n\nWhile it is possible to correct geometric distortions after the image is\ncaptured, it is difficult to do the necessary modelling accurately and\nreliably. Instead, we suggest the grabbed images should simply be cropped,\nsince the most severe distortion affects the perimeter of each video image.\n\nTo determine the area to crop, set up the Vidicon as it would be set to\nimage a painting and capture an image of a rectangular grid --- a piece of\ngraph paper works well as a target.  Before capturing the grid, check the\ncurrent video crop settings in the \\ct{Preferences} window\nand ensure that the crop is set at maximum: left 0, top 0, width 768,\nheight 576 (these are the dimensions for a PAL signal, they may be different\non your system). Also set the \\ct{Aspect ratio} line to 1.\n\nCreate a new video object and look for the largest rectangle with little\ndistortion (no more than a few pixels). If you create a region on the video\nimage (by holding down the Ctrl key and dragging down and right with\nthe left mouse button, see \\pref{sec:region}) you can compare the straight\nedges of the region against the distorted lines of the grid. You can then\nexpand and contract the region until you decide on the optimum area. The\nsettings you need for the crop box can be taken from the values contained\nwithin the region object, which can be viewed by left-clicking several\ntimes on the down arrow to the left of the region object name.\n\nFinally, you can set an aspect ratio: \\nip{} will automatically stretch\nvideo frames vertically by this factor. You can measure the aspect ratio of\nyour capture card by taking a picture of something you know to be square and\ndividing the width in pixels by the height in pixels.\n\nMove back to the \\ct{Preferences} window and enter the crop values in the\n\\ct{General video capture} section.  Next time you create a new video object,\nyou should find that it is cropped to the appropriate area.  The settings\nyou enter in the \\ctr{Preferences} window will be saved and automatically\nloaded again next time you start \\nip{}. See appendix~\\ref{sec:config}.\n\nChoosing the usable area of the image is a matter of compromise --- the\nsmaller the area, the more images are required to build a mosaic of a\nparticular painting. If the area chosen is too large then the amount of\ndistortion can cause serious errors in the final mosaic.\n\nIt's possible to use the VIPS rubber sheet plug in to detect and correct\ngeometric distortion in your images automatically. This lets you use the\nfull area of the sensor. It is a bit fiddly, but see the rubber sheet\ndocumentation if you are determined.\n\n\\subsection{Capturing the data}\n\n\\subsubsection{Setting the gain and offset}\n\nOnce everything is correctly set up, position the painting in front of the\ncamera and experiment with the gain and offset settings on the Vidicon to\nachieve the optimum infrared image on the computer screen. Note that the\nappearance of the image on the computer will normally be different to its\nappearance on the video monitor connected directly to the camera.\n\nRepeat this process at different points across the whole area to be captured.\nAlthough it is not always possible, the aim is to find a setting that does\nnot need altering much during the capture of the data. This seems to lead\nto more successful mosaics.\n\n\\subsubsection{Grey card correction}\n\nTo counteract the problem of uneven sensitivity across the target area of the\ntube, it is necessary to capture an image of a piece of grey card. This grey\ncard image is then used to correct all subsequent images. The card should be a\nflat, even grey, of around 50\\% reflectance. The Vidicon and lighting\npositions with respect to the painting should not be changed between the\nimaging of the grey card and the capturing of the mosaic. A grey card can be\ncaptured at any time, but it is good practice to start with one --- you may\nforget later.\n\nIf your mosaic will take several hours to capture, you may wish to grab extra\ngrey cards, since the sensitivity of the tube can change as it warms\nup. Be sure to note which data images correspond to which grey cards!\n\nIn association with the first grey card, it is a good idea to grab an image of\nyour grid to record the scale at which the data images are being made.\n\n\\subsubsection{Image capture}\n\\mylabel{sec:imcap}\n\nOpen a video window, \\ctr{Tasks}\\ctr{Capture}\\ct{Capture Video Frame},\nand when it shows the desired area, save the file. The choice of file name\nis a question of personal preference. We find it helpful to use a format\nthat indicates where in the mosaic the data comes from --- for example,\n\\ct{dat3.5.v} for the fifth image in row three.\n\nIt is helpful to be able to see the previous image to ensure that there is\nsufficient overlap. To achieve this, a second video window can be opened and\nplaced alongside and the images grabbed into alternate windows.\n\n\\subsubsection{Capture tips}\n\n\\begin{itemize}\n\n\\item\nMake a new directory for each painting, and keep all of the image files\nfor that painting (including a grey card and a grid) in that directory.\n\n\\item\nVIPS can join up images in any layout, but you will get much less confused\nwhen you assemble your images if you stick to a regular grid. This can be\ndifficult --- a good compromise is to keep one axis fixed and grab in rows\n(or columns).\n\n\\item\nYou can help to reduce mosaicing errors later if you keep your rows (or\ncolumns) as short as possible. So if the painting is in landscape format, grab\nin columns (or turn the painting on its side and grab in rows); if the\npainting is portrait, grab in rows (or turn the painting on its side and grab\nin columns).\n\n\\item\nThe semi-automatic mosaic functions (see \\pref{sec:mosaicing}) need a minimum\noverlap between the sub-images they join of around 20 pixels. For safety, you\nshould aim for a larger overlap than this: we recommend an overlap\nof 60 pixels (around 20mm, usually).\n\n\\item\nIf the overlap area is featureless, it is worth identifying a good tie-point\nand ensuring it is visible in both images, even if this means increasing the\noverlap for one of the joins.\n\n\\end{itemize}\n\n\\subsection{Correcting illumination}\n\\mylabel{sec:grey}\n\nBefore the mosaic can be assembled, the data images need to be corrected for\nnon-uniformity of illumination using the grey card image. This function can be\nperformed within \\nip{} or directly using a predefined VIPS command-line tool.\n\n\\subsection{Correcting with the command-line tool}\n\\mylabel{sec:linuxgrey}\n\nFirst, close \\nip{} and open a command line window, (xterm, mingw, etc). Move\nto the directory containing your image files with \\ct{cd}. For example, if you\nhave made a directory called \\ct{raphael} inside your home directory, type:\n\n\\begin{verbatim}\nprompt% cd raphael\n\\end{verbatim}\n\nThe program you need to use is called \\ct{light\\_correct}. You need to give\nit the name of the grey-card image and the names of all of the image files\nyou want it to correct with that gray card.  Suppose you have saved your\ngray card image as \\ct{grey.v}, and your painting image files are called\n\\ct{dat1.1.v} and \\ct{dat1.2.v}. You would then enter:\n\n\\begin{verbatim}\nprompt% light_correct grey.v dat1.1.v dat1.2.v\n\\end{verbatim}\n\nThe program will run and print messages explaining its progress. It creates\na new set of corrected image files, with the same names as before, but\nprefixed with \\ct{ic\\_}. In this example, it would create two new images files\ncalled \\ct{ic\\_dat1.1.v} and \\ct{ic\\_dat1.2.v}.\n\nIf there are a lot of image files to correct this could mean a lot of typing.\nFortunately, you can use wildcard characters to abbreviate lists of file\nnames. The example above can be abbreviated to:\n\n\\begin{verbatim}\nprompt% light_correct grey.v dat*.v\n\\end{verbatim}\n\n\\noindent\nThe \\ct{dat*.v} means `any filename which starts \\ct{dat} and ends with\n\\ct{.v}'. \n\nYou can use this technique to correct different parts of your mosaic\nwith different grey cards. If you have a file called \\ct{grey1.v} for the\nfirst row in your mosaic, and a file called \\ct{grey2.v} for the second, you\ncould do the correction in two parts:\n\n\\begin{verbatim}\nprompt% light_correct grey1.v dat1.*.v \\\\\nprompt% light_correct grey2.v dat2.*.v\n\\end{verbatim}\n\n\\subsection{Correcting within \\nip{}}\n\\mylabel{sec:wingrey}\n\nThe function within \\nip{} used to preform this correction is\n\\ctr{Tasks}\\ctr{Capture}\\ct{Flatfield}.  A set of images can be corrected\nat the same time by joining them together in a \\ct{Group}.  A group can\nbe produced by selecting all of the required images and then using the\n\\ctr{Edit}\\ct{Group} command.\n\nLoad all of your images into \\nip{}, and group all the image except the\ngrey image.  Select your grey image and then your new group and then run\nthe \\ctr{Tasks}\\ctr{Capture}\\ct{Flatfield} function.  This will produce\nyou a group of corrected images.  Right-click on this new group and select\n\\ct{Save As} from the menu.  In the save window type in a name, for example\n\\ct{fred\\_01.v} and then hit the save button.  All of the images in your group\nwill then be saved as \\ct{fred\\_01.v}, \\ct{fred\\_02.v}, \\ct{fred\\_03.v}\n\\ldots{} \\ct{fred\\_n.v}.\n\nIf you want to keep row numbers in your file names, (see \\pref{sec:imcap}),\nyou will need to correct your images one row at a time, saving each row as\n\\ct{fred01\\_01.v}, \\ct{fred02\\_01.v}, etc.\n\n\\section{Assembling the mosaic}\n\\mylabel{sec:mosaicing}\n\nThe tutorial has a section on mosaic assembly with \\nip{}: see \\pref{sec:irtut}.\n\nMosaic assembly is normally painless.  There are a few factors\nyou should bear in mind when you are deciding how to assemble an image\n(particularly a large image):\n\n\\begin{itemize}\n\n\\item\nYou can open up a mosaic join and change a few options, such as the blend\nwidth. If you want to change the defaults for a whole workspace, change the\n\\ct{Mosaic defaults} options in your \\ct{Preferences}.\n\n\\item\nIf two images just won't join correctly, try using \n\\ctr{Tasks}\\ctr{Mosaic}\\ctr{One Point}\\ct{Manual Left to\nRight} instead.  These functions operate in the same way as the usual\nmosaic functions, but do not do a search. \nThis is useful when the overlap is too small for the search\nto work correctly, or when the overlap area is very smooth and contains\ntoo few features for the search to find the exact overlap for you.\n\n\\item\n\\nip{} does not do sub-pixel interpolation. As a result, each join will on\naverage cause a positioning error of about 0.5 pixels, even if your input\nimages contain no geometric distortion. If there are distortions in your input\nimages (there usually are distortions in infrared images), then errors can be\nas much as 1--2 pixels per join. These errors accumulate as the number of\nimages you join becomes larger.\n\nIf you join a strip of 10 images together with\n\\ctr{Tasks}\\ctr{Mosaic}\\ctr{One Point}\\ct{Left to Right}, on average you\ncan expect a total error of about 5 pixels. If you join two strips like\nthis together top-bottom, you can therefore expect a mismatch of about 2.5\npixels at each end of the join.\n\nYou can minimise the effect of these errors if you assemble your images\ndifferently. Suppose you have a 10 by 10 mosaic to build.  Instead of making\nand joining 10 strips of 10 images each, make four 5 by 5 sub-mosaics (one for\neach quadrant) and then join these four quadrants together.  The errors will\nnow be more evenly spread over the image and therefore will be less visible.\n\n\\item\n\\mylabel{sec:pieces}\nSome operating systems limit the number of files a program can have open\nat once: this in turn limits the size of the mosaics you can assemble in\none go.  If you are having problems putting together very large mosaics, try\nbuilding your image in sections (\\ct{top}, \\ct{middle} and \\ct{bottom},\nperhaps), and later load up and join these larger pieces.\n\n\\end{itemize}\n\n\\section{Balancing the mosaic}\n\\mylabel{sec:balance}\n\nLike assembly, mosaic balancing is normally automatic and painless. You may\nsometimes have problems if the image is very large, or needs dramatic\ncorrections:\n\n\\begin{itemize}\n\n\\item\nEach VIPS image file has an associated history, recording the operations on\nthat image since it was loaded from a file. You can view an image's history\nby clicking on \\ctr{View}\\ct{Image header} in an image view window.\n\nThe automatic balancer uses the history to work out how you built your\nmosaic. The balancer knows about left-right and top-bottom joins, but nothing\nelse! If the history has other stuff recorded in there, you'll see\nunhelpful error messages like \\ct{unable to open tmp/xxx.v}, or \\ct{more\nthan one root}.\n\nIf you need to perform corrections to any of your sub-images, do them, save\nthe image, load it again, and then build the mosaic. This will make sure the\nhistory of the image you are trying to balance only contains mosaic\noperations.\n\n\\item\nOn some systems the balancer can run out of memory or out of file descriptors\non very large mosaics. If your mosaic is made up of more than a few hundred\nimages, and you are having balancing problems you may have hit one\nof these limits.\n\nThe solution (as with mosaic assembly) is to assemble and balance your mosaic\nin smaller pieces.\n\n\\item\nIf your grey-card correction is not accurate, you will find that the\nbalancer will magnify any problems you have. \n\nSuppose your lighting and camera set-up always produces images which are\nbrighter on the right than the left, and suppose, due to some problem with\nyour grey-card correction, this effect is not completely removed. You will\nfind that when you balance a mosaic, the small differences between left and\nright edges of your sub-images will have been smoothed out, but they will have\ncaused a large difference in brightness between the extreme left edge of your\nfinal image and the extreme right.\n\n\\nip{} includes several functions which can help to fix this problem, the\nmost commonly used being: \\ctr{Tasks}\\ctr{Mosaic}\\ctr{Tilt Brightness}\\ct{Left\nto Right} and \\ctr{Tasks}\\ctr{Mosaic}\\ctr{Tilt Brightness}\\ct{Top to Bottom}.\n\n\\end{itemize}\n\n\\section{Other \\nip{} features useful for reflectograms}\n\nYou can use \\nip{}'s general image processing facilities to play around with\nreflectogram mosaics. You can make false-colour images of your reflectograms,\nblend them with visible images or X-rays, search them for edges, and so on\nsee the \\ct{registering} and\n\\ct{overlays\\_and\\_blending}\nexamples for ideas.\n\nThere are also some first order mosaic functions:\n\\ctr{Tasks}\\ctr{Mosaic}\\ctr{Two Points}\\ct{Left to Right} and\n\\ctr{Tasks}\\ctr{Mosaic}\\ctr{Two Points}\\ct{Top to Bottom}. These functions\nautomatically rotate and scale the right-hand image in a join. They are\nuseful for assembling X-ray mosaics, and for fixing very difficult joins in\nreflectogram images. These functions work the same way as the \\ct{One Point}\nfunctions except that you will need to define two tie-points on each image.\n\nYou can mosaic images of any numeric type: 16-bit integer images are handy for\nmosaicing X-ray images, for example.\n\n\\section{Printing}\n\nOnce you have assembled a good reflectogram, you will want to print it,\nor to use it in other computer programs. The best way to do this is to save\nthe final image in TIFF or JPEG format, and then load it into the new\napplication --- see~\\pref{sec:loadsave}.\n\nThere are a couple of points to bear in mind: first, like any image,\nreflectograms look best on paper if you sharpen them up a little first. Click\non \\ctr{Filter}\\ctr{Convolution}\\ct{Custom Convolution}, right click on\nthe matrix button, select \\ct{Replace from file}. Double Click on the\nsecond or lower \\ct{data} directory listed in the left hand column to\nenter \\nip{}'s main data directory. Change the \\ctr{Image type select}\noption to \\ct{All FIles (*)} and then select and load \\ct{rachel.con}.\nThis will usually produce an approprioatly sharpened reflectogram.\n\nSecondly, you will need to try several prints with different contrasts\nand brightnesses to get a good match between the paper and the screen,\ntry \\ctr{Image}\\ctr{Levels}\\ct{Linear}. You may even want to fiddle with\nthe gamma, try \\ctr{Image}\\ctr{Levels}\\ct{Power}.\n\nFinally, you may not need a full resolution image. For almost all printers\nthere's no point going over about 300 dpi (dots per inch), or about 3000 by\n2000 pixels for an A4 page. To reduce the size of an image, use one of the \nfunctions listed under \\ctr{Resize}\\ctr{Transform}\\ct{Resize}.\n\n\n"
  },
  {
    "path": "doc/src/intro.tex",
    "content": "\\chapter{Getting started}\n\n\\noindent\n\\nip{} is a user interface for the VIPS image processing library. It is\ndesigned to be fast, even when working with very large images, and to\nbe easy to extend.  \n\nThis guide is split into quite a few chapters:\n\n\\begin{itemize}\n\n\\item\nIf you want to use \\nip{} to assemble infrared mosaics, you should read\n\\cref{sec:ir}. The middle section in the tutorial (see \\pref{sec:irtut})\ndoes IR mosaics very quickly.\n\n\\item\nIf you want to use \\nip{} for general image processing, work through \n\\cref{sec:tutorial}.\n\n\\item\nIf you have specific questions about some part of \\nip{}'s user-interface, look\nat \\cref{sec:reference}.\n\n\\item\nIf you're really hardcore, take a look at \\cref{sec:program}, which covers\nprogramming.\n\n\\item\nIf you want to know more about VIPS, the image processing package\nunderlying \\nip{}, try the \\emph{VIPS Manual}.\n\n\\end{itemize}\n\nIf \\nip{} has installed correctly you should see something like\n\\fref{fg:introwin} when it starts up.\n\n\\begin{figure}\n\\figw{3in}{snap1.jpg}\n\\caption{\\nip{} as it starts up}\n\\label{fg:introwin}\n\\end{figure}\n\n"
  },
  {
    "path": "doc/src/menus.tex",
    "content": "\\chapter{Image processing menus}\n\\mylabel{sec:menus}\n\n\\noindent\nThis chapter is runs quickly through the \\ct{Toolkits} menu.  See\n\\cref{sec:program} if you want to understand how the menus are written\n(or want to add more of your own). Use the Toolkit Browser to find stuff.\n\nSome things are common to almost all menu items:\n\n\\begin{description}\n\n\\item[Tooltips]\n\tIf you rest your mouse pointer over an item,\n\tyou'll see a quick description of what the item does.\n\n\\item[Grouping]\n\tYou can select several objects, click \\ctr{Edit}\\ct{Group}, and then\n\twhen you click the item, it will operate on all the objects in the \n\tgroup.\n\n\\item[Any type]\n\tAlmost all items will work on any object. You can add an image and a\n\tnumber, for example, find the colour difference between a number and\n\tan image, or transform a matrix from LAB to XYZ.\n\n\\end{description}\n\n\\section{Colour}\n\\mylabel{sec:menu-colour}\n\nThis menu groups operations on colorimetric images and patches of\ncolour. A colour patch is three float numbers plus a tag saying how those\nnumber should be interpreted as colour (for example, as a colour in CIE LAB\ncolourspace). You can drag and drop between colour patches, and into and from\nthe inkwell in an image paint window. Double-left-click on a colour patch to\nopen a colour select dialog.\n\n\\nip{} has 9 main types of colorimetric image, see \\tref{tb:colour}.\nAll these types are D65 (that is, daylight) absolute colorimetric.\nWhen it displays an image, \\nip{} uses the \\ct{Type} field in the image\nheader as a hint on how to transform the numbers in the image into RGB for\nthe display. The current \\ct{Type} is displayed at the end of the caption\nline below an image thumbnail. \n\nThe \\ct{Mono}, \\ct{GREY16} and \\ct{RGB16} types are not really calibrated\nthemselves: they are usually whatever you get by loading an image from a file.\nYou'll usually need an extra step, such as applying an embedded ICC profile,\nbefore you get accurate colour.\n\n\\begin{tab2}\n\\begin{center}\n\\begin{tabular}{||l|l|l||}\n\\hline\nName & Format & Notes \\\\\n\\hline\n\\ct{Mono} & One band 8 bit & \n\tNot calibrated \\\\\n\\ct{sRGB} & Three band 8 bit & \n\tScreen device space for the sRGB standard \\\\\n\\ct{GREY16} & One band 16 bit & \n\tNot calibrated \\\\\n\\ct{RGB16} & Three band 16 bit & \n\tNot calibrated \\\\\n\\ct{Lab} & Three band float & \n\tThe 1976 version of the CIE perceptual colourspace \\\\\n\\ct{LabQ} & Four band 8 bit & \n\tLike \\ct{Lab}, but represented as 10:11:11 bits \\\\\n\\ct{LabS} & Three band 16 bit & \n\tLike \\ct{Lab}, but represented as 15:16:16 bits \\\\\n\\ct{LCh} & Three band float & \n\t\\ct{Lab}, but with polar coordinates \\\\\n\\ct{XYZ} & Three band float & \n\tThe base CIE colourspace \\\\\n\\ct{Yxy} & Three band float & \n\tSometimes useful for colour meters \\\\\n\\ct{UCS} & Three band float & \n\tHighly uniform space from the CMC(l:c) standard \\\\\n\\hline\n\\end{tabular}\n\\end{center}\n\\caption{\\nip{} colourspaces}\n\\mylabel{tb:colour}\n\\end{tab2}\n\n\\begin{description}\n\n\\item[\\ct{New}]\n\tMake a patch of colour, or pick a colour from a slice through CIELAB\n\tcolourspace.\n\n\\item[\\ct{Convert To Colour}]\n\tConvert anything into a Colour object.\n\n\\item[\\ct{Colourspace}]\n\tChange the colourspace. The stored numbers change, but the\n\tvisual appearance should stay the same.\n\n\\item[\\ct{Tag As}]\n\tChange the colourspace tag (the \\ct{Type} field in the image\n\theader). The stored numbers stay the same, but the visual appearance\n\tshould change.\n\n\\item[\\ct{Colour Temperature}]\n\tChange the colour temperature. \\ct{Move Whitepoint} just adjusts the\n\tratios of X and Z using the CIE standard illuminants.\n\t\n\t\\ct{D65 to D50} and \\ct{D50 to D65} transform using either a 3x3\n\tmatrix which is numerically minimal in XYZ space with respect to the\n\tcolours on a Macbeth Color Checker, or via Bradford cone space. The\n\tBradford transform omits the power term.\n\n\tThe final two items go from XYZ to LAB and back, but with D50\n\tnormalisation rather than the default D65.\n\n\\item[\\ct{ICC}]\n\tTransform images (not patches of colour) device space to profile \n\tconnection space (LAB float) and back. \n\t\n\tYou need to be careful about colour temperature issues:\n\tall printers work with D50, and \\nip{} is all D65. Use the D65 to D50\n\tinterchange items in the \\ct{Colour Temperature} menu to swap back and\n\tforth.\n\n\tAll printers also work with relative colorimetry, and \\nip{} is\n\tgenerally absolute. Use \\ct{Absolute to Relative} to scale an absolute\n\tcolorimetric image by a media white point.\n\n\\item[\\ct{Radiance}]\n\t\\nip{} can read and write images written by the Radiance family\n\tof programs (usually with the suffix \\ct{.hdr}), commonly used in\n\tHDR photrography.\n\n\tImages in this format used a packed floating point layout for their\n\tpixels. Items in this menu pack and unpack pixels for you.\n\n\\item[\\ct{Difference}]\n\tCalculate various colour difference metrics. You can mix patches of\n\tcolour and colour images.\n\n\\item[\\ct{Adjust}]\n\tChange colour in a colorimetric way. \\ct{Recombination}\n\tmultiplies each pixel in an image through a matrix. \\ct{Cast}\n\tdisplaces the neutral axis in LAB space. \\ct{HSB} lets you adjust an\n\timage in LCh colourspace.\n\n\\item[\\ct{Similar Colour}]\n\tfind pixels in an image with a similar colour to a patch of\n\tcolour. \n\n\\item[\\ct{Measure Colour Chart}]\n\tThis takes a trimmed image of a colour chart (a rectangular grid of\n\tcoloured squares), measures the average pixel value in the centre 50\\%\n\tof each square, and returns a matrix of the measured values. \n\n\tUse \\ct{Make Synthetic Colour Chart} to make a colour chart image from\n\ta matrix of measurements. \n\n\\item[\\ct{Plot ab Scatter}]\n\tdraws a 2 dimensional histogram of the distribution of pixel colours\n\tin LAB colourspace.\n\n\\end{description}\n\n\\section{Filter}\n\\mylabel{sec:menu-filter}\n\nThis menu groups operations which filter images, or which are filters in the\nphotoshop sense.\n\n\\begin{description}\n\n\\item[\\ct{Convolution}]\n\tThis menu has several standard convolution operations (blur, sharpen,\n\tedge detect, etc.), plus the option to convolve with a custom kernel.\n\n\tTwo menu items are slightly more complicated. \\ct{Unsharp Mask}\n\ttransforms to CIE LAB colour space, then sharpens just the L band\n\twith a cored unsharp filter. The \\ctr{Tasks}\\ct{Print} menu has a\n\tversion of this filter tuned for typical inkjet printers.\n\n\t\\ct{Custom Blur} builds and applies a square or gaussian convolution\n\tkernel for you based on a radius setting.\n\n\\item[\\ct{Rank}]\n\tA preset median filter, and a custom rank filter that lets you specify\n\twindow size and rank.\n\n\tThe \\ct{Image Rank} item does pixel-wise ranking of a set of images.\n\n\\item[\\ct{Morphology}]\n\tThese menu items implement basic morphological operations. Images are\n\tzero for background and non-zero (usually 255) for object. Matricies\n\tare shown as 0, 1 and * for background, object and don't-care.\n\n\tThe \\ct{Threshold} item does a simple level threshold. Use the\n\t\\ctr{Math}\\ct{Relational} menu to construct more complex image\n\tbinarisations. Use \\ctr{Math}\\ct{Boolean} to combine morphologies.\n\n\tThe first half of the menu lists simple erode and dilate operations, 4-\n\tand 8-way connected. The second half contains several useful compound\n\tfilters.\n\n\tSee also \\ctr{Histogram}\\ct{Find Profile} for\n\tsomething that can search an image for object edges. And\n\t\\ct{Math}\\ctr{Statistics}\\ct{Edges} can count the number of edges\n\tacross and down an image.\n\n\\item[\\ct{Fourier}]\n\tA selection of ideal, Gaussian and Butterworth Fourier space filters.\n\n\tYou can make other mask shapes yourself using the \\ctr{Image}\\ct{Make\n\tPatterns} menus, then apply them using \\ctr{Math}\\ct{Fourier}. You can\n\talso use the image paintbox to directly paint out peaks in a\n\tfourier-space image before transforming back to real space.\n\t\n\\item[\\ct{Enhance}]\n\tA selection of simple image enhancement filters. \\ct{Statistical\n\tDifference} passes a window over an image and tries to match the\n\tregion statistics at each point to a target mean and deviation. \n\n\\item[\\ct{Spatial Correlation}]\n\tPlace a small image at every possible position in a big image and\n\tcalculate the correlation at each position. \\ct{Simple Difference} is\n\tthe much faster unnormalised version.\n\n\\item[\\ct{GREYCstoration}]\n\tVIPS includes a copy of the CImg library and you can use two useful\n\tCImg operations from this menu: denoising and enlarging.\n\n\\item[\\ct{Tilt Brightness}]\n\tA selection of tools for adjusting the brightness of an image across\n\tit's surface. Useful for correcting lighting problems.\n\n\\item[\\ct{Blend}]\n\tBlend two objects together using either a third object to control the\n\tblend at each point, or a slider to set all points together. You can\n\tblend almost anything with anything.\n\n\tOne useful version is to use a text image (see \\ctr{Image}\\ctr{Make\n\tPatterns}\\ct{Text}) to blend between two colours (see\n\t\\ctr{Colour}\\ct{New}).\n\n\t\\ct{Along Line} does a left/right or top/bottom fade between two\n\timages.\n\n\\item[\\ct{Overlay}]\n\tMake a colour overlay of two monochrome images. Useful with\n\t\\ctr{Image}\\ctr{Transform} for testing image superposition.\n\n\\item[\\ct{Colourize}]\n\tUse a colour image to tint a monochrome image. Useful in conjunction\n\twith \\ctr{Image}\\ctr{Transform}.\n\n\\item[\\ct{Browse}]\n\tLook at either the bits or the bands of an image.\n\n\\item[\\ct{Photographic Negative} and friends]\n\tA small selection of simple, faintly photoshop-style filters. \n\n\\end{description}\n\n\\section{Histogram}\n\\mylabel{sec:menu-histogram}\n\nThis menu groups operations for finding and transforming image histograms.\n\\nip{} represents histograms and lookup tables as images with \\ct{Type}\nset to \\ct{Histogram}.  Histograms may have pixels in any format and any\nnumber of bands. You can only find histograms of unsigned 8- and 16-bit\nimages.\n\n\\begin{description}\n\n\\item[\\ct{New}]\n\tThis makes a new ramp histogram. A set of sliders let you adjust the\n\tshape. Use \\ct{Map Histogram} to apply your ramp to an image.\n\n\t\\ct{Build LUT from Scatter} makes a histogram from a matrix of \n\t$(x, y)$ values. \n\n\t\\ct{Tag Image as Histogram} marks an image as actually being a \n\thistogram after all.\n\n\t\\ct{Tone Curve} builds a tone curve which you can later apply to an\n\timage.\n\n\\item[\\ct{Find}]\n\tA one dimensional histogram treats each band as an independent\n\tvariable. An $n$-dimensional histogram treats each pixel as a vector of\n\t$n$ elements, where $n$ is the number of bands in the image.\n\n\\item[\\ct{Map}]\n\tLooks up each pixel in the input in the histogram and sends the found\n\tvalue to the output.\n\n\\item[\\ct{Equalise}]\n\tFind the global or locally histogram equalised image.\n\n\\item[\\ct{Cumulative}]\n\tUse this and friends to calculate a cumulative histogram (integrate), \n\tnormalise a histogram and match two histograms. \n\n\\item[\\ct{Find Profile}]\n\tSearches from the edges of an image for the first non-zero pixel and\n\treturns a profile histogram. \n\n\\item[\\ct{Find Projections}]\n\tSum columns and rows in an image.\n\n\\item[\\ct{Plot Slice}]\n\tMark a guide on an image (drag from the\n\timage rulers, or click \\ctr{File}\\ctr{New}\\ct{Guide}) and click \n\t\\ct{Plot Slice} to make a histogram which is a horizontal or vertical \n\tslice through an image. Use \\ct{Extract Arrow} to extract the area\n\taround an arrow or guide. Use \\ct{Plot Object} to make a plot of any\n\tobject.\n\n\\end{description}\n\n\\section{Image}\n\\mylabel{sec:menu-image}\n\nThis menu groups operations which apply only to images.\n\n\\begin{description}\n\n\\item[\\ct{New}]\n\tMakes a new image. \\ct{Region on Image} makes a new region, arrow,\n\tguide or mark on an image. It's usually easier to open a viewer on\n\tan image and Ctrl-drag.\n\n\\item[\\ct{Convert to Image}]\n\tTry to make an image out of anything.\n\n\\item[\\ct{Format}]\n\tSwitch between the various precisions.\n\n\\item[\\ct{Header}]\n\tTry to change or examine the image header in various ways.\n\n\\item[\\ct{Cache}]\n\tThis caches an image in RAM. Use this to save the results of a long\n\tcomputation.\n\n\\item[\\ct{Levels}]\n\tVarious tools that change the levels in an image. \\ct{Tone Curve} is\n\tthe only complex one: it lets you adjust the image levels with a set\n\tof sliders.\n\n\\item[\\ct{Transform}]\n\tVarious tools that change the geometry of an image. \n\n\tTo use \\ctr{Rotate}\\ct{Straighten}, mark an arrow on an image\n\t(Ctrl-drag up and left in an image view window) along a\n\tnear-horizontal or near-vertical edge. When you click on\n\t\\ctr{Rotate}\\ct{Straighten}, \\nip{} will rotate the image by the\n\tsmallest amount that makes that edge exactly horizontal or vertical.\n\n\t\\ct{Linear Match} takes two images and rotates and scales\n\tthe second so that the images can be superimposed. Drag the\n\ttie-=points to mark common features. Use \\ctr{Filter}\\ct{Overlay}\n\tor \\ctr{Filter}\\ct{Colourize} to actually superimpose them.\n\n\t\\ct{Rubber Sheet} is useful for fixing things like lens distortion.\n\tYou give \\ct{Find} two images, a reference and a distorted version\n\tof that reference, and it automatically finds a transform which\n\twill map the distorted image back on to the reference image. Use\n\t\\ct{Apply} to apply the discovered transform to another image.\n\n\\item[\\ct{Band}]\n\tExtract/insert/delete image bands. Use \\ct{To Dimension} to change\n\timage bands into a horizontal or vertical dimension. Use \\ct{To\n\tBands} to compress the horizontal or vertical dimension into bands\n\t(small images only!).\n\n\\item[\\ct{Crop}]\n\tCrops an image. It's often easier to drag out a region. This menu item\n\tis only really useful for cropping large groups of images.\n\n\\item[\\ct{Insert}]\n\tThis takes two images and pastes the smaller into the centre of the\n\tlarger. The two images have to have the same number of bands.\n\tIf you open an image viewer on the large image, you'll see an area\n\twhich you can drag around to set the exact insert point.\n\n\\item[\\ct{Select}]\n\tDraw elipses and polygons on an image. Useful for selecting defined\n\tareas.\n\n\\item[\\ct{Join}]\n\tUse to join two images together bandwise, left/right or up/down.\n\t\\ct{Array} joins a list of lists of images together into a single\n\tlarge image.\n\n\\item[\\ct{Tile}]\n\tRepeat an image horizontally and vertically to make a larger image, or\n\tchop an image into a set of tiles.\n\n\\item[\\ct{Patterns}]\n\tThese items all make useful images for you, from checkerboards to\n\tgaussian masks. \\ct{XY Image} is the most useful: you can use it to\n\tbuild other patterns.\n\n\\item[\\ct{Test Images}]\n\tThese items make a variety of useful testcharts for evaluating\n\tspatial response and colour.\n\n\\end{description}\n\n\\section{Math}\n\\mylabel{sec:menu-math}\n\nBasic maths operations on any combination of any objects. You can add a slider\nto a matrix, for example, then divide by an image. Hopefully most of these \nare obvious.\n\n\\begin{description}\n\n\\item[\\ctr{Arithmetic}\\ct{Absolute Value Vector}]\n\tThe absolute value item normally calculates mod of each band of an\n\timage separately. By contrast, \\ct{Absolute Value Vector} treats\n\teach pixel as a vector and calculates the modulus of that.\n\n\\item[\\ct{List}]\n\tThese aren't really maths operations, but they're in here too.\n\n\\end{description}\n\n\\section{Matrix}\n\\mylabel{sec:menu-matrix}\n\nThis menu groups operations which operate on matricies. \\nip{} has four ways\nof displaying a matrix, but they all behave in the same way under the skin.\nAlmost all the items in the \\ct{Math} menu will work on matricies. Most of the\nmatrix operations will also work on images.\n\n\\begin{description}\n\n\\item[\\ct{New}]\n\tThe first four items make matricies which display and edit in various \n\tways useful for different applications. The final two make matricies\n\twhich are pre-filled with useful numbers.\n\n\\item[\\ct{Convert to Matrix}]\n\tTry to make anything into a matrix.\n\n\\item[\\ct{Extract}]\n\tThis group of items extracts various submatricies. You can also do\n\tthis graphically: just drag-select an area in matrix.\n\n\\item[\\ct{Insert}, \\ct{Delete}, \\ldots]\n\tAlso work on images, which can be handy.\n\tA 45 degree rotate will only work for square matricies with\n\todd-length sides.\n\n\\item[\\ct{Invert}]\n\tSimple matrix-only maths operations.\n\n\\item[\\ct{Plot Scatter}]\n\tThis takes a two-column matrix where the columns are the X and Y\n\tpositions of points and draws a scatter graph.\n\n\\end{description}\n\n\\section{Object}\n\\mylabel{sec:menu-object}\n\nThis groups a few items which had no obvious home and which change the format\nof objects.\n\n\\begin{description}\n\n\\item[\\ct{Duplicate}]\n\tCopy an object, stripping off any derived classes. For images, this\n\treally takes a copy of the underlying object (using \\ct{im\\_copy()}).\n\n\\item[\\ct{List to Group}]\n\tChanges lists (see \\ctr{Math}\\ct{List}) into Groups (see\n\t\\ctr{Edit}\\ct{Group}) and back. A list os an ordered collection of\n\tobjects. A group is a list that \\nip{} will automatically iterate\n\tover.\n\n\\item[\\ct{Break Up Object}]\n\tThis tries to take an object apart. So a multi-band image becomes a\n\tlist of 1-band images. A matrix becomes a list of vectors, and so on.\n\t\\ct{Assemble Object} is the inverse.\n\n\\end{description}\n\n\\section{Tasks}\n\\mylabel{sec:menu-tasks}\n\nThis menu repeats many items from other menus, but tries to group them by\ntasks they are useful for, rather than by function.\n\n\\subsection{Capture}\n\\mylabel{sec:menu-capture}\n\nThis menu groups operations which are useful in capturing images, or for the\ninitial processing you might want to do to an image captured from another\nprogram.\n\n\\begin{description}\n\n\\item[\\ct{CSV Import}]\n\tImport an image from a CSV file, with a few controls.\n\n\\item[\\ct{Interpret Analyze 7 Header}]\n\tRead the meta fields for volume layout and calibration from the\n\tAnalyze header and reformat the image appropriately.\n\n\\item[\\ct{Capture Video Frame}]\n\tThis menu item will currently only work on Linux machines with a\n\tcompatible video4linux capture card. See \\pref{sec:vidpref}\n\tfor notes on how it works.\n\n\\item[\\ct{Smooth}]\n\tUse this to remove texture from images. It's handy in conjunction with\n\t\\ct{Flatfield}.\n\n\\item[\\ct{Flatfield}]\n\tUse this to correct homogeneity. Select an image of a piece of white\n\t(or mid-grey) card, then select the image to correct, then click\n\t\\ct{Flatfield}. Use \\ct{Smooth} to renmove texture from the white card\n\tif necessary.\n\n\tYou can select a single white and a group of images to correct a large\n\tset in one step\n\n\\item[\\ct{White Balance}]\n\tUse this to move the white point to make an area of the image you know\n\tto be white, white.\n\tMark a region on an image, enclosing a patch you know to be white.\n\tSelect the region and the image and click on \\ct{White Balance}.\n\n\\item[\\ct{Find Colour Calibration}]\n\tUse this to colour calibrate an image. Drag a region enclosing an\n\timage of a Macbeth Color Checker Chart and click \\ct{Find Colour\n\tCalibration}. \n\n\\item[\\ct{Apply Colour Calibration}]\n\tUse this to apply the transform calculated by the previous item to\n\tanother image. Select the calibration object, select the RGB image\n\tyou want calibrated, and click \\ct{Apply Colour Calibration}.\n\n\\end{description}\n\n\\subsection{Mosaic}\n\\mylabel{sec:menu-mosaic}\n\nThe items in this menu are discussed in appalling detail in\n\\cref{sec:ir}.\n\n\\begin{description}\n\n\\item[\\ct{One Point}]\n\tJoin two images left-right or top-bottom with a simple\n\ttranslation. Mark a point on each image to be joined (open image\n\tview window, Ctrl-left-click, drag to position), then click on the\n\tmosaic button. The\n\toperation performs elaborate tie-point adjustment, so your selection\n\tof a common feature does not have to be exact.\n\n\tThe \\ct{Manual} versions do not perform automatic tie-point correction\n\tand are useful when joing very difficult images.\n\n\\item[\\ct{Two Point}]\n\tDo a join, but allow the right-hand (or bottom) image to rotate and\n\tscale if it will improve the match. You need to pick two points on\n\teach image.\n\n\\item[\\ct{Balance}]\n\tBreak a mosaic apart, examine average pixel value in the overlap\n\tregions, adjust brightness to match, and reassemble. This only works\n\tfor images which have been produced just by mosaic joins! If you've\n\tdone anything else to the image since loading it, the balance will\n\tfail with a mysterious message.\n\n\\item[\\ct{Manual Balance}]\n\tAdjust the brightness in a set of masked areas to match. Useful for\n\tremoving shadows.\n\n\\item[\\ct{Rebuild}]\n\tUse this to mosaic up one set of files based on joins you made\n\tin another.  Breaks a mosaic part to component files, performs a\n\tstring substitution on the file names, and reassembles. \n\n\\item[\\ct{Clone Area}]\n\tSelect over- or under-exposed pixels in one image and replace them\n\twith the corresponding pixels from another image. Useful for removing\n\tlead numbers used to identify X-ray plates.\n\n\tThe function\n\toperates on two 8-bit mono images.  Move and resize the region\n\ton the first image to define the area around the white number.\n\tMove the region on the second to overlapping area.  A section of the\n\tarea on the second image is cloned and blended into the first image.\n\tThe amount of the defined area to be cloned in defined by a slider\n\twithin the output image.\n\n\\end{description}\n\n\\subsection{Picture Frame}\n\\mylabel{sec:menu-picture-frame}\n\nItems useful for mocking up painting frames.\n\n\\subsection{Print}\n\\mylabel{sec:menu-print}\n\nItems useful while preparing an image for printing.\n\n\\begin{description}\n\n\\item[\\ct{Sharpen}]\n\tSharpen an image for printing. This is a version of\n\t\\ctr{Filter}\\ctr{Convolution}\\ct{Unsharp Mask} tuned for typical\n\tinkjet printers.\n\n\\item[\\ct{Adjust Tone Curve}]\n\tAdjust the reproduction tone curve in LAB. Most useful for offset\n\twork, especially from transparencies.\n\n\\end{description}\n"
  },
  {
    "path": "doc/src/mydefs.tex",
    "content": "% My defs\n\n% Computer Text, Computer text=>, Computer Text Display\n\\newcommand{\\ct}[1]{\\textsf{\\smaller{}#1}}\n\\newcommand{\\ctr}[1]{\\ct{#1} / }\n\n\\newenvironment{ctd}{\\begin{quote}\\footnotesize\\tt}{\\end{quote}}\n\\pagecolor{white}\n\n% abbreviations\n\\newcommand{\\nip}{\\ct{nip2}}\n\\newcommand{\\bs}{$\\backslash$}\n\\newcommand{\\rtp}{\\^{ }}\n\\newcommand{\\cielab}{\\emph{CIE~}$L^{*}a^{*}b^{*}$}\n\\newcommand{\\ciexyz}{\\emph{CIE XYZ}}\n\\newcommand{\\cross}{$\\times{}$}\n\n% make a label ... override this for HTML output and insert an anchor\n\\newcommand{\\mylabel}[1]{\\label{#1}}\n\n% generate \" on page xx\" if a label is referring to something on another page\n% override this for HTML output\n\\newcounter{boink}\n\\newcommand{\\onpage}[1]{%\n\\addtocounter{boink}{1}%\n\\label{atref\\theboink{}}%\n\\ifthenelse{\\pageref{atref\\theboink{}}=\\pageref{#1}}%\n{}%\n{ on page~\\pageref{#1}}}\n\n% format a reference to a section .. \"$3.11 on page 37\"\n\\newcommand{\\pref}[1]{\\S\\ref{#1}\\onpage{#1}}\n\\newcommand{\\tref}[1]{Table~\\ref{#1}\\onpage{#1}}\n\\newcommand{\\fref}[1]{Figure~\\ref{#1}\\onpage{#1}}\n\\newcommand{\\cref}[1]{Chapter~\\ref{#1}\\onpage{#1}}\n\\newcommand{\\aref}[1]{Appendix~\\ref{#1}\\onpage{#1}}\n\n% Insert a file ... height and name.\n\\newcommand{\\fig}[2]{\n\t\\begin{center}\n\t\\includegraphics[height=#1]{figs/#2}\n\t\\end{center}\n}\n\n% Insert a file ... width and name.\n\\newcommand{\\figw}[2]{\n\t\\begin{center}\n\t\\includegraphics[width=#1]{figs/#2}\n\t\\end{center}\n}\n\n% make a 2-column figure ... define our own so we can easily override in html\n% output\n\\newenvironment{fig2}{\\begin{figure*}}{\\end{figure*}}\n\n% same for 2-col tables\n\\newenvironment{tab2}{\\begin{table*}}{\\end{table*}}\n\n% causes problems for htlatex :-( \n% make this a noop for now\n% \\newcommand{\\dtxt}[1]{\\multicolumn{25}{@{\\hspace{0.2em}}l}{#1}}\n\\newcommand{\\dtxt}[1]{#1}\n\n% Insert a blank page\n\\newcommand{\\blankpage}{%\n\\newpage\n~~~~\n\\pagestyle{plain}\n\\newpage\n% Another one necessary in twocolumn mode\n~~~~\n\\newpage\n\\pagestyle{fancy}\n}\n\n%\\addtolength{\\headheight}{3pt}\n\n% Make text a bit wider, since we are two column.\n\\addtolength{\\textwidth}{0.5in}\n\\addtolength{\\oddsidemargin}{-0.25in}\n\\addtolength{\\evensidemargin}{-0.25in}\n\n% twocolumn seems to remove the binding offset ... add it back\n%\\addtolength{\\oddsidemargin}{-0.2in}\n%\\addtolength{\\evensidemargin}{0.2in}\n\n% More space between headers and footers and the body\n\\addtolength{\\topmargin}{-0.5em}\n\\addtolength{\\headsep}{0.5em}\n\\addtolength{\\footskip}{0.5em}\n\n% Swap left and right binding offsets\n\\newlength{\\fred}\n\\setlength{\\fred}{\\oddsidemargin}\n\\setlength{\\oddsidemargin}{\\evensidemargin}\n\\setlength{\\evensidemargin}{\\fred}\n"
  },
  {
    "path": "doc/src/nipguide.tex",
    "content": "\\documentclass[a4paper,twocolumn,dvips]{book}\n\\usepackage[dvips=false,pdftex=false,vtex=false]{geometry}\n\\usepackage{relsize}\n\\usepackage{ifpdf}\n\\ifpdf\n  \\usepackage[pdftex]{graphicx,color}\n\\else\n  \\usepackage{graphicx,color}\n\\fi\n\\usepackage{times}\n\\usepackage{fancyhdr}\n\\usepackage{ifthen}\n\n\\input{mydefs}\n\n\\fancyhead{} % clear all fields\n\\fancyhead[LE,RO]{\\leftmark}\t\t% left-even, right-odd\n\\fancyhead[RE,LO]{\\nip{} Manual}\t% right-even, left-odd\n\\fancyfoot[LE,RO]{\\thepage}\t\t% left-even, right-odd\n\\fancyfoot[RE,LO]{December 2017}\t\t\n\n\\begin{document}\n\n\\pagenumbering{roman}\n\n\\begin{titlepage}\n\\thispagestyle{empty}\n\\begin{center}\n\\huge\n\\nip{} Manual\\\\[0.2em]\n\\large Version 8.6\\\\\n\\vspace{0.5in}\n\\large\nJohn Cupitt, \nRachel Billinge,\nJoseph Padfield, \nClare Richardson, \nDavid Saunders\\\\ \n\\end{center}\n\n% hmm ... must be a better way to get the quote at the bottom of the page\n\\vspace{3in}\n\n\\begin{center}\n\\noindent\n\\emph{``It's quite simple really, and at the same time, rather \ncomplicated.''} \\\\\n--- A.\\ Haddock, Sea captain (rtd.)\n\\end{center}\n\n\\vspace{3in}\n\n\\noindent\n\\small{This document formatted \\today}\n\\setcounter{page}{1}\n\\end{titlepage}\n\n%\\blankpage\n\\tableofcontents\n\\thispagestyle{plain}\n\n%\\blankpage\n\\listoffigures\n\\thispagestyle{plain}\n\n%\\blankpage\n\\listoftables\n\\thispagestyle{plain}\n\n\\blankpage\n\\pagenumbering{arabic}\n\\thispagestyle{plain}\n\\cfoot{}\n\n\\input{intro}\n\\input{tutorial}\n\\input{infrared}\n\\input{reference}\n\\input{menus}\n\\input{program}\n\\appendix\n\\input{config}\n\n\\end{document}\n"
  },
  {
    "path": "doc/src/program.tex",
    "content": "\\chapter{Programming}\n\\mylabel{sec:program}\n\n\\noindent\n\\nip{} includes a tiny lazy functional programming language. You can use it to\nglue VIPS image processing functions together to perform more complicated\ntasks.  All of the \\nip{} toolkit menus are written in this language.\n\nThese first sections just describe the programming language. See\n\\pref{sec:progwin} for a description of the programming window.  You use\n\\nip{}'s programming language to control the user interface: the link between\nwhat happens inside a \\nip{} function and what you see on the screen in\ncovered in \\pref{sec:bowser}.\n\n\\section{Load and save}\n\nWhen \\nip{} starts up it loads all of the definition files (files with a\n\\ct{.def} extension) it can find in the directories listed in your start\npath. You can change the start path in Preferences. By default, the start\npath lists just two areas: a personal start directory that \\nip{} makes in\nyour home area, and the main system \\nip{} start directory containing all\nthe standard toolkits.\n\nIf there are two files with the same name on the start path, then\n\\nip{} will only load the first one. This means that if you modify one\nof \\nip{}'s built-in menus and save it to your personal start directory,\nin future you'll just see your personalised version. \n\nYou can load or reload a toolkit at any time with the \\ctr{File}\\ct{Open\nToolkit} menu item in the program window. If you open a toolkit with the same\nname as an existing toolkit, \\nip{} will remove the old toolkit before it\nloads the new one. \n\n\\section{Using an external editor}\n\nIf you're going to be doing any more than a little programming in \\nip{} you\nprobably won't want to use the built-in editor. I suggest you start your\nfavorite editor in one window on the screen and then in the \\nip{} program\nwindow click \\ctr{File}\\ct{Open Toolkit} and check the Pin-up box in the file\nselector.\n\nNow every time you want to try out your definition, save the file from your\nexternal editor and click OK in \\nip{}'s file selector. \n\n\\nip{}'s editor automatically adds some semicolon characters to separate\ndefinitions in a file. If you're using an external editor, you'll need to put\nthese in yourself. Also check the syntax for adding separators and column\nitems to menus.\n\n\\section{Syntax}\n\nThe most basic sort of definition looks like this:\n\n\\begin{verbatim}\n// very simple!\nfred = 12\n\\end{verbatim}\n\n\\noindent\nThis defines a function called \\ct{fred} whose value is the number 12. The\n\\ct{//} marks a comment: everything to the end of the line is skipped.\nCase is distinguished, so \\ct{Fred} and \\ct{fred} are two different functions.\nYou can use letters, numbers, underscores and single quotes in function names.\n\nYou can have patterns on the left of the equals sign. For example:\n\n\\begin{verbatim}\n[fred, petra] = [12, 13]\n\\end{verbatim}\n\n\\noindent\ndefines \\ct{fred} to have the value 12 and \\ct{petra} to have the value 13.\nSee \\pref{sec:pattern} for details.\n\nFunctions may take parameters:\n\n\\begin{verbatim}\n/* A function with parameters.\n */\njim a b = a + b + 12\n\\end{verbatim}\n\n\\noindent\nThis defines a function called \\ct{jim} which takes two parameters and whose\nvalue is the sum of the two parameters, plus 12. The \\ct{/*} and \\ct{*/}\nenclose a multi-line comment.\n\nFunctions may have several right-hand-sides, each right-hand-side qualified by\na guard expression. Guards are tested from top to bottom and the first guard\nwhich has the value \\ct{true} causes the function to have the value of that\nright-hand-side. If no guard evaluates to \\ct{true}, then the last\nright-hand-side is used.\n\n\\begin{verbatim}\njenny a b\n  = 42, a + b >= 100\n  = 43, a + b >= 50\n  = 44\n\\end{verbatim}\n\n\\noindent\nThis defines a function called \\ct{jenny} which takes two parameters and whose\nvalue is 42 if the sum of the parameters is 100 or greater; 43 if the sum is\ngreater than or equal to 50 but less than 100; and 44 if the sum is less than\n50.\n\nAny function may be followed by any number of local functions, enclosed in\ncurly braces. So \\ct{jenny} could be written as:\n\n\\begin{verbatim}\njenny a b\n  = 42, sum >= 100\n  = 43, sum >= 50\n  = 44\n{\n  sum = a + b;\n}\n\\end{verbatim}\n\n\\noindent\nNote that you need a semi-colon after each local function.  A local function\nmay refer to anything in an enclosing scope, including itself.\n\nYou can write \\ct{if-then-else} expressions:\n\n\\begin{verbatim}\ndavid a = if a < 12 then \"my cat\"\n  else \"likes lasagne\"\n\\end{verbatim}\n\n\\noindent\nThis is exactly equivalent to:\n\n\\begin{verbatim}\ndavid a\n  = \"my cat\", a < 12\n  = \"likes lasagne\"\n\\end{verbatim}\n\n\\noindent\n\\ct{if-then-else} expressions are sometimes easier to read than guards.\n\nFunctions application is with spaces (juxtaposition). For example:\n\n\\begin{verbatim}\nharry = jim 2 3\n\\end{verbatim}\n\n\\noindent\ndefines \\ct{harry} to have the value 17. \n\nAll functions are curried, that is, they can accept their arguments in\nstages. For example:\n\n\\begin{verbatim}\nsandro = jim 1\n\\end{verbatim}\n\n\\noindent\ndefines \\ct{sandro}, a function which takes one parameter and will add 13 to\nit. This trick becomes very useful with list processing, see \\pref{sec:lists}.\n\n\\nip{} has some built-in functions, see \\tref{tb:builtin}. They mostly \ntake a single argument. All other functions are defined in the various\nstandard toolkits and can be edited in the program window.\n\n\\begin{tab2}\n\\begin{center}\n\\begin{tabular}{||l|l||}\n\\hline\nFunction & Description \\\\\n\\hline\n\\ct{dir} \\textit{any}\t\t& List names in scope \\\\\n\\ct{has\\_member} \\textit{[char]} \\textit{any}\t& \n\t\t\t\tDoes class have member \\\\\n\\hline\n\\ct{name2gtype} \\textit{[char]}\t& Search for a GType by name \\\\\n\\ct{gtype2name} \\textit{real}\t& Return the name of a GType \\\\\n\\hline\n\\ct{error} \\textit{[char]}\t& Stop with error message \\\\\n\\ct{print} \\textit{any}\t\t& Convert to string \\\\\n\\ct{expand} \\textit{[char]}\t& Expand environment variables in string \\\\\n\\ct{search} \\textit{[char]}\t& Search for a file \\\\\n\\ct{\\_} \\textit{[char]}\t\t& Translate string \\\\\n\\hline\n\\ct{is\\_image} \\textit{any}\t& Test for image \\\\\n\\ct{is\\_bool} \\textit{any}\t& Test for boolean \\\\\n\\ct{is\\_real} \\textit{any}\t& Test for real\t\\\\\n\\ct{is\\_class} \\textit{any}\t& Test for class \\\\\n\\ct{is\\_char} \\textit{any}\t& Test for char\t\\\\\n\\ct{is\\_list} \\textit{any}\t& Test for list\t\\\\\n\\ct{is\\_complex} \\textit{any}\t& Test for complex \\\\\n\\ct{is\\_instanceof} \\textit{[char]} \\textit{any}\t& \n\t\t\t\tTest for instance of class\t\\\\\n\\hline\n\\ct{re} \\textit{image}/\\textit{complex}/\\textit{class} & \n\t\t\t\tExtract real part of complex\t\\\\\n\\ct{im}\t\\textit{image}/\\textit{complex}/\\textit{class} &\n\t\t\t\tExtract imaginary part of complex \\\\\n\\ct{hd} \\textit{list}\t\t& Extract head of list \\\\\n\\ct{tl}\t\\textit{list}\t\t& Extract tail of list \\\\\n\n\\ct{sin} \\textit{image}/\\textit{number}/\\textit{class} & \n\t\t\t\tSine \\\\\n\\ct{cos} \\textit{image}/\\textit{number}/\\textit{class} & \n\t\t\t\tCosine \\\\\n\\ct{tan} \\textit{image}/\\textit{number}/\\textit{class} & \n\t\t\t\tTangent \\\\\n\\ct{asin} \\textit{image}/\\textit{number}/\\textit{class} & \n\t\t\t\tArc sine \\\\\n\\ct{acos} \\textit{image}/\\textit{number}/\\textit{class} & \n\t\t\t\tArc cosine \\\\\n\\ct{atan} \\textit{image}/\\textit{number}/\\textit{class} & \n\t\t\t\tArc tangent \\\\\n\\ct{log} \\textit{image}/\\textit{number}/\\textit{class} & \n\t\t\t\tNatural log \\\\\n\\ct{log10} \\textit{image}/\\textit{number}/\\textit{class} & \n\t\t\t\tBase 10 log \\\\\n\\ct{exp} \\textit{image}/\\textit{number}/\\textit{class} & \n\t\t\t\te to the power \\\\\n\\ct{exp10} \\textit{image}/\\textit{number}/\\textit{class} & \n\t\t\t\t10 to the power \\\\\n\\ct{ceil} \\textit{image}/\\textit{number}/\\textit{class} & \n\t\t\t\tRound up \\\\\n\\ct{floor} \\textit{image}/\\textit{number}/\\textit{class} & \n\t\t\t\tRound down \\\\\n\\ct{gammq} \\textit{real} \\textit{real} & \n\t\t\t\tNormalised incomplete Gamma function \\\\\n\\hline\n\\ct{vips\\_image} \\textit{[char]}& Load image from file \\\\\n\\ct{read} \\textit{[char]}\t& Load file as a string \\\\\n\\hline\n\\end{tabular}\n\\end{center}\n\\caption{\\nip{} built in functions}\n\\mylabel{tb:builtin}\n\\end{tab2}\n\n\\section{Naming conventions}\n\nYou can name things in any way you like, but we've used the following\nconventions.\n\n\\begin{itemize}\n\n\\item\nClasses start with a capital letter, words are separated with underscores,\nsubsequent words are not capitalised (eg. \\ct{Image\\_file})\n\n\\item\nPrivate names are prefixed with underscores (and are hidden by most of the\nuser interface)\n\n\\item\nFunctions from the VIPS library are prefixed with \\ct{im\\_}\n\n\\item\nGlobal utility functions (eg. \\ct{map}), public members (eg.\n\\ct{Colour.colour\\_space}) are all lower case, words are separated\nwith underscores, subsequent words are not capitalised\n\n\\item\nConstants are capitalised (eg. \\ct{Operator\\_type.COMPOUND\\_REWRAP})\n\n\\end{itemize}\n\n\\section{Evaluation}\n\n\\nip{} calculates the value of an expression by using the definitions you\nentered to successively reduce the expression until it becomes one of the\nbase types. Sometimes there is a choice as to which part of the expression\nwill be reduced next --- \\nip{} will always choose to reduce the leftmost,\noutermost part of the expression first.\n\nFor example, consider this definition:\n\n\\begin{verbatim}\nfactorial n\n  = n * factorial (n - 1), n > 1\n  = 1\n\\end{verbatim}\n\nAnd here's how \\nip{} will evaluate the expression \\ct{factorial 3}:\n\n\\begin{verbatim}\nfactorial 3 -->\n  3 > 1 -->\n  true\n3 * factorial (3 - 1) -->\n  (3 - 1) > 1 -->\n  2 > 1 -->\n  true\n3 * (2 * factorial (2 - 1)) -->\n  (2 - 1) > 1 -->\n  1 > 1 -->\n  false\n3 * (2 * 1) -->\n3 * 2 -->\n6\n\\end{verbatim}\n\n\\noindent\nNote how \\nip{} delays evaluating parameters to functions until they are\nneeded, but still shares the result. \\ct{3 - 1} is only evaluated once,\nfor example, even though the result is used three times.  \\nip{} has a trace\nwindow: click on \\ctr{Debug}\\ct{Trace} in the program window and check the\n\\ctr{View}\\ct{Operators} menu item.\n\nThe advantage of this style of computation over conventional imperative\nprogramming languages is that you can reason about your program\nmathematically\\footnote{Since programs are referentially transparent (that\nis, the value of an expression depends only upon its syntactic context,\nnot upon computation history), you can easily do equational reasoning,\nproof by induction, and so on.\n\nExpressions are like theorems, definitions are like axioms, computation\nis like proof.}. \n\nThis isn't the best way to write a factorial function. A function with lots\nof recursive calls can be hard to understand --- it's much better to use one\nof the higher order functions from the standard environment to encapsulate\nthe type of recursion you want to use.\n\nThe clearest definition for factorial is probably:\n\n\\begin{verbatim}\nfactorial n = product [1..n]\n\\end{verbatim}\n\n\\noindent\nSee \\pref{sec:listsyntax} for an explanation of the list syntax.\n\n\\section{Operators}\n\\mylabel{sec:operators}\n\n\\nip{}'s expression syntax is almost exactly the same as C,\nwith a few small changes. \\tref{tb:precedence} lists all of \n\\nip{}'s operators in order of increasing precedence. If you've used C, the\ndifferences are:\n\n\\begin{itemize}\n\n\\item\n\tC's \\verb+?:+ operator becomes \\ct{if-then-else}, see above\n\n\\item\n\tLike almost every functional language, \\nip{} uses square brackets\n\tfor list constants (see \\pref{sec:listsyntax}), so to index a\n\tlist, \\nip{} uses \\ct{?}\n\n\\item\n\t\\nip{} adds \\ct{@} for function composition, see \\pref{sec:func}\n\n\\item\n\tThe \\ct{:} operator is infix list cons, see \\pref{sec:lists}\n\n\\item\n\tThe \\ct{++} operator becomes an infix concatenation operator, \\ct{--}\n\tbecomes list difference. Again, see \\pref{sec:listsyntax}\n\n\\end{itemize}\n\nThe only slightly tricky point is that function application binds very\ntightly (only list index and class project bind more tightly). So the\nexpression:\n\n\\begin{verbatim}\njim = fred 2 + 3\n\\end{verbatim}\n\n\\noindent\nbinds as:\n\n\\begin{verbatim}\njim = (fred 2) + 3\n\\end{verbatim}\n\n\\noindent\nThis is almost always the behaviour you want.\n\nThere are two special equality tests: \\ct{===} and \n\\ct{!==}. These test for pointer equality, that is, they return \\ct{true} if\ntheir arguments refer to the same object. These are occasionally useful for\nwriting interactive functions.\n\n\\begin{tab2}\n\\begin{center}\n\\begin{tabular}{||l|l|l||}\n\\hline\nOperator & Associativity & Description \\\\\n\\hline\n\\ct{if then else}\t& Right\t\t\t& If-then-else construct \\\\\n\\ct{=>}\t\t\t& Left\t\t\t& Form name/value pair \\\\\n\\verb+||+\t\t& Left\t\t\t& Logical or \\\\\n\\ct{\\&\\&}\t\t& Left\t\t\t& Logical and \\\\\n\\ct{@}\t\t\t& \t\t\t& Function composition \n\t\t\t\t\t\t  (see \\pref{sec:func}) \\\\\n\\verb+|+\t\t& Left\t\t\t& Bitwise or \\\\\n\\rtp{}\t\t\t& Left\t\t\t& Bitwise exclusive or \\\\\n\\ct{\\&}\t\t\t& Left\t\t\t& Bitwise and \\\\\n\\hline\n\\ct{==}\t\t\t& Left\t\t\t& Equal to\\\\\n\\ct{!=}\t\t\t& \t\t\t& Not equal to\\\\\n\\ct{===}\t\t& \t\t\t& Pointer equal to\\\\\n\\ct{!==}\t\t& \t\t\t& Pointer not equal to\\\\\n\\hline\n\\ct{<}\t\t\t& Left\t\t\t& Less than \\\\\n\\ct{<=}\t\t\t& \t\t\t& Less than or equal to\\\\\n\\ct{>}\t\t\t& \t\t\t& Greater than \\\\\n\\ct{>=}\t\t\t& \t\t\t& Greater than or equal to\\\\\n\\hline\n\\ct{<<}\t\t\t& Left\t\t\t& Left shift \\\\\n\\ct{>>}\t\t\t& \t\t\t& Right shift \\\\\n\\hline\n\\ct{+}\t\t\t& Left\t\t\t& Addition \\\\\n\\ct{-}\t\t\t& \t\t\t& Subtraction \\\\\n\\ct{*}\t\t\t& Left\t\t\t& Multiplication \\\\\n$/$\t\t\t& \t\t\t& Division \\\\\n\\ct{\\%}\t\t\t& \t\t\t& Remainder after division \\\\\n\\ct{!}\t\t\t& Left\t\t\t& Logical negation \\\\\n\\verb+~+\t\t& \t\t\t& One's complement \\\\\n\\ct{++}\t\t\t& \t\t\t& Join \n\t\t\t\t\t\t  (see \\pref{sec:listsyntax}) \\\\\n\\verb+--+\t\t& \t\t\t& Difference \n\t\t\t\t\t\t  (see \\pref{sec:listsyntax}) \\\\\n\\ct{-}\t\t\t& \t\t\t& Unary minus \\\\\n\\ct{+}\t\t\t& \t\t\t& Unary plus \\\\\n\\ct{(}\\emph{type}\\ct{)}\t& \t\t\t& Type cast expression \\\\\n\\ct{**}\t\t\t& Right\t\t\t& Raise to power \\\\\n\\ct{:}\t\t\t& \t\t\t& List CONS\n\t\t\t\t\t\t  (see \\pref{sec:listsyntax}) \\\\\n\\emph{space}\t\t& Left\t\t\t& Function application \\\\\n\\ct{?}\t\t\t& Left\t\t\t& List index \n\t\t\t\t\t\t  (see \\pref{sec:listsyntax}) \\\\\n\\ct{.}\t\t\t& Left\t\t\t& Class project \n\t\t\t\t\t\t  (see \\pref{sec:class}) \\\\\n\\hline\n\\end{tabular}\n\\end{center}\n\\caption{\\nip{} operators in order of increasing precedence}\n\\mylabel{tb:precedence}\n\\end{tab2}\n\n\\subsection{The real type}\n\n\\nip{} has a single number type for integers and real numbers. All are\nrepresented internally as 64-bit floating point values. You can use the four\nstandard arithmetic operators (\\ct{+}, \\ct{-}, \\ct{*}, \\ct{/}), remainder\nafter integer division (\\%), raise-to-power (\\ct{**}), the relational\noperators (\\ct{<}, \\ct{<=}, \\ct{>}, \\ct{>=}, \\ct{==}), the bitwise logical\noperators (\\ct{\\&}, \\verb+|+, \\rtp{}, \\verb+~+), integer shift operators\n(\\ct{<<}, \\ct{>>}) and unary negation and positive (\\ct{-}, \\ct{+}).\n\nOther mathematical functions are pre-defined for you:  \\ct{sin}, \\ct{cos},\n\\ct{tan}, \\ct{asin}, \\ct{acos}, \\ct{atan}, \\ct{log}, \\ct{log10}, \\ct{exp},\n\\ct{exp10}, \\ct{ceil}, \\ct{floor}. Each has the standard behaviour.\n\nYou can use type-casts on reals. However, they remain 64-bit floating point,\nthe range is simply clipped. Casting to \\ct{unsigned short} produces a 64-bit\nfloat whose fractional part has been set to zero, and which has been\nclipped to the range 0 to 65535. This may or may not cause rounding problems.\n\nYou can write hexadecimal number constants as \\verb\"0xff\".\n\n\\subsection{The complex type}\n\nComplex numbers are rather sketchily implemented. They are generally handy for\nrepresenting vectors and coordinates rather than for doing arithmetic, so the\nrange of operations is limited.\n\nComplex constants are written as two numbers enclosed in round brackets and\nseparated by a comma. You can use the four standard arithmetic operators\n(\\ct{+}, \\ct{-}, \\ct{*}, \\ct{/}), raise-to-power (\\ct{**}), and unary negation\nand positive (\\ct{-}, \\ct{+}). You can use \\ct{==} only of the relational\noperators. You can mix complex and real numbers in expressions. You can cast\nreals to complex and back.  Use the functions \\ct{re} and \\ct{im}\nto extract the real and imaginary parts.\n\n\\begin{verbatim}\n(12, 13) + 4 == (16, 13)\n(12, 2 + 2) ==  (12, 4)\nre (12, 13) == 12\nim (12, 13) == 13\n\\end{verbatim}\n\n\\subsection{The character type}\n\nCharacter constants are written as single characters enclosed in single\nquotes. You can use the relational operators (\\ct{<}, \\ct{<=}, \\ct{>},\n\\ct{>=}, \\ct{==}) to sort characters by ASCII order. You can cast a\ncharacter to a real to get its ASCII value. You can cast a real ASCII value \nto a character. You can use the standard C escapes to represent non-ASCII\ncharacters.\n\n\\begin{verbatim}\n(int) 'A' == 65\n(char) 65 == 'A'\nis_digit x = '0' <= x && x <= '9'\nnewline == '\\n' \n\\end{verbatim}\n\n\\subsection{The boolean type}\n\nThe two boolean constants are written as \\ct{true} and \\ct{false}. Boolean\nvalues are generated by the relational operators.  You can use the standard\nlogical operators (\\ct{\\&\\&}, \\verb+||+, \\ct{!}). You can use a boolean type\nas an argument in an \\ct{if-then-else} expression.\n\nAs with C, the logical operators do not evaluate their right-hand sides if\ntheir value can be determined just from evaluating their left-hand sides.\n\n\\begin{verbatim}\ntrue && false == false\ntrue || error \"boink!\" == true\nif true then 12 else 13 == 12\n\\end{verbatim}\n\n\\subsection{The list type}\n\\mylabel{sec:listsyntax}\n\nLists are created from two constructors. \\ct{[]} denotes the empty list. The\nlist construction operator (\\ct{:}, pronounced CONS by LISP programmers) takes\nan item and a list, and returns a new list with the item added to the front.\nAs a convenience, \\nip{} has a syntax for list constants. A list constant is a\nlist of items, separated by commas, and enclosed in square brackets:\n\n\\begin{verbatim}\n12:[] == [12]\n12:13:14:[] == 12:(13:(14:[])) == \n  [12,13,14]\n[a+2,3,4] == (a+2):3:4:[]\n[2]:[3,4] == [[2],3,4]\n\\end{verbatim}\n\nUse the functions \\ct{hd} and \\ct{tl} to take the head and the\ntail of a list:\n\n\\begin{verbatim}\nhd [12,13,14] == 12\ntl [12,13,14] == [13,14]\n\\end{verbatim}\n\nUse \\ct{..} in a list constant to define a list generator. List generators\nbuild lists of numbers for you:\n\n\\begin{verbatim}\n[1..10] == [1,2,3,4,5,6,7,8,9,10]\n[1,3..10] == [1,3,5,7,9]\n[10,9..1] == [10,9,8,7,6,5,4,3,2,1]\n\\end{verbatim}\n\n\\noindent\nList generators are useful for expressing iteration. \n\nLists may be infinite:\n\n\\begin{verbatim}\n[1..] == [1,2,3,4,5,6,7,8,9 ..]\n[5,4..] == [5,4,3,2,1,0,-1,-2,-3 ..]\n\\end{verbatim}\n\n\\noindent\nInfinite lists are useful for expressing unbounded iteration.\nSee \\pref{sec:lazy}.\n\nYou can write list comprehensions like this:\n\n\\begin{verbatim}\n[x :: x <- [1..]; x % 2 == 0]\n\\end{verbatim}\n\n\\noindent\nThis could be read as {\\em All x such that x is in \\verb+[1..]+ and x is\neven}, that is, the list of even numbers.\n\nYou can have any number of semicolon-separated qualifiers and each one can\nbe either a generator (like \\verb\"x <- [1..]\") introducing a new variable\nor pattern (see \\pref{sec:pattern}), or a predicate (like \\verb\"x % 2 == 0\") \nwhich filters the generators to the left of it.\n\nLater generators change more rapidly, so for example:\n\n\\begin{verbatim}\n[(x, y) :: \n  x <- [1..3]; y <- [x..3]] ==\n    [(1, 1), (1, 2), (1, 3), \n      (2, 2), (2, 3), (3, 3)]\n\\end{verbatim}\n\nYou can nest list comprehensions to generate more complex data structures. For\nexample:\n\n\\begin{verbatim}\n[[x * y :: x <- [1..10]] :: \n  y <- [1..10]]\n\\end{verbatim}\n\n\\noindent\nwill generate a times-table.\n\nYou can use pattern-matching (see \\pref{sec:pattern}) to loop over several \ngenerators at the same time. For example:\n\n\\begin{verbatim}\n[(x, y) :: [x, y] <- \n  zip2 [1..3] [1..3]] == \n    [(1, 1), (2, 2), (3, 3)]\n\\end{verbatim}\n\nAs a convenience, lists of characters may be written enclosed in double\nquotes:\n\n\\begin{verbatim}\n\"abc\" == ['a','b','c']\n\\end{verbatim}\n\nYou can define a string constant which has the same form as a variable name \n(that is, letters, numbers, underscore and apostrophy only) with a \\verb+$+\nprefix. For example:\n\n\\begin{verbatim}\n$form7 == \"form7\"\n\\end{verbatim}\n\n\\noindent\n\\nip{} often uses these in option lists.\n\nYou can define a name, value pair with the \\ct{=>} operator. \n\n\\begin{verbatim}\n$fred => 12 == [\"fred\", 12]\n\\end{verbatim}\n\n\\noindent\nAgain, these pairs are frequently used to pass options to objects.\n\nA list may contain any object:\n\n\\begin{verbatim}\n[1,'a',true,[1,2,3]] \n\\end{verbatim}\n\n\\noindent\nMixing types in a list tends to be confusing and should be avoided. If you\nwant to group a set of diverse objects, define a class instead, \nsee \\pref{sec:class}.\n\nLists of lists of reals are useful for representing arrays.\n\nYou can use the list index operator (\\ct{?}) to extract an element from a\nposition in a list:\n\n\\begin{verbatim}\n[1,2,3] ? 0 == 1\n\"abc\" ? 1 == 'b'\n\\end{verbatim}\n\nYou can use the list join operator (\\ct{++}) to join two lists together\nend-to-end.\n\n\\begin{verbatim}\n[1,2,3] ++ [4,5,6] == [1,2,3,4,5,6]\n\\end{verbatim}\n\nYou can use the list difference operator (\\verb+--+) to remove elements of one \nlist from another.\n\n\\begin{verbatim}\n[1..10] -- [4,5,6] == [1,2,3,7,8,9,10]\n\\end{verbatim}\n\n\\subsection{The function type}\n\\mylabel{sec:func}\n\nFunctions are objects just like any other. You can pass functions to other\nfunctions as parameters, store functions in lists, and so on. \n\nYou can create anonymous functions with \\verb\"\\\" (lambda). For example:\n\n\\begin{verbatim}\nmap (\\x x + 2) [1..3] == [3, 4, 5]\n\\end{verbatim}\n\nYou can nest lambdas to make multi-argument anonymous functions, for example:\n\n\\begin{verbatim}\nmap2 (\\x\\y x + y) [1..3] [2..5] == \n  [3, 5, 7]\n\\end{verbatim}\n\nYou can compose functions with the \\ct{@} operator. For example, for two\nfunctions of one argument \\ct{f} and \\ct{g}:\n\n\\begin{verbatim}\nf (g 2) == (f @ g) 2\n\\end{verbatim}\n\n\\subsection{The image type}\n\nThese represent a low-level handle to a VIPS image structure. You can make\nthem with the \\ct{vips\\_image} builtin, and you can pass them as parameters to\nVIPS functions. The \\ct{Image} class is built on top of them,\nsee \\pref{sec:Image}.\n\nAs an accident of history, \\nip{} also lets you do arithmetic with them. This\nwill probably be removed in the next version or two, so it's best to go\nthrough the higher-level \\ct{Image} class.\n\n\\section{Lists and recursion}\n\\mylabel{sec:lists}\n\nFunctional programming languages do not have variables, assignment or\niteration. You can achieve the same effects using just lists and recursion.\n\nThere are two main sorts of recursion over lists. The first is called \n\\emph{mapping}: a function is applied to each element of a list, producing\na new list in which each element has been transformed.\n\n\\begin{verbatim}\nmap fn [a,b,c] == [fn a, fn b, fn c]\n\\end{verbatim}\n\nThe second main sort of recursion is called \\emph{folding}: a list is turned\ninto a single value by joining pairs of elements together with a function and\na start value.\n\n\\begin{verbatim}\nfoldr fn start [a,b .. c] == \n  (fn a (fn b (.. (fn c start))))\n\\end{verbatim}\n\n\\noindent\n(The function is called \\ct{foldr} as it folds the list up right-to-left.\nThere is an analogous function called \\ct{foldl} which folds a list up\nleft-to-right, but because of the way lists work, it is much slower and should\nbe avoided if possible.)\n\n\\ct{map} is defined in the standard list library for you:\n\n\\begin{verbatim}\n/* map fn l: map function fn over list l\n */\n\nmap fn l\n  = [], l == []\n  = fn (hd l) : map fn (tl l) \n\\end{verbatim}\n\n\\noindent\nSo, for example, you could use \\ct{map} like this:\n\n\\begin{verbatim}\nmap (add 2) [1..5] == [3,4,5,6,7,8]\n\\end{verbatim}\n\n\\ct{foldr} is defined in the standard list library for you:\n\n\\begin{verbatim}\n/* foldr fn st l: fold up list l, \n * right to left with function fn and \n * start value st\n */\n \nfoldr fn st l\n  = st, l == []\n  = fn (hd l) (foldr fn st (tl l)) \n\\end{verbatim}\n\n\\noindent\nSo, for example, you could use \\ct{foldr} like this:\n\n\\begin{verbatim}\nfoldr add 0 [1..5] == 15\n\\end{verbatim}\n\n\\noindent\n(Mathematically, \\ct{foldr} is the more basic operation. You can write\n\\ct{map} in terms of \\ct{foldr}, but you can't write \\ct{foldr} in terms of\n\\ct{map}.)\n\nUnconstrained recursion over lists can be very hard to understand, rather like\n\\ct{goto} in an imperative language. It's much better to use a combination of\n\\ct{map} and \\ct{foldr} if you possibly can.\n\nThe toolkit \\ct{\\_list} contains definitions of most of the standard\nlist-processing functions. These are listed in \\tref{tb:list}. Check the\nsource for detailed comments.\n\n\\begin{tab2}\n\\begin{center}\n\\begin{tabular}{||l|l||}\n\\hline\nName & Description \\\\\n\\hline\n\\ct{all l} \t\t& and all the elements of list \\ct{l} together \\\\\n\\ct{any l} \t\t& or all the elements of list \\ct{l} together \\\\\n\\ct{concat l} \t\t& join a list of lists together \\\\\n\\ct{drop n l} \t\t& drop the first \\ct{n} elements from list \\ct{l} \\\\\n\\ct{dropwhile fn l} \t& drop while \\ct{fn} is true \\\\\n\\ct{extract n l} \t& extract element \\ct{n} from list \\ct{l} \\\\\n\\ct{filter fn l} \t& all elements of \\ct{l} for which \\ct{fn} holds \\\\\n\\ct{foldl fn st l} \t& fold list \\ct{l} left-to-right with \\ct{fn} \n\t\t\t  and \\ct{st} \\\\\n\\ct{foldl1 fn l} \t& like \\ct{foldl}, but use the first element of the \n\t\t\t  list as the start value \\\\\n\\ct{foldr fn st l} \t& fold list \\ct{l} right-to-left with \\ct{fn} \n\t\t\t  and \\ct{st} \\\\\n\\ct{foldr1 fn l} \t& like \\ct{foldr}, but use the first element of the \n\t\t\t  list as the start value \\\\\n\\ct{index fn l} \t& search list \\ct{l} for index of first element \n\t\t\t  matching predicate \\ct{fn} \\\\\n\\ct{init l} \t\t& remove last element of list \\ct{l} \\\\\n\\ct{iterate f x} \t& repeatedly apply \\ct{f} to \\ct{x} \\\\\n\\ct{last l} \t\t& return the last element of list \\ct{l} \\\\\n\\ct{len l} \t\t& find length of list \\ct{l} \\\\\n\\ct{limit l}\t\t& find the first element of list \\ct{l} equal to\n\t\t\t  its predecessor \\\\\n\\ct{map fn l} \t\t& map function \\ct{fn} over list \\ct{l} \\\\\n\\ct{map2 fn l1 l2} \t& map 2-ary function \\ct{fn} over lists \\ct{l1}\n\t\t \t  and \\ct{l2} \\\\\n\\ct{map3 fn l1 l2 l3} \t& map 3-ary function \\ct{fn} over lists \\ct{l1},\n\t\t \t  \\ct{l2} and \\ct{l3} \\\\\n\\ct{member l x}\t\t& true if \\ct{x} is a member of list \\ct{l} \\\\\n\\ct{mkset eq l} \t& remove duplicates from list \\ct{l} with equality \n\t\t\t  function \\ct{eq} \\\\\n\\ct{postfix l r} \t& add element \\ct{r} to the end of list \\ct{l} \\\\\n\\ct{product l} \t\t& product of list l \\\\\n\\ct{repeat x} \t\t& make an infinite list of \\ct{x}es \\\\\n\\ct{replicate n x} \t& make \\ct{n} copies of \\ct{x} in a list \\\\\n\\ct{reverse l} \t\t& reverse list \\ct{l} \\\\\n\\ct{scan fn st l} \t& apply \\ct{(foldr fn r)} to every initial segment\n\t\t\t  of list \\ct{l} \\\\\n\\ct{sort l} \t\t& sort list \\ct{l} into ascending order \\\\\n\\ct{sortc fn l} \t& sort list \\ct{l} into order by using a comparison\n\t\t\t  function \\\\\n\\ct{sortpl pl l} \t& sort list \\ct{l} by predicate list \\ct{pl} \\\\\n\\ct{sortr l} \t\t& sort list \\ct{l} into descending order \\\\\n\\ct{split fn l} \t& break list \\ct{l} into sections separated by\n\t\t\t  predicate \\ct{fn} \\\\\n\\ct{splits fn l} \t& break list \\ct{l} into single sections separated by\n\t\t\t  predicate \\ct{fn} \\\\\n\\ct{splitpl pl l} \t& break list \\ct{l} up by predicate list \\ct{pl} \\\\\n\\ct{split\\_lines n l} \t& break list \\ct{l} into lines of length \\ct{n} \\\\\n\\ct{sum l} \t\t& sum list l \\\\\n\\ct{take n l} \t\t& take the first \\ct{n} elements from list \\ct{l} \\\\\n\\ct{takewhile fn l} \t& take from the front of \\ct{l} while \\ct{fn} holds \\\\\n\\ct{zip2 l1 l2} \t& zip two lists together \\\\\n\\ct{zip3 l1 l2 l3} \t& zip three lists together \\\\\n\\hline\n\\end{tabular}\n\\end{center}\n\\caption{Functions in the standard list-processing toolkit}\n\\mylabel{tb:list}\n\\end{tab2}\n\n\\section{Lazy programming}\n\\mylabel{sec:lazy}\n\n\\nip{}'s programming language is \\emph{lazy}, that is, it delays evaluation\nas long as it possibly can.  For example, \\ct{error} is a function which \nimmediately halts execution of your function and pops up an alert window. So:\n\n\\begin{verbatim}\n12 + error \"wombat!\"\n\\end{verbatim}\n\n\\noindent\nHas no value: this expression will halt with an error message. However:\n\n\\begin{verbatim}\nfalse && error \"lasagne!\"\n\\end{verbatim}\n\n\\noindent\nWill evaluate to \\ct{false}, since \\nip{} knows after looking at the\nleft-hand-side of \\ct{\\&\\&} that the result must be \\ct{false}, and so does\nnot evaluate the right-hand-side.\n\n\\begin{verbatim}\n[12, error \"hot chilli!\"] ? 0 == 12\n\\end{verbatim}\n\n\\noindent\nThis also evaluates completely, since the second element of the list is never\nused, and therefore never evaluates.\n\nThings become more confusing when you start calling functions, since the\narguments to a function call are also not evaluated until the function needs\nthat value. For example:\n\n\\begin{verbatim}\nfoldr (error \"boink!\") 2 [] == 2\n\\end{verbatim}\n\n\\noindent\nAgain, this evaluates successfully, since the function is never used by\n\\ct{foldr}.\n\n\\section{Pattern matching}\n\\mylabel{sec:pattern}\n\nAny time you define a name, you can use a pattern instead. For example:\n\n\\begin{verbatim}\n[fred, petra] = [12, 13]\n\\end{verbatim}\n\n\\noindent\ndefines \\ct{fred} to have the value 12 and \\ct{petra} to have the value 13.\n\nA pattern describes the structure you are expecting for the value. When the\nvalue is computed it is matched against the pattern and, if the match is\nsuccessful, the names in the pattern are bound to those parts of the value.\nOur example is exactly equivalent to:\n\n\\begin{verbatim}\ntemp = [12, 13];\nfred \n  = temp?0, is_list temp && \n      is_list_len 2 temp\n  = error \"pattern match failed\";\npetra \n  = temp?1, is_list temp && \n    is_list_len 2 temp\n  = error \"pattern match failed\";\n\\end{verbatim}\n\n\\noindent\nwhere \\ct{temp} is an invisible, anonymous symbol.\n\nYou can pattern match on any of \\nip{}'s data structures and types. You can\nuse:\n\n\\begin{description}\n\n\\item[\\ct{a:b}]\nTests for the value being a non-empty list and then assigns \\ct{a} to the\nhead and \\ct{b} to the tail.\n\n\\item[\\ct{(a,b)}]\nTests for the value being a complex and then assigns \\ct{a} to the\nreal part and \\ct{b} to the imaginary.\n\n\\item[\\ct{[a,b,c]}]\nTests for the value being a list of length three and then assigns \\ct{a},\n\\ct{b} and \\ct{c} to the three elements.\n\n\\item[\\ct{($class-name$ b)}]\nTests for the value being an instance of the named class, then assigns \n\\ct{b} to that class instance.\n\n\\item[\\ct{$constant$}]\nTests for the value being equal to that constant. Constants are things like\n\\ct{\"hello world\"} or \\ct{12}.\n\n\\end{description}\n\nYou can nest patterns in any way you like. Patterns are useful in conjunction\nwith list comprehensions, see \\pref{sec:listsyntax}.\n\nYou can't use patterns in function arguments in the current version, hopefully\nthis will added shortly.\n\n\\section{The standard libraries}\n\n\\nip{} comes with a lot of little utility functions. The functions for list\nprocessing are listed in \\tref{tb:list}. There are a huge number more, too\nmany to really list here. \\tref{tb:toolkits} lists all the utility toolkits\nwith some hints about the kinds of function they contain. Read the (heavily\ncommented) toolkits for details.\n\n\\begin{tab2}\n\\begin{center}\n\\begin{tabular}{||l|l|l||}\n\\hline\nToolkit & Contains & Description \\\\\n\\hline\n\\ct{\\_convert}\t\t& \\ct{parse\\_int l}, \\ldots{}  \t\t& \n\tconvert ascii text to numbers \\\\\n\t\t\t& \\ct{to\\_matrix x}, \\ldots{}  \t\t& \n\tconvert anything into a matrix \\\\\n\t\t\t& \\ct{colour\\_transform\\_to to x}, \\ldots{}\t& \n\tconvert between colour spaces \\\\\n\\hline\n\\ct{\\_generate}\t\t& \\ct{image\\_new w h ...}  \t\t& \n\tmake a blank image \\\\\n\t\t\t& \\ct{image\\_white i}  \t\t\t& \n\tlook at image \\ct{i}, try to guess what white is \\\\\n\t\t\t& \\ct{make\\_xy w h}  \t\t\t& \n\tmake an image of size \\ct{w} by \\ct{h} whose pixel value are \\\\\n\t\t\t& \t\t  \t\t\t& \n\ttheir coordinates \\\\\n\\hline\n\\ct{\\_types}\t\t& \\ct{Image i}  \t\t\t& \n\tall the standard classes and support functions, \\\\\n\t\t\t& \t\t  \t\t\t& \n\tsee \\pref{sec:object} \\\\\n\\hline\n\\ct{\\_predicate}\t& \\ct{is\\_colour\\_space i} \t\t& \n\ttest for objects are in various categories or have \\\\\n\t\t\t& \t\t  \t\t\t& \n\tvarious properties \\\\\n\\hline\n\\ct{\\_stdenv}\t\t& \\ct{logical\\_and x}, \\ldots{}\t\t& \n\tfunction versions of all the operators \\\\\n\t\t\t& \\ct{bandsplit i}, \\ldots{}\t\t& \n\tbreak up and recombine images by band \\\\\n\t\t\t& \\ct{mean x}, \\ldots{}\t\t\t& \n\tstatistical ops on objects \\\\\n\t\t\t& \\ct{transpose x}, \\ct{flipud x}, \\ct{rot90 x},\n\t\t\t\\ldots{} \t\t\t\t& \n\tflips, rotates, etc. on objects \\\\\n\t\t\t& \\ct{rad x}, \\ct{pi}, \\ldots{}\t\t& \n\ttrigonometry stuff \\\\\n\t\t\t& \\ct{sign x}, \\ct{conj x}, \\ct{polar x}, \\ldots{} & \n\tcomplex stuff \\\\\n\t\t\t& \\ct{rint x}, \\ct{ceil x}, \\ldots{}\t& \n\tvarious rounding things \\\\\n\t\t\t& \\ct{fwfft x}, \\ldots{}\t\t& \n\tfourier stuff \\\\\n\t\t\t& \\ct{dilate m x}, \\ct{rank w h n i}, \\ldots{} & \n\tmorphology stuff \\\\\n\t\t\t& \\ct{conv m x}, \\ldots{}\t\t& \n\tconvolution stuff \\\\\n\t\t\t& \\ct{image\\_set\\_type t i}, \\ldots{}  \t& \n\tset various image header field \\\\\n\t\t\t& \\ct{resize x y i}, \\ldots{}\t\t& \n\tresampling images \\\\\n\t\t\t& \\ct{recomb m i}, \\ldots{}\t\t& \n\trecombinations \\\\\n\t\t\t& \\ct{clip2fmt f i}, \\ldots{}\t\t& \n\tformat conversions \\\\\n\t\t\t& \\ct{hist\\_find m x}, \\ldots{}\t\t& \n\thistogram stuff \\\\\n\t\t\t& \\ct{id x}, \\ct{const x y}, \\ldots{} \t& \n\tvarious useful operations on functions \\\\\n\t\t\t& \\ct{map\\_binary fn x y},  \\ldots{} \t& \n\tmapping over groups \\\\\n\\hline\n\\end{tabular}\n\\end{center}\n\\caption{Useful utility functions --- see the source for details}\n\\mylabel{tb:toolkits}\n\\end{tab2}\n\n\\section{Classes}\n\\mylabel{sec:class}\n\nYou can define new types using \\ct{class}. For example:\n\n\\begin{verbatim}\nPasta_plain = class {\n  lasagne = \"large sheets\";\n  fusilli = \"sort of twisty\";\n  radiatori = \"lots of ridges\";\n}\n\\end{verbatim}\n\n\\noindent\nThis defines a new class called \\ct{Pasta\\_plain}. The class has three members\n(\\ct{lasagne}, \\ct{fusilli} and \\ct{radiatori}), each of which has a list of\n\\ct{char} as its value. By convention, we've named classes with an initial\ncapital letter, but of course you can do what you like.\n\nYou can refer to the members of a class using the class project (\\ct{.}) \noperator. For example:\n\n\\begin{verbatim}\nPasta_plain.lasagne == \"large sheets\"\n\\end{verbatim}\n\n\\noindent\nYou can use an expression to the right of \\ct{.} if you enclose it in\nbrackets. For example:\n\n\\begin{verbatim}\nPasta_plain.(\"las\" ++ \"agne\") == \n  \"large sheets\"\n\\end{verbatim}\n\nClasses can contain any objects as members, including functions and\nsub-classes. Functions may define local classes, classes may define local\nfunctions, and all may refer to each other using the usual scope rules. For\nexample:\n\n\\begin{verbatim}\nPasta_all = class { \n  filled = class { \n    tortelloni = \"venus' navel\";\n    ravioli = \"square guys\";\n  }\n  plain = Pasta_plain;\n}\n\\end{verbatim}\n\nWhen you define a class, \\nip{} adds a few extra members for you. \\ct{name}\nis a list of \\ct{char} giving the name of the class. \\ct{this} and\n\\ct{super} are the most-enclosing class instance and the class instance\nthis class is derived from (see \\pref{sec:inheritance}). \\nip{} also adds\na default constructor: a member with the same name as the class, pointing\nback to the class constructor. \n\nFor efficiency reasons \\nip{} does not allow mutual recursion at the top\nlevel. If two functions depend on each other, neither will ever be\ncalculated. For example:\n\n\\begin{verbatim}\na = 1 : b;\nb = 2 : a;\n\\end{verbatim}\n\n\\noindent\nNeither \\ct{a} nor \\ct{b} will have a value.\n\nYou can have mutual recursion between class members. For example:\n\n\\begin{verbatim}\nFred = class {\n  a = 1 : b;\n  b = 2 : a;\n}\n\\end{verbatim}\n\n\\noindent\nNow \\ct{Fred.a} will have the value \\ct{[1, 2, 1, 2, 1, \\ldots{}]}.\n\n\\subsection{Parameterised classes}\n\nClasses can have parameters. Parameters behave like class members initialised\nfrom arguments to the class constructor. For example:\n\n\\begin{verbatim}\nMy_pasta pasta_name cooked = class {\n  is_ready t = \"your \" ++ \n    pasta_name ++ \" is \" ++ state\n  {\n    state\n      = \"underdone!\", t < cooked\n      = \"perfect\", t == cooked\n      = \"yuk!\";\n  }\n}\n\\end{verbatim}\n\n\\noindent\nThis defines a class called \\ct{My\\_pasta} which takes a pasta name\nand a cooking time as parameters. Once you have made an instance of\n\\ct{My\\_pasta}, you can test if it's been cooked at a certain time with the\n\\ct{is\\_ready} member. For example:\n\n\\begin{verbatim}\ntele = My_pasta \"telephoni\" 10;\ntele.is_ready 5 == \n  \"your telephoni is underdone!\"\n\\end{verbatim}\n\n\\subsection{Inheritance}\n\\mylabel{sec:inheritance}\n\nClasses can inherit from a super-class. For example:\n\n\\begin{verbatim}\nPasta_more = class Pasta_plain { \n  macaroni = \"tubes\";\n  spaghetti = \"long and thin\";\n  lasagne = \"fairly large sheets\";\n}\n\\end{verbatim}\n\n\\noindent\nHere the new class \\ct{Pasta\\_more} inherits members from the previous class\n\\ct{Pasta\\_plain}. It also overrides the definition of \\ct{lasagne} from\n\\ct{Pasta\\_plain} with a new value. For example:\n\n\\begin{verbatim}\nPasta_more.macaroni == \"tubes\"\nPasta_more.fusilli == \"sort of twisty\"\nPasta_more.lasagne == \"fairly large sheets\"\n\\end{verbatim}\n\nYou can use \\ct{this} and\n\\ct{super} to refer to other members up and down the class hierarchy.\n\\ct{super} is the class instance that the current class inherits from (if\nthere's no super-class, \\ct{super} has the value \\ct{[]}), and\n\\ct{this} is the most-enclosing class instance. \n\n\\begin{verbatim}\nPasta_more.super == Pasta_plain\nPasta_more.this == Pasta_more\nPasta_more.super.this == Pasta_more \n\\end{verbatim}\n\n\\noindent\ntherefore:\n\n\\begin{verbatim}\nPasta_more.lasagne == \"fairly large sheets\"\nPasta_more.super.lasagne == \"large sheets\"\nPasta_more.super.this.lasagne ==\n  \"fairly large sheets\" \n\\end{verbatim}\n\nThere's a special symbol \\ct{root} which encloses all symbols. For\nexample:\n\n\\begin{verbatim}\nfred = 12; \n\nFreddage = class { \n  fred = 42;\n  mystery = root.fred;\n}\n\\end{verbatim}\n\n\\noindent\nNow \\ct{Fred.mystery} will have the value 12.\n\nThere's another special symbol called \\ct{scope} which encloses all symbols in\nthe file this definition was loaded from. If you want to refer to another\ndefinition in the same file which is being masked somehow, use \\ct{scope}.\n\nYou can use the built in function \\ct{is\\_instanceof} to test whether an\ninstance is or inherits from a class. For example:\n\n\\begin{verbatim}\nis_instanceof \"Pasta_more\" Pasta_more == true\nis_instanceof \"Pasta_plain\" Pasta_more == true\nis_instanceof \"Pasta_more\" Pasta_plain ==\n  false\n\\end{verbatim}\n\nThe super-class constructor can take arguments, and these arguments can refer\nto class members. For example:\n\n\\begin{verbatim}\nFresh_pasta pasta_name = class\n  My_pasta pasta_name cooked {\n  cooked = 2;\n}\n\\end{verbatim}\n\n\\noindent\nDefines a class for fresh pasta, which always cooks in 2 minutes. You need to\nbe careful not to make loops: if \\ct{cooked} did tried to refer to\nsomething in the super-class, this class would never construct properly.\n\\nip{} unfortunately does not check for this error.\n\nFinally, the superclass can be a fully constructed class. In this case, the\nsuperclass is cloned and the new class members wrapped around it. You can use\nthis to write a class which can wrap any other class and add members to it.\nMany of the toolkit menu items use this trick to enable them to work for any\nobject type.\n\n\\subsection{Minor class features}\n\nThere are a couple of other things you can do with classes. You can define a\nspecial member called \\ct{\\_check}. If this member is defined, then when a\nclass instance is created, the check member is returned instead of the class\nitself. You can use this to implement class argument type checks, for example:\n\n\\begin{verbatim}\nFred a b = class { \n  _check\n    = this, is_real a && is_real b\n    = error \"args to Fred must \" ++\n      \"both be real\"\n}\n\\end{verbatim}\n\n\\noindent\nDefines a class called \\ct{Fred} which has to have two real numbers as\narguments.\n\nYou can define members called \\ct{oo\\_binary}, \\ct{oo\\_binary'} and\n\\ct{oo\\_unary} and do operator overloading. When \\nip{} sees one of the\nstandard operators being used on an instance of your class, it will look up\none of these members and pass in the name of the operator and the argument.\nThe two forms of the binary operator member are called for the class-on-left\nand the class-on-rights cases. So:\n\n\\begin{verbatim}\nx = Fred 1 2\nx + 12 == x.oo_binary \"add\" 12\n12 + x == x.oo_binary' \"add\" 12\n!x == x.oo_unary \"negate\" \n\\end{verbatim}\n\nThese two features are very primitive. The \\ct{\\_Object} class in the\n\\ct{\\_types} toolkit builds on these to provide a fairly high-level system for\nchecking class arguments and defining the meaning of operators.\nSee \\pref{sec:object}.\n\n\\section{Controlling the interface}\n\\mylabel{sec:bowser}\n\n\\nip{} looks at the scraps of program you type in and execute and tries to\nshow them on the screen in a graphical way. The sorts of display you get\ndepend on where in \\nip{} you define the expression, and what sort of value it\nhas.\n\n\\subsection{Tools and toolkits}\n\\mylabel{sec:tools}\n\nDefinitions in toolkits are turned into menus off the \\ct{Toolkits} menu\nin the main window, and added to the toolkit browser. Toolkits are loaded\nfrom files at startup or can be made in the program window.\nToolkit or a definition names which start with\nan underscore character are hidden and not displayed. The toolkits are always\ndisplayed in alphabetical order, but you can order the items within a toolkit\nin any way you like. \n\nThere are two ways to write toolkit definitions. Function definitions and\nzero-argument classes simply appear as menu items, built from static analysis\nof their source code. However, if a definition evaluates to an instance of the\nclass \\ct{Menu}, a menu item is built from dynamic analysis of the value of\nthe definition.\n\n\\subsubsection{Static menu items}\n\nZero-argument classes within toolkits are displayed\nas pull-right menus. You can nest classes to any depth. \n\n\\nip{} uses the first line of the comment before a definition as\nhelp text for that function, so it's a good idea to put a simple one-line\ndescription of the function at the start of a comment.\n\nFor example, if the following text is placed in a file called \\ct{Fred.def}\non \\nip{}'s start path, you'll get a menu in the tookits called \\ct{Fred} with\na pull-right and a tooltip. See \\fref{fg:toolkit}.\n\n\\begin{verbatim}\nBanana a = a * 3;\n\nSubfred = class { \n  // add two things\n  Jim a b = a + b;\n  Apple e = e * 12;\n  Harry z = 12 + z;\n}\n\\end{verbatim}\n\n\\begin{figure}\n\\figw{2.5in}{toolkit.jpg}\n\\caption{How \\ct{Fred.def} will look}\n\\mylabel{fg:toolkit}\n\\end{figure}\n\n\\subsubsection{Dynamic menu items}\n\nDynamic menus give you much more control over the way menus are drawn and make\nit easy to reuse menus. A dynamic menu item is a class instance that is a\nsub-class of \\ct{Menuitem}. It needs to have three members: \\ct{label}, the\ntext that should appear in the menu (with an underscore character to indicate\nthe mnenonic); \\ct{tooltip}, a short hint that appears as a tooltip or in\nthe toolkit browser; \\ct{icon}, an optional image file to be displayed in the \nmenu next to the text; and \\ct{action}, the function that is called when\nthe menu item is activated. \\ct{label} and \\ct{tooltip} are constructor\narguments for \\ct{Menu}.\n\nSo for example:\n\n\\begin{verbatim}\nWombat_find_item = class Menuitem\n  \"_Find Wombat\"\n  \"analyse image and locate wombat\" {\n  icon = \"nip-slider-16.png\";\n  action x = im_wombat_locate x;\n}\n\\end{verbatim}\n\n\\noindent\nwill appear as shown in \\fref{fg:toolkit2}.\n\n\\begin{figure}\n\\figw{2.5in}{toolkit2.jpg}\n\\caption{How \\ct{Wombat\\_find\\_item} will look}\n\\mylabel{fg:toolkit2}\n\\end{figure}\n\nA dynamic pullright menu is a subclass of \\ct{Menupullright}. It's just like\n\\ct{Menuitem}, but without the need for an \\ct{action} member. Any members\nwhich are subclasses of \\ct{Menu} are displayed as items in the submenu. So\nagain:\n\n\\begin{verbatim}\nWombat_item = class Menupullright\n  \"_Wombat\"\n  \"wombat-related operations\" {\n  icon = \"nip-slider-16.png\";\n  item1 = Wombat_find_item;\n  sep = Menuseparator;\n  boink = Wombat_find_item;\n}\n\\end{verbatim}\n\n\\noindent\nwill appear as shown in \\fref{fg:toolkit3}.\n\n\\begin{figure}\n\\figw{2.5in}{toolkit3.jpg}\n\\caption{How \\ct{Wombat\\_item} will look}\n\\mylabel{fg:toolkit3}\n\\end{figure}\n\n\\subsection{Workspaces}\n\\mylabel{sec:workspaces}\n\nDefinitions in workspaces are displayed with \\nip{}'s class browser. Each row\nis displayed in four main parts: a button for the row name, a line of text,\na set of sub-rows for the members of the row's class, and a graphic display\nrepresenting the row's value. See \\fref{fg:row2}.\n\n\\begin{figure}\n\\figw{2.5in}{ir8a.jpg}\n\\caption{Components of a workspace row}\n\\mylabel{fg:row2}\n\\end{figure}\n\nThe text part of the right-hand-side of each row is always displayed, but the\nsub-rows are only displayed if the row represents a class, and the graphic is\nonly displayed if the class is an instance of one of the classes in\n\\tref{tb:classes}. You can subclass these if you want to use the graphic\ndisplay in your own widgets.\n\nThere are three separate ways to set the value for a row. You can\nedit the line of program text, you can edit one of the members, or you can\nmanipulate the graphic representation (dragging a slider, or moving a region).\nThese can be contradictory, so \\nip{} resolves conflicts by always applying\nchanges in the order text, then graphic, then member. \n\nWhen it applies a graphic change, \\nip{} rebuilds the class using a class \nmember called \\emph{class-name}\\ct{\\_edit}, or if that is not defined, the\nclass's constructor member. For example, the \\ct{Colour} class can be defined\nas:\n\n\\begin{verbatim}\nColour colour_space value = class {}\nA1 = Colour \"sRGB\" [255,0,0];\n\\end{verbatim}\n\n\\noindent\nThere are two ways to change \\ct{A1}. You can open \\ct{A1} and change\n\\ct{colour\\_space} to \\ct{\"Lab\"}, or you can double-click on the swatch\nand drag the disc. When you click \\ct{OK} on the colour edit dialog, \\nip{}\nsearches for a member called \\ct{Colour\\_edit}, fails to find it, and so\npicks the \\ct{Colour} member instead (the default constructor generated by\n\\nip{}). It then replaces the value of A1 with\n\n[needs finishing]\n\n\\begin{tab2}\n\\begin{center}\n\\begin{tabular}{||l|l||}\n\\hline\nClass & Description \\\\\n\\hline\n\\ct{Clock \\emph{interval} \\emph{value}}\t\t\t\t& \n\tA clock widget, handy for animations \\\\\n\\ct{Expression \\emph{caption} \\emph{expr}}\t\t\t& \n\tDisplays an editable expression \\\\\n\\ct{Group \\emph{value}}\t\t\t\t\t\t& \n\tA group of objects for iteration \\\\\n\\ct{List \\emph{value}}\t\t\t\t\t\t& \n\tA list of related objects \\\\\n\\ct{Pathname \\emph{caption} \\emph{value}}\t\t\t& \n\tDisplays a file browser \\\\\n\\ct{Fontname \\emph{caption} \\emph{value}}\t\t\t& \n\tDisplays a font browser \\\\\n\\ct{Toggle \\emph{caption} \\emph{value}}\t\t\t\t& \n\tA toggle switch \\\\\n\\ct{Scale \\emph{caption} \\emph{from} \\emph{to} \\emph{value}}\t& \n\tA slider \\\\\n\\ct{Option \\emph{caption} \\emph{labels} \\emph{value}}\t\t& \n\tSelect one item from a list \\\\\n\\ct{Colour \\emph{colour\\_space} \\emph{value}}\t\t\t& \n\tA patch of colour \\\\\n\\ct{Matrix\\_vips \\emph{value} \\emph{scale} \\emph{offset} \\emph{filename} \n\t\\emph{display}}\t\t\t\t\t\t& \n\tA matrix \\\\\n\\ct{Arrow \\emph{image} \\emph{left} \\emph{top} \\emph{width} \\emph{height}} & \n\tTwo points joined by a line on an image \\\\\n\\ct{Region \\emph{image} \\emph{left} \\emph{top} \\emph{width} \\emph{height}} & \n\tA sub-area of an image \\\\\n\\ct{Plot \\emph{options} \\emph{value}}\t\t\t\t& \n\tDisplays a plot widget \\\\\n\\ct{Image \\emph{value}}\t\t\t\t\t\t& \n\tAn image \\\\\n\\ct{Number \\emph{caption} \\emph{value}}\t\t\t\t& \n\tDisplays an editable number \\\\\n\\ct{Real \\emph{value}}\t\t\t\t\t\t& \n\tDisplays a real number \\\\\n\\ct{Vector \\emph{value}}\t\t\t\t\t& \n\tDisplays a list of reals \\\\\n\\ct{String \\emph{caption} \\emph{value}}\t\t\t\t& \n\tDisplays an editable string \\\\\n\\ct{Mark \\emph{image} \\emph{left} \\emph{top}} \t\t\t& \n\tA point on an image \\\\\n\\ct{HGuide \\emph{image} \\emph{top}} \t\t\t\t& \n\tA horizontal line on an image \\\\\n\\ct{VGuide \\emph{image} \\emph{left}} \t\t\t\t& \n\tA vertical line on an image \\\\\n\\ct{Area \\emph{image} \\emph{left} \\emph{top} \\emph{width} \\emph{height}} & \n\tA sub-area of an image, fixed in size \\\\\n\\hline\n\\end{tabular}\n\\end{center}\n\\caption{\\nip{} built in graphic classes}\n\\mylabel{tb:classes}\n\\end{tab2}\n\n\\subsection{The \\ct{Image} class}\n\\mylabel{sec:Image}.\n\nsay supports mixed ops with real, vector and complex constants \n\n\\subsection{The \\ct{Colour} class}\n\\mylabel{sec:colour}\n\nThis class displays a swatch of colour. If you double-click on the\n\n\\begin{verbatim}\nPathname caption value = class {}\n\\end{verbatim}\n\n\\section{The \\ct{\\_Object} class}\n\\mylabel{sec:object}\n\n\\section{Optimisation}\n\\mylabel{sec:optimise}\n\n\\nip{} performs three useful optimisations on expressions. First, it finds and\nremoves common sub-expressions in functions. So for example:\n\n\\begin{verbatim}\nif a + b < 12 then a + b else b\n\\end{verbatim}\n\n\\noindent\nwill only evaluate \\ct{a + b} once. This can save a lot of time if \\ct{a} or\n\\ct{b} is a large image. \n\nSecond, \\nip{} detects arithmetic operations on \\ct{unsigned char} images, and\nreplaces them with look-up tables. For example:\n\n\\begin{verbatim}\na = vips_image \"campin.v\"\nb = a * (a - 1) ** 0.5\n\\end{verbatim}\n\n\\noindent\nProvided \\ct{campin.v} is an 8 bit image image, this expression will\nevaluate with a single call to \\ct{im\\_maplut()}.\n\nFinally, \\nip{} has a VIPS operation cache. It memorises the arguments to the \nlast few hundred calls to VIPS, and the result each call gave. Before calling\nVIPS again, it checks to see if there is a previous call with the same\narguments and if there is, uses the result it obtained last time.\n\n\\section{Calling VIPS functions}\n\\mylabel{sec:callvips}\n\nYou can call any VIPS operation which has the following properties:\n\n\\begin{itemize}\n\n\\item\nThere must be at least 1 output argument. If there's a single output argument,\nthat becomes the value of the function. If there is more than one output, then\nthe function returns a list with the outputs as members.\n\n\\item\nThe output arguments must all be one of:\n\n\\begin{itemize}\n\\item \\verb+IM_TYPE_DOUBLE+, \n\\item \\verb+IM_TYPE_INT+, \n\\item \\verb+IM_TYPE_COMPLEX+, \n\\item \\verb+IM_TYPE_STRING+, \n\\item \\verb+IM_TYPE_IMAGE+, \n\\item \\verb+IM_TYPE_DOUBLEVEC+, \n\\item \\verb+IM_TYPE_DMASK+, \n\\item \\verb+IM_TYPE_IMASK+\n\\end{itemize}\n\n\\item\nThe input arguments must all be one of the types above, or\n\\verb+IM_TYPE_DISPLAY+. If an argument is an input display, \\nip{} passes in\nits current display structure, it does not take a display from your program.\n\n\\end{itemize}\n\nWhen \\nip{} starts up, it loads any VIPS plug ins it can find on its data\nsearch path. You can call functions from plug ins in just the same way. For\ninformation on writing plug ins, see the \\emph{VIPS Manual}.\n\n"
  },
  {
    "path": "doc/src/reference.tex",
    "content": "\\chapter{Reference}\n\\mylabel{sec:reference}\n\n\\noindent\nThis chapter is supposed to be a user-interface reference.\n\\cref{sec:menus} describes the items in the \\ct{Toolkits} menu\nand \\cref{sec:program} is the programming language \nreference. \\cref{sec:tutorial} has a tutorial-style introduction.\n\n\\section{Image view window}\n\\mylabel{sec:view}\n\n\\fref{fg:imageview} shows \\nip{}'s image view window with all the toolbars\nturned on.\n\nIf you press \\ct{i} (or \\ct{+}) with the keyboard focus on the image\nyou will zoom in on the pixel your mouse pointer is over. Press \\ct{o}\n(or \\ct{-}) to zoom out again, or press the number keys \\ct{1}, \\ct{2},\n\\ct{4} and \\ct{8} to jump straight to a particular magnification. If you\nhold down the Ctrl key while pressing these numbers, \\nip{} will zoom\nout by that amount. If you press \\ct{0} (the number zero), then \\nip{}\nwill pick a magnification or reduction which fits the image to the size\nof the window.\n\nWhen the image is too large for the window, you can use the scroll bars\nto move about the image. With the keyboard focus on the image the cursor\nkeys left, right, up and down move a few pixels in each direction; hold down\nShift as well to move a screenful at a time; hold down Ctrl as well to jump\nto the extreme edges of the image. \n\nYou can also drag with the middle mouse button to pan around the image. Use\nthe mousewheel to pan up and down, hold down Shift and the mousewheel to\npan left and right.  Use Ctrl and the mousewheel to zoom in and out.\n\nUse the \\ct{View} menu to add extra elements to the window.  You can turn\nthe status bar on and off, and you can add a display control bar, a paintbox\nand a set of rulers to the window. \n\n\\begin{fig2}\n\\figw{6in}{ir2.jpg}\n\\caption{The display control bar}\n\\mylabel{fg:scr3}\n\\end{fig2}\n\nIf you select \\ctr{View}\\ctr{Toolbar}\\ct{Display Control}, \\nip{} will add a\nbar to the top of the window which you can use to change the contrast and\nbrightness of the image you are viewing. The left-hand slider and text box\nset the gain for the image: each pixel is multiplied by this amount\nbefore display. The right-hand slider and text box set the offset:\neach pixel has this value added to it before display. This is useful\nfor boosting the brightness in dark areas of images.\n\n\\begin{figure}\n\\figw{1.5in}{ir3.jpg}\n\\caption{The display control bar menu}\n\\mylabel{fg:scr4}\n\\end{figure}\n\nIf you click the left mouse button on the arrow to the left of the display \ncontrol bar, \\nip{} pops up a menu of useful display functions ---\nsee \\fref{fg:scr4}.\n\n\\ct{Scale} searches the area of the image you are viewing for the darkest\nand brightest points and chooses settings for the gain and offset sliders\nwhich will stretch the image to use the full range of your screen. \\ct{False\ncolour} tries to make small differences in brightness more visible by\ncolour-coding them.\n\nIf \\ct{Interpret} is turned on (it is by default), then \\nip{} will look\nat the \\ct{Type} field in the image header, and use that as a hint when\ntransforming the image to a viewable form for you. This is usually the\nbehaviour you want.  \\ct{Reset} moves the sliders back to the default\npositions of 1.0 and 0.0. \\ct{Set As Workspace Default} makes the current\ndisplay bar settings the default for all new image windows in this workspace.\nFinally, \\ct{Hide} removes this display control\nbar.\n\nIf you select \\ctr{View}\\ctr{Toolbar}\\ct{Rulers}, \\nip{} will add rulers to the\nedges of the window which you can use to measure numbers of pixels.\nIf you left-drag from the ruler, you can create a guide.\nGuides are useful for lining up other things in the view window, and also\naffect paint box actions. A right-button menu on the rulers lets you use a mm\nscale rather than a pixel scale, and controls whether the \\ct{Xoffset} and\n\\ct{Yoffset} header fields are used.\n\n\\mylabel{sec:paintbox} \nIf you select \\ctr{View}\\ctr{Toolbar}\\ct{Paint}, \\nip{} adds a paint bar\nto the top of the window. You can use the paint bar to do simple edits to\nthe image being displayed. See \\fref{fg:paint}.\n\nWhile the paint bar is very limited, it does have two useful features. First,\nit can paint with any pixel value, even complex numbers. For example you can \ntake the fourier transform of an image and paint out the peaks. Secondly, it \ndoesn't operate on a memory copy of an image, it operates directly on the \nfile on disc. This means that you can paint very quickly on images of any \nsize, but it does make the paint bar a bit dangerous.\n\nNormally paint actions are live, that is, every time you paint something all\nthe objects which depend on the thing you painted will recalculate. This can\nsometimes cause annoying delays: there's a preferences option to turn off\nautomatic recalculations for the paint bar.\n\n\\begin{fig2}\n\\figw{6in}{ir4.jpg}\n\\caption{The paint bar}\n\\mylabel{fg:paint}\n\\end{fig2}\n\nThe \\ct{Undo} and \\ct{Redo} buttons move forward and back though paint\nactions. The \\ct{Clear} button wipes the undo/redo history (useful if memory\nis getting low). There's an option in the preferences workspace which controls\nthe number of undo steps \\nip{} tracks.\n\nThe slider sets the nib diameter for drawing operations, the black square is\nthe current ink colour (you can drag and drop colour, or pixel values, from \nother parts of \\nip2{}), and the text box at the far right is the text that\nwill be drawn by the text tool. The paint tools will `snap' to guides, points\nand regions, so you can line things up easily. \n\nYou can mark regions on images by holding down Ctrl and dragging down and\nright with the left mouse button.  You can move the region about by dragging\non the label with the left mouse button; you can resize it by dragging with\nthe left mouse button in the border; you can get a useful context menu by\nright-clicking on the label; and you can pop up a box which will let you\nedit the region numerically by double-left-clicking on the label.  \n\nIf you drag up and left, you will make an \\emph{arrow}.  If you hold down Ctrl\nand just click the left mouse button, you will make a \\emph{point}. If you\ndrag from a horizontal or vertical ruler, you'll make a \\emph{guide}. Guides\nare useful for lining up other things in the view window.\n\n\\ctr{View}\\ct{Image Header} shows the image metadata and history. Use the\nsearch box to filter large metadata sets. \n\nThe \\ct{File} menu contains two useful items: select \\ct{Replace\nImage} to change the image which is being displayed in the window (you can\nalso drag and drop new images in). Select\n\\ct{Save Image} to save the image you are viewing to a file. See\n\\pref{sec:loadsave} for details on \\nip{}'s load and save dialogs. \nUse \\ctr{File}\\ct{New} to make regions, points, arrows and guides without\nthe mouse.\n\n\\section{File select dialogs}\n\\mylabel{sec:loadsave}\n\nOn most platforms you can drag files from your file manager directly to\n\\nip{}'s main window.  Alternatively, if you select \\ctr{File}\\ct{Open}\nin the main window, \\nip{} will pop up a file dialog, see\n\\fref{fg:open}. The open dialog has the following extra features:\n\n\\begin{figure}\n\\figw{2in}{ir5.jpg}\n\\caption{Open dialog}\n\\mylabel{fg:open}\n\\end{figure}\n\n\\begin{description}\n\n\\item[Pin up button]\nNormally the file dialog closes after you have opened something.\nIf this item is checked, the dialog will stay up instead --- this is useful\nif you want to load or save a series of objects.\n\n\\item[Image type select]\nUse this menu to select the type of file you want \\nip{} to display.\nThere's a preference option to set the default image format.  The VIPS\nfile format is fast and accurate, but sadly not very widely supported\n(joke). You can also load and save images in TIFF, JPEG, PNG, HDR, CSV and\nPBM/PGM/PPM formats. You can usually load in many more formats, it depends\nhow your \\nip{} has been configured.\n\n\\item[Image info]\nThis displays a one-line summary of the selected image, plus a large\nthumbnail. \n\n\\end{description}\n\nThe save dialog adds one extra feature: \\ct{Increment filename}.\n\nIf pin up and increment are both selected, then after a save \\nip{} will\nattempt to add one to the selected file name. For example, if you save a file\ncalled \\ct{fred001.v}, after the save \\nip{} will put the name \\ct{fred002.v}\ninto the selected file name box. Again, this is useful if you want to save\na series of images.\n\n\\section{Image processing window}\n\\mylabel{sec:ipwindow}\n\n\\fref{fg:startup} shows \\nip{}'s main image processing window. The centre\narea is the workspace, the left-hand area is a pane you can reveal to write\ncustom definitions for this workspace (see \\ctr{View}\\ct{Workspace\nDefinitions}), and the right-hand pane is the toolkit browser (see\n\\ctr{View}\\ct{Toolkit Browser}).\n\nDrag with the middle mouse button to scroll the workspace window. Drop a file\non to the workspace background (from your file manager) to load that file.\nIf you right-click on the workspace background, a useful menu will appear.\n\n\\begin{figure}\n\\figw{3in}{ir7.jpg}\n\\caption{\\nip{}'s main image processing window}\n\\mylabel{fg:startup}\n\\end{figure}\n\n\\begin{description}\n\n\\item[Workspace]\nA workspace is split into a set of separate tabs. Right-click on a tab to get\na useful menu. Press the add icon at the right to make a new tab. You can drag\ntabs between workspaces, or drag a tab to the desktop to make a new workspace. \nUse the syntax \\ct{tab1.A1} to make references between tabs.\n\n\\item[Tab]\nThis area displays the current tab.\nTabs are divided into columns of\nobjects which each behave rather like windows: they can be moved around,\nfolded away, loaded, saved and deleted. \n\n\\item[Current column]\nOne column is the current column. This is the column to\nwhich all new objects are added. Single-left-clicking on the title bar of\na column makes that the current column. See \\pref{sec:column}.\n\n\\item[File, Edit, View]\nUse the \\ct{File} menu to create or save work\\-spaces, to open workspaces\nor load other objects into this workspace, to merge workspaces and to search\nfor workspace backups.  Use the \\ct{Edit} menu to select, group, delete and\nduplicate sets of objects.  Use \\ct{View} to show and hide elements of the\nmain window, and to set the object view mode.\n\n\\item[Toolkits]\nThis menu contains all of the image processing functions which are currently\nloaded into \\nip{}. They are generally grouped by object type: all of the\noperations on matricies are under \\ctr{Toolkits}\\ct{Matrix}, for example.\n\nIf you select one of these image processing operations, \\nip{} will apply\nthat operation to the bottom few items in the current column (however many are\nnecessary --- two items for \\ctr{Math}\\ctr{Arithmetic}\\ct{Add}, for example),\nor alternatively, if you have selected some objects explicitly, it will try\nto apply the operation to the selected objects. See \\pref{sec:apply}. As\nyou move the mouse pointer over menu items \\nip{} tries to display some\nhelpful information about the operation, including the number and type of\narguments the operation expects.\n\n\\item[Toolkit Browser]\nThis side panel shows all the image processing operations again, but this time\nas a large flat list you can easily browse. Type into the search box at the\ntop to filter operations by keyword. Doubleclick on an item to activate it.\n\n\\item[Tab Definitions]\nThis side pane shows private definitions for this tab. Programs you\nwrite here are loaded and saved with this workspace. See the Programming\nchapter for details on \\nip{}'s programming language.\n\n\\item[Free space]\nThis displays the amount of disc space you have left in your temporary\nfile area. See \\pref{sec:config} if you want to change the directory \\nip{}\nuses to store temporary files.\n\nIf you left-click on the label, it changes to display the space \\nip{} has\nfree internally for performing calculations. You can change this limit in the\n\\ct{Preferences} workspace. Click again to switch back to disc free.\n\nIf you have objects selected, this area changes to show the\nnames of the selected objects.\n\n\\item[Status bar]\nAs you move the mouse pointer about the window, this bar tries to display\nuseful information about the thing you are pointing at. \n\n\\end{description}\n\n\\subsection{Columns}\n\\mylabel{sec:column}\n\nColumns are split into a number of areas:\n\n\\begin{description}\n\n\\item[Column name]\nEach column has a name. You can pick any name you like when you make a new\ncolumn with \\ctr{File}\\ctr{New}\\ct{Column}. There's no way to rename a column,\nunfortunately. Objects in the column are named using the column name,\nplus a number.\n\n\\item[Column title bar]\nDrag with the left mouse button held down on the column title bar to move\nthe column around the workspace. Double-left-click on the title bar to\nchange the comment attached to the column. Hold down the right mouse button\non the column title bar to pop up a useful menu. \n\nThe items in the menu let you edit the caption, select all the objects\nin the column, make a new column which is a copy of this column, save the\ncolumn to a file, convert the column into a menu item\n(see \\pref{sec:diaref}) and remove the whole column.\n\n\\item[Column fold button]\nLeft-clicking on the fold button folds the column away. Use this to hide\ncolumns which you still need, but which you are not interested in just now.\n\n\\item[Expression entry]\nYou can perform calculations by typing expressions directly into this box. For\nexample, try entering the following expressions, and pressing Return:\n\n\\begin{verbatim}\n2 + 2\nA1 + 120\n\"My cat likes\\nlasagne\"\nfred = 12\n\\end{verbatim}\n\n\\noindent\nThe last example shows custom button name creation. Normaly \\nip{} will pick a\nname for you, but you can chose your own.\n\n\\end{description}\n\n\\subsection{Rows}\n\\mylabel{sec:row}\n\nA column holds a number of rows. Each row comes in four main parts, not all of\nwhich are visible for all row values. Rows which represent classes have a pair\nor up/down arrows to the left of the row name button which you can use to\ncontrol which parts of the row are visible.\n\n\\begin{figure}\n\\figw{1.5in}{ir8a.jpg}\n\\caption{Components of a workspace row}\n\\mylabel{fg:row}\n\\end{figure}\n\n\\begin{description}\n\n\\item[Row name button]\nEach row has a name. The name is normally formed from the name of the current\ncolumn, plus a number.\n\nIf you double-left-click on the row name button, \\nip{} will pop up a viewer\nor dialog box for the value of the row. If you left-click, \\nip{} will select\nthat row and deselect all other rows. If you click on an empty space\nin the workspace, it will deselect all rows. If you\nCtrl-left-click, \\nip{} will toggle selection of that row.  \nIf you select one row and then Shift-left-click on\nanother row in the same column it will select the second row and\nall the rows in between. If you drag with the left button, you can change\nthe order of rows in a column.  Hold down the right mouse button for a useful\nmenu. If you let the mouse linger over a button, a useful tooltip will appear.\n\n\\item[Graphic]\nIf the row's value is a class, and if the class is an instance of one of\n\\nip{}'s graphic classes, then \\nip{} will draw a graphic representation of\nthe row's value. See \\pref{sec:workspaces} for a more detailed explanation.\n\n\\item[Members]\nIf the row has a class for a value, then \\nip{} will draw a sub-column listing\nthe class members. Subcolumn members are in turn rows themselves.\n\n\\item[Text]\nFinally, the text part normally shows a text representation of the row's\nvalue. If you left-click on the value, it changes to show the formula which\ngenerated that value. You can edit the formula and press Return to change it.\n\nAlternatively, selecting \\ctr{View}\\ct{Show Formula} toggles \nbetween displaying values for objects and displaying the formula.\n\n\\end{description}\n\n\\subsubsection{Object name colours}\n\n\\nip{} changes the background colour of the row name button to show the state\nof the row. If background colours are not visible (perhaps your theme turns\nthem off), try turning on the \\ct{Display LEDs in workspace} option in\n\\ct{Preferences}.\n\nGreen means the row is selected (click on the background to unselect), red\nindicates an error (right-click on the row button ans select \\ct{Recalculate}\nto see the full text of the error), brown indicates that the row value is out \nof date and needs recalculating and the various blues indicate parent and\nchild relationships.\n\n\\subsection{Applying operations to objects}\n\\mylabel{sec:apply}\n\nThere are three ways you can apply image processing operations to objects\nin your workspace:\n\n\\begin{enumerate}\n\n\\item\nSelect the object you want to apply the operation to by single-left-clicking\non the object name. When you single-click, the object name will change\ncolour to show that it is selected, and \\nip{} will display the name of\nthe selected object at the left end of the status bar (this is\nuseful if the selected object is scrolled off the edge of the window).\n\nYou can select additional objects with Ctrl-left-click and\nShift-left-click. This is necessary if you want to use an image\nprocessing operation that takes more than one argument.\n\nOnce you have selected the rows (sometimes you need to select them in\na certain order), click on the processing operation you want from the\n\\ct{Toolkits} menu.\n\n\\item\nIf there are no objects selected when you click on an image processing\noperation, \\nip{} uses the bottom few items (as many as are needed by the\noperation) in the current column. \n\n\\item\nYou can also type your formula directly into the expresion\nentry line at the bottom of the selected column. \\cref{sec:program} describes\nthe syntax in detail, but it's approximately C.\n\n\\end{enumerate}\n\n\\subsection{Batch processing}\n\\mylabel{sec:batch}\n\nIf you select a number of rows and then click \\ctr{Edit}\\ct{Group}, \\nip{}\nwill group the rows together. Now if you select the group and click on an item\nin the \\ct{Toolkits} menu, \\nip{} will apply that operation to every item in\nthe group. You can group groups, and you can mix grouped and non-grouped rows\nfreely.\n\nIf you save a group, \\nip{} will write each item in the group to a separate\nfile, incrementing the filename each time. \n\n\\subsection{Error handling}\n\\mylabel{sec:error}\n\nIf an object in your workspace has an error (for example, if you are trying\nto join two images of different types), then the object name button will\nturn red to show that this object contains an error and the tooltip for the\nbutton will show the error message.\n\n\\subsection{Making menu items out of columns}\n\\mylabel{sec:diaref}\n\nIf you make a column that does\nsomething useful, you can make it into a menu item by following these steps:\n\n\\begin{enumerate}\n\n\\item\nMake your column look nice. Drag with the left mouse button on the object\nname buttons to re-order items in the column, and add comments to explain\nwhat are the input fields and what are the output. Double-click on the column\ntitle bar to add a helpful title to the column.\n\nAdd a comment by typing your text (enclosed in double quotes) into the line\nat the bottom of the column. Left-drag the row to the right place.\n\n\\item\nSelect \\ct{Make Column Into Menu Item} from the \ncolumn title-bar menu, see \\pref{sec:column}.\n\nThis will open up a new dialog box which you can use to set a name for\nyour new menu item and the name of the top level menu \nthe item should be added to. \n\n\\item\nThat's it. You'll be prompted to save your new toolkit when you try to\nquit \\nip{}. We recommend you just say \\ct{OK} to the suggested location\nfor the file. Edit your menus with the programming window, see\n\\pref{sec:progwin}.\n\n\\end{enumerate}\n\n\\section{The programming window}\n\\mylabel{sec:progwin}\n\nTo pop up the programming window, click on \\ctr{Toolkits}\\ct{Edit Toolkits} in\n\\nip{}'s main image processing window. The window shown in \\fref{fg:Fred}\nshould appear.\n\nEach of the things down the left of the program window \nis a toolkit. Each toolkit is a text\nfile containing a set of definitions in \\nip{}'s programming language.\nSee \\cref{sec:program} for details on the language.\n\nIf you open a toolkit, \\nip{} shows all of the definitions in that file.\nIf you click on one of these\n\\nip{} shows the source for that definition in the main part of the\nprogram window.  After editing a definition, click on \\ctr{File}\\ct{Process} \nto make \\nip{} read what you typed, compile it, and update itself.\n\nClick on \\ctr{File}\\ctr{New}\\ct{Tool} to add a new definition to a toolkit,\nclick on \\ctr{File}\\ctr{New}\\ct{Toolkit} to make a completely new toolkit. You\ncan also right-click on tools and toolkits to get a context menu, and you\ncan left-drag tools to move them around within a toolkit or between toolkits.\n\nSome toolkits are loaded from files when \\nip{} starts up, others are built\nfrom the VIPS operation database (for example, \\ct{\\_arithmetic}), and one \n(called \\ct{\\_builtin}) contains the functions that are built into \\nip{}. If\nyou select a tool and then click on \\ctr{Help}\\ct{Help on \nTool}, \\nip{} will try to display the relevant section from the VIPS manual\nin your web browser. Currently, this works only for things in the VIPS\noperation database: try \\ctr{\\_arithmetic}\\ct{im\\_add}, for example.\nThere's a section in the \\ct{Preferences} workspace to control which web\nbrowser \\nip{} uses and how it asks for a page.\n\nToolkits and tools whose names begin with an underscore character are not\ndisplayed in the main \\ct{Toolkits} menu.  The idea is that they represent\nlittle utility functions, rather than stuff a user might be interested in. See\n\\pref{sec:tools} for more information on how tools and toolkits are displayed.\n\nYou can have several programming windows open at the same time (often useful,\nif confusing). The \\ct{Edit} menu lets you search for patterns across all\ndefinitions. The \\ct{Jump To Definition} item jumps to the definition of a\nsymbol. \n\n\\mylabel{sec:trace}\nThe \\ct{Debug} menu has items which open a trace window (use this to track\nthe actions taken by \\nip{}'s reduction engine) and which report on unresolved\nsymbols and list all current errors.\n\n\\section{Command-line interface}\n\\mylabel{sec:cmdline}\n\nYou can use \\nip{} from the command-line as well as from the GUI. This can be\nhandy for automation: you can build a workspace and then run it over a whole set\nof images, or use \\nip{} as part of a larger system. We've make\nwebsites which use \\nip{} as the back-end.\n\nIn command-line mode \\nip{} runs without a GUI of any sort, it doesn't\neven need a window system to be installed on the machine. This makes it\npossible to use it in a server or batch context.\n\nThese notes are for the Unix command-line, but they should work for Windows as\nwell.\n\n\\nip{} has three main modes of operation from the command-line:\n\n\\begin{description}\n\n\\item[\\nip{} \\emph{filename1} \\ldots{}]\nStart \\nip{} in GUI mode, loading the command-line arguments as files.\nFilenames can be images, workspaces, matricies, toolkits, and so on.\n\n\\item[\\nip{} \\ct{-e} \\emph{expression} \\emph{arg1} \\ldots{}]\nStart in no-GUI mode, print the value of \\emph{expression}. The list\n\\ct{argv} is set to be \\verb+[\"filename\",\"arg1\",..]+.\n\n\\item[\\nip{} \\ct{-s} \\emph{filename} \\emph{arg1} \\ldots{}] Start\nin no-GUI mode, read in \\emph{filename} as a set of definitions,\nprint the value of symbol \\ct{main}.  The list \\ct{argv} is set to be\n\\verb+[\"filename\",\"arg1\",..]+.\n\n\\end{description}\n\nYou can use the \\ct{-o} option to send output somewhere other than the\nscreen. If these modes don't do quite what you need, you can get finer control\nof how \\nip{} behaves with a set of other options: see the man page for\ndetails.\n\n\\subsection{Using expression mode}\n\nThe \\ct{-e} option is very easy to use. For example:\n\n\\begin{verbatim}\nnip2 -e \"2 + 2\"\n\\end{verbatim}\n\n\\noindent\nPrints 4 to stdout.\n\n\\begin{verbatim}\nnip2 -e \"99 + Image_file argv?1\" -o result.png fred.jpg\n\\end{verbatim}\n\n\\noindent\nLoads argv1 (\\ct{fred.jpg}), adds 99, writes the result to \\ct{result.png}.\n\n\\begin{verbatim}\nnip2 -e \"Matrix [[1,2],[4,5]] ** -1\" -o poop.mat\n\\end{verbatim}\n\n\\noindent\nInvert the 2x2 matrix and write the result to \\ct{poop.mat}.\n\nIf the result of the expression is a list, each item is printed on a new\nline. For example:\n\n\\begin{verbatim}\nnip2 -e \"[1..5]\"\n\\end{verbatim}\n\n\\noindent\nWill print the numbers 1 to 5, each on a new line.\n\nIf you have a list result and you are using \\ct{-o} to direct the output to a\nfile, the filename will be incremented each time you write. For example:\n\n\\begin{verbatim}\nnip2 -e \"map (add (Image_file argv?1)) [10, 20 .. 50]\" -o result1.png fred.jpg\n\\end{verbatim}\n\n\\noindent\nWill load \\ct{fred.jpg}, add 10, 20, 30, 40 and 50, then save those images to\n\\ct{result1.png} to \\ct{result5.png}.\n\n\\subsection{Using script mode}\n\nWith the \\ct{-s} option you can use \\nip{} as a Unix script interpreter.\n\nCreate a file in your favourite text editor called \\ct{brighten} containing:\n\n\\begin{verbatim}\n#!/usr/bin/nip2 -s\n\nmain\n  = clip2fmt infile.format (infile * scale), argc == 3\n  = error \"usage: infile scale -o outfile\"\n{\n  infile = Image_file argv?1;\n  scale = parse_float argv?2;\n}\n\\end{verbatim}\n\n\\noindent\nThe first line needs to be the path to \\nip{} on your system. Use \\ct{which\nnip2} to find the path if you don't know it. Mark the file as executable with\n\\ct{chmod +x brighten}, then use it on one of your image files with:\n\n\\begin{verbatim}\nbrighten fred.jpg 1.5 -o bright_fred.png\n\\end{verbatim}\n\n\\noindent\nSee \\cref{sec:program} for details on the programming language. This program\nmultiplies each input pixel by the constant, producing a floating point image,\nthen then clips the result back to the same format as the original image\n(usually 8-bit unsigned).\n\n\\nip{} takes a while (a few seconds) to start up, so this isn't going to be\nappropriate for small images or simple calculations. But for complex\noperations, or operations on large images, this mode can be very useful.\n\n\\subsection{Using \\ct{--set}}\n\nThe \\ct{--set} option (which can be abbreviated to \\ct{-=}) lets you make\nchanges to a workspace after loading it.  Suppose the workspace \\ct{test.ws}\nhas a row called \\ct{A1} with the value 12.  Then entering:\n\n\\begin{verbatim}\nnip2 test.ws --set Workspaces.test.A1=45\n\\end{verbatim}\n\n\\noindent\nWill, as normal, start \\nip{} and load \\ct{test.ws}. But before the first\nrecalculation, \\nip{} will change the value of \\ct{A1} to be 45.  You can\nuse \\ct{--set} to create new symbols as well.\n\n\\subsection{Other modes}\n\nA set of sub-options let you mix up other modes yourself. For example, it's\ncommon to want to run a workspace on many files.\n\nSuppose the workspace \\ct{process.ws} loads an image in \\ct{A1}, performs some\nprocessing and produces a result image \\ct{A10}. If you run \\nip{} with:\n\n\\begin{verbatim}\nnip2 -bp \\\n  -= 'Workspaces.process.A1=Image_file \"fred.jpg\"' \\\n  -= main=Workspaces.process.A10 \\\n  -o fred.jpg process.ws\n\\end{verbatim}\n\n\\noindent\nThis will start \\nip{} in batch (ie. no GUI) mode (the \\ct{-b} switch), \nload \\ct{process.ws}, change \\ct{A1} to load another file, set \\ct{main}\nto be the value of \\ct{A10} and save the value of \\ct{A10} to \\ct{fred.jpg} \n(the \\ct{-p} switch).\n\n"
  },
  {
    "path": "doc/src/tutorial.tex",
    "content": "\\chapter{Tutorial}\n\\mylabel{sec:tutorial}\n\nThis chapter runs very quickly through how to use \\nip{}'s user-interface. See\n\\cref{sec:reference} if you want more details on how the different bits work.\n\n\\section{Quick interface tour}\n\\mylabel{sec:quicktour}\n\nStart up \\nip{}. You should see something like \\fref{fg:introwin} (the\nexact look might be different on your system).\n\nThe menus at the top of the window are very ordinary, except for the\n\\ct{Toolkits} menu which contains all of the image processing operations.\nThe main part of the window shows a workspace. Workspaces are split into tabs\n(across the top) and each tab is made of a set of columns. The current column,\nwhere new objects appear, has a dark green bar across the top. \n\nClick on \\ctr{File}\\ct{Open} to get a file dialog and load up an\nimage. \\nip{} can load most image formats, try it and see.  Check the\n\\ct{Pin up} box to have the dialog remain after you press OK. \nYou can also drag files from the desktop or from your file manager.\n\nAfter you've loaded an image, \\nip{} should look like \\fref{fg:loadedimage}.\nDouble click on the thumbnail to open an image view window. Alternatively,\nselect \\ct{Edit} from the right-button menu on the thumbnail. See\n\\fref{fg:imageview}.\n\n\\begin{figure}\n\\figw{3in}{snap2.jpg}\n\\caption{After loading an image}\n\\mylabel{fg:loadedimage}\n\\end{figure}\n\n\\begin{figure}\n\\figw{3in}{snap3.jpg}\n\\caption{Image view window}\n\\mylabel{fg:imageview}\n\\end{figure}\n\nAs well as the standard keymappings, \\nip{} has extra shortcuts for\nnavigating images, see \\tref{tb:shortcuts}.  Use the \\ctr{View}\\ct{Toolbar}\nmenu to turn on other features. You can have a status bar (shows image\nproperties, mouse position and pixel value), a display control bar (lets\nyou change scale and offset for display pixels, click on the arrow on the\nleft for a useful extra menu), a paint bar and some rulers.\n\n\\begin{tab2}\n\\begin{center}\n\\begin{tabular}{||l|l||}\n\\hline\nKeys in image display widget  \t\t& Action \\\\\n\\hline\n\\ct{i}, \\ct{+} \t\t\t\t& Zoom in on mouse pointer \\\\\n\\ct{o}, \\ct{-} \t\t\t\t& Zoom out \\\\\nCursor up/down/left/right \t\t& Scroll a small amount in direction \\\\\nShift and cursor up/down/left/right \t& Scroll a screenful in direction \\\\\nCtrl and cursor up/down/left/right \t& Scroll to edge of image \\\\\nMiddle mouse drag \t\t\t& Pan image \\\\\nMouse wheel \t\t\t\t& Scroll up/down \\\\\nShift and mouse wheel\t\t\t& Scroll left/right \\\\\nCtrl and mouse wheel \t\t\t& Zoom in/out \\\\\n\\ct{0} (zero key) \t\t\t& Zoom out to fit image to window \\\\\n\\ct{1}, \\ct{2}, \\ct{4}, \\ct{8}  \t& Set magnification to 1, 2, 4 or 8 \\\\\nCtrl and \\ct{2}, \\ct{4}, \\ct{8}\t\t& Set zoom out factor to 2, 4 or 8 \\\\\n\\hline\n\\end{tabular}\n\\end{center}\n\n\\caption{\\nip{} shortcuts for the image view window}\n\\mylabel{tb:shortcuts}\n\\end{tab2}\n\nYou can mark things on an image. Hold down Ctrl and drag down and right with\nthe left mouse button to mark a region. Ctrl-left-click to mark a point. Drag\nup and left to mark an arrow (two points connected by a line). Drag from\nthe rulers to mark guides. Right-click on a label to get a menu which\nyou can use to remove or edit one of these things. Left drag on a label\nto move the things around, left-drag on the edges or corners to resize.\n\\fref{fg:imageviewregion} shows the same image with stuff marked on it.\n\n\\begin{figure}\n\\figw{3in}{snap4.jpg}\n\\caption{Image view window with marked regions}\n\\mylabel{fg:imageviewregion}\n\\end{figure}\n\nClean up any messing about and leave two regions on your image. The main\nwindow should now look something like \\fref{fg:main2regions}.\n\n\\begin{figure}\n\\figw{3in}{snap5.jpg}\n\\caption{Main window, two regions marked}\n\\mylabel{fg:main2regions}\n\\end{figure}\n\nThere are three rows visible here, \\ct{A1}, \\ct{A4} and \\ct{A7}. Each row\nhas (from left to right) a pair of up/down arrows (these indicate that\nthe row contains sub-rows: click on the down arrow several times to\nopen the row up and see inside), the name button (left-click to select,\nShift-left-click to extend-select, Ctrl-left-click to toggle select, click\non the workspace background to unselect everything, left-drag on the name\nbutton to reorder items within the column, right-click to get a context menu) \nand the thumbnail image.\n\nLeft-click on the name button of one of these images to select it, and\nthen click on \\ctr{Toolkits}\\ctr{Image}\\ctr{Transform}\\ctr{Rotate}\\ct{Free}\n(alternatively, if nothing is selected when you click on one of the toolkit\nmenus, \\nip{} will apply the operation to the bottom object in the current\ncolumn). A new row will appear representing the rotation operation. Drag\nthe slider to rotate the image (or type an angle in degrees into the box\nto the left of the slider and press Return). Pick an interpolation type from\nthe option menu and zoom in on some pixels to check the result. \nSee \\fref{fg:rotate}.\n\n\\begin{figure}\n\\figw{3in}{snap6.jpg}\n\\caption{Using \\ctr{Rotate}\\ct{Free}}\n\\mylabel{fg:rotate}\n\\end{figure}\n\nThe same thing works for image processing operations that take two arguments.\nLeft-click on one of your original regions, Ctrl-left-click on the rotated\nimage (the box at the left of the main window status bar says what's selected\nand in what order), and click on \\ctr{Toolkits}\\ctr{Image}\\ctr{Join}\\ct{Left\nto Right}. A new row appears representing the join operation.\n\nClick on \\ct{Background Colour}, type in 128 and press Return. Drag the\n\\ct{shim} slider to 50 (or type 50 into the box just to the left of the\nslider and press Return). See \\fref{fg:join}.\n\n\\begin{figure}\n\\figw{3in}{snap7.jpg}\n\\caption{Using \\ctr{Join}\\ct{Left to Right}}\n\\mylabel{fg:join}\n\\end{figure}\n\nThe \\ct{Toolkits} menu is large and can be slow and annoying to find\nthings in, so \\nip{} has several shortcuts. First, you can tear-off menus\nby clicking on the dotted line at the top. If you're going to be using\none of the sub-menus repeatedly this can save a lot of clicking. Next,\nyou can set keyboard shortcuts for menu items by moving the mouse pointer\nover the item and pressing the key combination you want to set. \n\nSome systems won't let you edit menu shortcuts by default. For example,\non GNOME, you need to enable this in \\ctr{System}\\ctr{Preferences}\\ct{Menus\n\\& Toolbars}.\n\nFinally, there is a toolkit browser: this shows the same set of items, but in\nan easier-to-browse way. Click on \\ctr{View}\\ct{Toolkit Browser} and the\nbrowse side-panel will appear, see \\fref{fg:browse}. It shows all of the items\nas a single long list. Type into the search box at the top to only show items\nwhich match. Double-click (or press Return) on an item to activate it. Scroll\nto the right to see what arguments the item needs and what menu it appears in.\n\n\\begin{figure}\n\\figw{3in}{snap7a.jpg}\n\\caption{The toolkit browser}\n\\mylabel{fg:browse}\n\\end{figure}\n\nThe box at the bottom of each column is for entering new expressions. You\ncan type stuff here, and \\nip{} will make a new row for each item you\nenter. Try typing \\ct{2 + 2} and pressing Return. The syntax is (almost,\nwith a few small differences) the same as the C programming language. See\n\\pref{sec:operators} for a list of the differences. Try\nmultiplying the joined images by a small amount (eg. type something like\n\\ct{A9 * 1.2} and press Return). Normally \\nip{} will pick names for new\nobjects for you (like \\ct{A1}), but you can set a name yourself if you like.\nTry entering \\ct{fred = 12}.\n\nClick the down button once on your brightened image and left-click on the area\njust below the thumbnail. You should see the stuff you typed to make that row.\nYou can edit it to be anything else, press Return and \\nip{} will recalculate.\nTry going back to your original image (the one you loaded from a file),\nopen an image view window, and try dragging one of the regions. You can\nchange any of the sliders in the rotate or the join rows as well.  \n\nRight-click on a thumbnail for a useful menu. Use \\ct{Save As} to save an\nimage to a file. Use \\ct{Replace From File} to change the image in a row (and\nrecalculate the rest of your workspace, very handy). Use \\ct{Header} to view\nan image's metadata. \n\nYou can also edit the insides of objects. Click the down button next to\none of your regions until the \\ct{width} and \\ct{height} rows appear, click on\n\\ct{width} and type \\ct{height * 2}. Now open the image window the region is\ndefined on and try to resize it: you'll find that the width of the region is\nfixed, but that if you change the height, the width changes with it. This is a\nvery general property of classes in \\nip{}: you can use it to join objects\ntogether in complex ways, and to modify the behaviour of interactive objects. \n\nRight click on a column title bar to get a useful menu. Click on\n\\ctr{File}\\ctr{New}\\ct{Column} make another column (handy for organising\na workspace). If you drag from an image thumbnail on to the workspace\nbackground, \\nip{} will make a new column for you. You can drop thumbnails\non to other thumbnails to make links.  \n\nThere's a useful right-click menu on the tab name. Duplicating tabs is a\nvery easy way to try something out: make a copy of your tab, try changing\nsomething, if it doesn't work out, just delete your new tab and go back to\nwhere you were. You can drag tabs between workspaces, and you can drag a\ntab to the desktop to make a new workspace. You can make references between\ntabs with the tab name and a dot, for example {\\ct{tab1.A1}}. You can save\ncolumns, tabs or workspaces to workspace files, then merge them back into\na colum, as part of a tab, or as a new tab.\n\nIf \\nip{} falls over (I do hope\nit doesn't), you can usually get your work back by restarting \\nip{} and\nclicking on \\ctr{File}\\ct{Search for Workspace Backups}.  There are a lot\nof preferences (perhaps too many), see \\aref{sec:config}.\n\nThere is a lot of stuff in the \\ct{Toolkits} menus, but they do almost\nall have tooltips. If you let your mouse hover over a menu item for a\nmoment you should get some helpful text. The toolkit menu is organised by\nobject type. If you want to do something to a matrix, look in the\n\\ctr{Toolkits}\\ct{Matrix} menu. The exception is \\ctr{Toolkits}\\ct{Tasks}\nwhich repeats many of the regular toolkit items, but groups them by typical\ntasks instead.\n\nOperations can work on groups as well as on single images, so you can batch\nthings up. If you save a group of images, \\nip{} will number each image\nsequentially for you.  You can use \\ctr{Edit}\\ct{Duplicate} to make copies\nof objects. If you select lots of objects and duplicate them, \\nip{} will\n(fairly intelligently) rename everything for you so it all still works.\n\n\\section{\\nip{} for reflectogram mosaics}\n\\mylabel{sec:irtut}\n\nThis section quickly builds an infrared reflectogram mosaic using the\nsample images that come with \\nip{}. See \\cref{sec:ir} for detailed\ncoverage.\n\nClick on \\ctr{File}\\ct{Open Examples}. \nYou should see a directory called \\ct{1\\_point\\_mosaic}. Doubleclick and\nyou'll see a file called \\ct{1pt\\_mosaic.ws}. Doubleclick that and you'll load\nthe workspace for this example.\n\nIf you'd rather make the workspace yourself, click on the file type filter and\nselect \\ct{All files}. A set of 8 images should appear.  Click on the first\nfile, shift-click on the last, and click \\ct{Open}. This will create a group\nof all eight images. Right-click on the row and select \\ct{Ungroup} to unpack\nto a set of rows.  See \\fref{fg:loadsamples}.\n\n\\begin{figure}\n\\figw{3in}{snap14.jpg}\n\\caption{Loading the sample images}\n\\mylabel{fg:loadsamples}\n\\end{figure}\n\nThe images have been named to match their positions in the mosaic, so for\nexample \\ct{cd2.1.jpg} is the first image in row two.  Open up viewing windows\nfor the first two images by double clicking on the thumbnails.\nMove the two opened images viewers so that they are side by side. Adjust\nthe zoom (using the \\ct{i} and \\ct{o} keys) and the pan (by dragging with the\nmiddle mouse button) so that the overlap\narea is visible in both images.\n\nMark a tie-point on each image by Ctrl-left-clicking on a feature you can see\nin both images, see \\fref{fg:readyjoin}. Move a point after you've marked it\nby dragging on the label. You don't need to be exact: \\nip{} just uses the\npoint you select as the start point for a search. It can cope with\nmisses of up to about 10 pixels. To mosaic the two images together, click\non \\ctr{Toolkits}\\ctr{Tasks}\\ctr{Mosaic}\\ctr{One Point}\\ct{Left to Right}. \nSee \\fref{fg:joined}.\n\n\\begin{figure}\n\\figw{3in}{snap15.jpg}\n\\caption{Ready to join}\n\\mylabel{fg:readyjoin}\n\\end{figure}\n\n\\begin{figure}\n\\figw{3in}{snap16.jpg}\n\\caption{Joined images}\n\\mylabel{fg:joined}\n\\end{figure}\n\nPicking items deep in the toolkit menu is fiddly, so \\nip{} has several\nshortcuts.  First, you can tear off any toolkit menu by clicking on the dotted\nline at the top. Secondly,\nyou can assign any keyboard accelerator to any menu item. Navigate to the\nmenu item and while it is selected, press the key combination you want to use\nas a shortcut (for example, Ctrl-L might be good for \\ctr{Mosaic}\\ctr{One\nPoint}\\ct{Left to Right}). Now whenever you press Ctrl-L with the keyboard\nfocus in the main window, you will do a left-right mosaic join. Finally, you\ncan use the toolkit browser to display a selection of the tools in a pane on\nthe right-hand side of the main window. Click on \\ctr{View}\\ct{Browse\nToolkits}, then type ``mosaic'' into the search box at the top. The toolkit\nbrowser will display all items related to mosaicing. Double-click an item to\ndo that action. \n\nSome systems won't let you edit menu shortcuts by default. For example,\non GNOME, you need to enable this in \\ctr{System}\\ctr{Preferences}\\ct{Menus\n\\& Toolbars}.\n\nJoin the rest of the pairs of sample images together\nleft-right. Once you\nhave made all the rows, join the rows together in turn to make the complete\nimage using \\ctr{Mosaic}\\ctr{One Point}\\ct{Top to Bottom}. \n\nWhen you've built the whole thing you'll see that there are differences\nin brightness between the tiles that make up your composite image. You can\nfix most problems like this automatically by selecting your final mosaiced\nimage and clicking on \\ctr{Mosaic}\\ct{Balance}. This operation takes your\nmosaic apart, examines the overlap areas for differences in brightness,\ncalculates a set of adjustment factors to minimise these differences,\nand then rebuilds the mosaic.\n\nThere can be some problems left even after mosaic balance. Use\n\\ctr{Mosaic}\\ct{Tilt Brightness} to remove any left-right or up-down\ngraduations in brightness. \n\nSave your mosaic workspace for future reference by clicking on\n\\ctr{File}\\ct{Save Workspace}. To save just the mosaiced image, right click\non the thumbnail and select \\ct{Save As}.\n\n\\section{\\nip{} for nerds}\n\\mylabel{sec:nerdtour}\n\nThis section sprints through a bit of \\nip{} programming, see\n\\pref{sec:program} for full details and a more formal definition of the\nlanguage.\n\nThe insides of \\nip{} are built with \\nip{}'s own programming language. It's a\npure lazy functional language with classes. It's C's expression syntax\n(more or less) plus approximately Miranda/Haskell function syntax,\nplus some basic class stuff. \\nip{}'s main window is a class browser for this\nprogramming language.\n\nClick on \\ctr{Toolkits}\\ct{Edit Toolkits} in \\nip{}'s main window to pop up the\nprogramming window (see \\pref{sec:progwin} for details on all the bits in the\nwindow), then in the edit area there type:\n\n\\begin{verbatim}\n// add two things\n \nFred a b = class {\n  sum = a + b;\n}\n\\end{verbatim}\n\nThis defines a class called \\ct{Fred} whose constructor takes two arguments,\n\\ct{a} and \\ct{b}. There's one member, called \\ct{sum}, which is \\ct{a}\nand \\ct{b} added together.\n\nIn the program window, click \\ctr{File}\\ct{Process}. This makes \\nip{}\nread what you typed, parse it, compile it and update itself. The program\nwindow should now look like \\fref{fg:Fred}.\n\n\\begin{figure}\n\\figw{3in}{snap8.jpg}\n\\caption{Programming \\ct{Fred}}\n\\mylabel{fg:Fred}\n\\end{figure}\n\nIf you look back at the main \\nip{} window, a new menu will have appeared\nunder \\ct{Toolkits} called \\ct{untitled}. If you click on that, there will\nbe a menu item called \\ct{Fred}. Let your mouse linger, and you'll see a\ntooltip too.\n\nIn the main window, type \\ct{Fred 2 3} into the box at the bottom of the\ncurrent column. Press Return and \\nip{} will make a \\ct{Fred} for you. Click\non the down arrow to the left of your new \\ct{Fred} once to see the members\nof \\ct{Fred} (just \\ct{sum} in this case), click again to see the class\nparameters too. The main window should look like \\fref{fg:mainFred}.\n\n\\begin{figure}\n\\figw{3in}{snap9.jpg}\n\\caption{Main window \\ct{Fred}}\n\\mylabel{fg:mainFred}\n\\end{figure}\n\nClick to the right of \\ct{b}, type in a new value and press Return. The\n\\ct{sum} member should update. \\nip{} keeps track of dependencies between\nrows, but it also tracks dependencies inside rows, both ones that come\nfrom the class, and ones created by any edits you do to the class instance\nafter creating it. You won't see it in a simple example, but \\nip{} also\ndiscovers and tracks dependencies which can arise at run time.  Click on\nthe text just to the right of the \\ct{b} button again, type \\ct{a} and\npress Return. Now edit \\ct{a}: press Return and both \\ct{b} and \\ct{sum}\nwill update.\n\nYou can use \\ct{Fred} to add any two things together. Click on\n\\ctr{Toolkits}\\ctr{Widgets}\\ct{Scale} to make a scale widget, press Ctrl-U\n(the keyboard shortcut for \\ctr{Edit}\\ct{Duplicate}) to duplicate it, and\nfinally click on \\ctr{Toolkits}\\ctr{untitled}\\ct{Fred}. Open up the new\n\\ct{Fred} and try dragging some of the scales around. The main window will\nlook like \\fref{fg:slideFred}.\n\n\\begin{figure}\n\\figw{3in}{snap10.jpg}\n\\caption{Scale \\ct{Fred}}\n\\mylabel{fg:slideFred}\n\\end{figure}\n\nThe scales are classes too (instances of \\ct{Scale}). You can open them up\nand do strange things with them as well. Open up one of the scales you made\n(eg. \\ct{A2} in \\fref{fg:slideFred}) and change the \\ct{from} parameter to\nbe \\ct{A3.value}. Now try dragging the sliders again.\n\nTry dragging the \\ct{sum} slider. Now go back and drag one of the\noriginal sliders.  You'll see that \\ct{sum} no longer updates, it's stuck\nat the last position you dragged it to. This is because there are now two\nthings affecting the value of \\ct{sum}: the underlying code (the \\ct{a +\nb} inside \\ct{Fred}), and the position you dragged the slider representing\n\\ct{sum} to. \\nip{} has the rule that graphical edits (dragging the slider)\noverride code. To make \\ct{sum} update again, right click on the \\ct{sum}\nbutton and select \\ct{Reset} from the pop up menu. Now drag one of\nthe input sliders again, and \\ct{sum} will start updating once more.\n\nClasses can inherit from other classes. Go back to the program window,\nclick on \\ctr{File}\\ctr{New}\\ct{Tool} to clear the edit window, and type:\n\n\\begin{verbatim}\n// multiply two things\n \nJim a b = class Fred a b {\n  product = a * b;\n}\n\\end{verbatim}\n\nThis defines a class called \\ct{Jim} which inherits from \\ct{Fred}. Click\n\\ctr{File}\\ct{Process}, then back in\nthe main window, type \\ct{Jim 4 5} into the bottom of the column. Click down\nonce to expose the members (just \\ct{product}), click again to expose the\nparameters as well (\\ct{a} and \\ct{b}), and click a third time to expose\nthe superclass member (which should be an instance of \\ct{Fred}). You can\nalso open up the \\ct{super} member and see inside the \\ct{Fred} that this\n\\ct{Jim} is using as its superclass. \n\\ct{A5} will respond to both \\ct{product} and \\ct{sum}. \nSee \\fref{fg:Jim}.\n\n\\begin{figure}\n\\figw{3in}{snap11.jpg}\n\\caption{Browsing \\ct{Jim}}\n\\mylabel{fg:Jim}\n\\end{figure}\n\n\\nip{} has about 20 different graphical classes like \\ct{Scale}. Whenever a\nrow takes a new value, \\nip{} checks to see if that value is an instance of\none of these special classes, and if it is, it will add a graphical element to\nthe row display which represents that class's value. It builds the graphical\npart by looking inside the class for certain members (for example, the scale\ngraphic looks for members called \\ct{from}, \\ct{to} and \\ct{value}). When\nyou change the graphic (maybe by dragging the scale), \\nip{} rebuilds\nthe class by looking inside for a edit member (eg. \\ct{Scale\\_edit})\nor if that's not defined, a constructor member (eg. \\ct{Scale}).\n\nYou can make your own graphic widgets by subclassing \\nip{}'s built-in\nones. By selectively overriding default constructors and adding edit members,\nyou can control how your new widget will behave in expressions, and how it\nwill behave if it's edited graphically.\n\nMake a new column, load up an image (use \\ctr{File}\\ct{Open}), open an\nimage viewer (double-click on the thumbnail), drag out two regions on it\n(hold down Ctrl and the left mouse button and drag down and right). Your main \nwindow should look like \\fref{fg:twomoreregions}.\n\n\\begin{figure}\n\\figw{3in}{snap12.jpg}\n\\caption{Two more regions}\n\\mylabel{fg:twomoreregions}\n\\end{figure}\n\n\\ct{im\\_insert} is a VIPS operation that puts one image inside another at an\n(x, y) position. VIPS operations work on VIPS images. The \\ct{value} member of\nan \\ct{Image} or \\ct{Region} is the VIPS image that underlies the \\nip{} row.\n\nYou can use \\ct{im\\_insert} to make a thing to join two images together. Back\nin the program window, click on \\ctr{File}\\ctr{New}\\ct{Tool} and enter:\n\n\\begin{verbatim}\n// join two images left-right\n\nJoin a b = class Image value {\n  shim = Scale \"Spacing\" 0 1000 0;\n  value = im_insert a.value b.value\n    (a.width + shim.value) 0;\n}\n\\end{verbatim}\n\n\\noindent\nClick \\ctr{File}\\ct{Process}. This defines a class \\ct{Join} which\nsubclasses the \\ct{Image} graphic.  \n\nNow select your two regions (click on the first one, shift-click on\nthe second) and click on \\ctr{Toolkits}\\ctr{untitled}\\ct{Join}. Alternatively,\njust click \\ct{Join} and it'll be given the borrom two items in the column.\nA new \\ct{Join} row will appear. Open it up and drag the slider to\nset the spacing between the two joined images. Go back to the image\nviewer for the image file you loaded and try dragging one of the\nregions. \\fref{fg:myjoin} shows this class in action. The thing in\n\\ctr{Toolkits}\\ctr{Image}\\ctr{Join}\\ct{Left to Right} is just a slightly \nfancier\nversion of this.\n\n\\begin{figure}\n\\figw{3in}{snap13.jpg}\n\\caption{Joining two images with \\ct{Join}}\n\\mylabel{fg:myjoin}\n\\end{figure}\n\nYou can change how the graphic widgets behave by subclassing them. Try:\n\n\\begin{verbatim}\nScale_int c f t v = class\n  scope.Scale c f t ((int) v) {\n  Scale = Scale_int;\n}\n\\end{verbatim}\n\n\\noindent\nThis defines a new scale class called \\ct{Scale\\_int} which can only take\ninteger values. The \\ct{Scale = Scale\\_int;} line is \\ct{Scale\\_int}\noverriding \\ct{Scale}'s constructor, so that a \\ct{Scale\\_int} stays a\n\\ct{Scale\\_int} when you drag. Because there's a local called \\ct{Scale},\n\\ct{Scale\\_int} needs to use \\ct{scope.Scale} to refer to the superclass.\n\nHere's a version of \\ct{Mark} which can only be dragged in a circle. You pass\nit an image to display on, an xy centre position, a radius and a start angle.\n\n\\begin{verbatim}\nMark_circle image x y r a = class \n  scope.Mark image _x' _y' {\n  // get rect cods for our point\n  _pos = (x, y) + rectangular (r, a);\n  _x' = re _pos;\n  _y' = im _pos;\n\n  Mark i l t \n    = this.Mark_circle i x y r a'\n  {\n    // vector from centre of\n    // circle to new position\n    u = (l, t) - (x, y);\n\n    // angle of vector\n    a' = im (polar u);\n  }\n}\n\\end{verbatim}\n\n"
  },
  {
    "path": "man/Makefile.am",
    "content": "SUBDIRS = man1\n"
  },
  {
    "path": "man/man1/Makefile.am",
    "content": "man_MANS = nip2.1\n\nEXTRA_DIST = ${man_MANS}\n"
  },
  {
    "path": "man/man1/nip2.1",
    "content": ".TH NIP2 1 \"Oct 4 2004\"\n.SH NAME\nnip2 \\- image processing with the VIPS library\n\n.SH SYNOPSIS\n.B nip2 [filename1 ...]\n.br\n.B nip2 -s filename [arg1 ...]\n.br\n.B nip2 -e expression [arg1 ...]\n\n.SH DESCRIPTION\n.B nip2\n(for New Image Processing) is a tool for manipulating images using the\nVIPS image processing library.\n\nThere are three principal modes:\n\n.B nip2 [filename1 ...]\n.br\n  start in GUI mode, loading the named files\n\n.B nip2 -e expression [arg1 ...]\n.br\n.B nip2 --expression=EXPRESSION [arg1 ...]\n.br\n  start in no-GUI mode; set main = expression, set list argv to\n  [\"filename\", \"arg1\", \"arg2\", ...], set argc to length of list; print\n  the value of symbol \"main\" to stdout; exit\n\n.B nip2 -s filename [arg1 ...]\n.br\n.B nip2 --script=FILENAME [arg1 ...]\n.br\n  start in no-GUI mode; read in filename as a set of definitions, \n  set list argv to [\"filename\", \"arg1\", \"arg2\", ...], set argc to \n  length of list; print the value of symbol \"main\" to stdout; exit; \n  useful for running nip2 as an interpreter on unix\n\nYou can use\n.B -o\nto direct output to a file rather than stdout.\n\n.B -o filename\n.br\n.B --output=FILENAME\n.br\n  the value of main is written to the named file. If main is a \n  list, the filename is incremented between objects. You can use \n  the suffix to specify the format and options to write in\n\nOther options provide finer control over startup and shutdown. If you need to\ndo something strange, don't use -e/-s, use these in combination.\n\n.B -b\n.br\n.B --batch\n.br\n  batch (ie. non-GUI) mode\n\n.B -m\n.br\n.B --no-load-menus\n.br\n  don't load menus, for faster startup\n\n.B -a\n.br\n.B --no-load-args\n.br\n  don't load extra command-line arguments\n\n.B -w\n.br\n.B --stdin-ws\n.br\n  load stdin as a workspace\n\n.B -d\n.br\n.B --stdin-def\n.br\n  load stdin as a set of definitions\n\n.B -p\n.br\n.B --print-main\n.br\n  print the value of main on exit. nip2 will check for a top-level \n  symbol called main, and also check each workspace for a main\n\nFinally some other options are useful for debugging, timing and for generating\nstrings for internationalisation.\n\n.B -V\n.br\n.B --verbose\n.br\n  produce verbose error messages: handy for debugging in batch mode\n\n.B -i\n.br\n.B --i18n\n.br\n  output strings from .def files for internationalisation\n\n.B -v\n.br\n.B --version\n.br\n  print version information\n\n.B -c\n.br\n.B --benchmark\n.br\n  benchmark: no GUI, just start up and shut down\n\n.B -t\n.br\n.B --time-save\n.br\n  time saves: after every image save a popup tells you the time the \n  save took in seconds\n\n.B -T\n.br\n.B --test\n.br\n  test: start up (including any arg processing), test for any errors, \n  and exit with an error code if any occured. Useful for running \n  automated tests.\n\n.B -x PREFIX\n.br\n.B --prefix=PREFIX\n.br\n  set install prefix: start up as if nip2 had been installed to PREFIX.\n  Useful for running automated tests without installing the thing.\n\n.SH EXAMPLES\n\n  nip2 fred.jpg\n\nStart nip2, loading fred.jpg.\n\n  nip2 -e \"2 + 2\"\n\nPrints 4 to stdout.\n\n  nip2 -e \"99 + Image_file argv?1\" -o result.png fred.jpg\n\nLoad argv1 (fred.jpg), add 99, output to result.png.\n\n  nip2 -e \"Matrix [[1,2],[4,5]] ** -1\" -o poop.mat\n\nInvert the 2x2 matrix and write the result to poop.mat.\n\n.SH COPYRIGHT\n2008 (c) Imperial College, London\n"
  },
  {
    "path": "nip2.appdata.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- Copyright 2014 John Cupitt <jcupitt@gmail.com> -->\n<application>\n <id type=\"desktop\">nip2.desktop</id>\n <metadata_license>CC0-1.0</metadata_license>\n <project_license>GPL-2.0+ and LGPL-2.1+</project_license>\n <name>nip2</name>\n <summary>Image processing spreadsheet</summary>\n <description>\n  <p>\n\t  nip2 is a GUI for the VIPS scientific image processing library. \n\t  It's a little \n\t  like a spreadsheet: you create a set of formula connecting your \n\t  images together, and on a change nip2 recalculates. \n  </p>\n  <p>\n \t  It can load \n\t  images in most commonly used formats, but also in scientific \n\t  formats such as Matlab, FITS, OpenSlide, OpenEXR, and others. \n\t  nip2 is especially useful with very large images.  You can \n\t  easily work with multi-gigabyte images even on a modest computer. \n  </p>\n </description>\n <screenshots>\n   <screenshot type=\"default\" width=\"739\" height=\"534\">https://raw.githubusercontent.com/libvips/nip2/master/doc/src/figs/snap1.jpg</screenshot>\n </screenshots>\n <url type=\"homepage\">https://libvips.github.io/libvips</url>\n <updatecontact>https://github.com/libvips/nip2</updatecontact>\n</application>\n"
  },
  {
    "path": "nip2.desktop.in",
    "content": "[Desktop Entry]\nName=@PACKAGE@\nComment=Image manipulation program based on VIPS\nComment[it]=Programma per la manipolazione di immagini basato su VIPS\nExec=nip2 %F\nIcon=nip2\nTerminal=false\nType=Application\nCategories=Graphics;RasterGraphics;\nStartupNotify=true\nMimeType=image/x-vips;\n"
  },
  {
    "path": "nip2.spec.in",
    "content": "Name:           @PACKAGE@\nVersion:        @VERSION@\nRelease:\t1%{?dist}\nSummary:\tInteractive tool for working with large images\n\nGroup:\t\tApplications/Multimedia\nLicense:\tGPLv2+\nURL:\t\thttps://github.com/jcupitt/nip2\nSource0:\thttps://github.com/jcupitt/nip2/releases\n\nBuildRoot:\t%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)\n\nBuildRequires:\tvips-devel = %{version}\nBuildRequires:\tgtk2-devel shared-mime-info gnome-icon-theme\nBuildRequires:\tflex bison intltool fftw-devel libxml2-devel gettext\nBuildRequires:\tdesktop-file-utils\n#Requires:\n\n\n# description taken from Debian package\n%description\nnip2 is a graphical front end to the VIPS package.\nWith nip2, rather than directly editing images, you build\nrelationships between objects in a spreadsheet-like fashion. When you\nmake a change somewhere, nip2 recalculates the objects affected by\nthat change. Since it is demand-driven this update is very fast, even\nfor very, very large images. nip2 is very good at creating pipelines\nof image manipulation operations. It is not very good for image\nediting tasks like touching up photographs. For that, a tool like the\nGIMP should be used instead.\n\n\n%prep\n%setup -q\n\n\n%build\n%configure\nmake %{?_smp_mflags}\n\n\n%install\nrm -rf $RPM_BUILD_ROOT\nmake install DESTDIR=$RPM_BUILD_ROOT\n\n# delete doc (we will get it later with %doc)\nrm -rf $RPM_BUILD_ROOT%{_datadir}/doc/nip2\n\n# malkovich??\nrm -rf $RPM_BUILD_ROOT%{_datadir}/locale/malkovich\n\n# the nip2 post install hook seems to run update-mime-database, but we\n# need to run it in post\nrm -rf $RPM_BUILD_ROOT%{_datadir}/mime\nmkdir -p $RPM_BUILD_ROOT%{_datadir}/mime/packages\ncp -a nip2.xml $RPM_BUILD_ROOT%{_datadir}/mime/packages\n\n# same with desktop file\nrm -rf $RPM_BUILD_ROOT%{_datadir}/applications\n\n# locale stuff\n%find_lang nip2\n\n# icon\ninstall -d $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/128x128/apps\ncp -a share/nip2/data/vips-128.png\t\\\n\t$RPM_BUILD_ROOT%{_datadir}/icons/hicolor/128x128/apps/nip2.png\n\n# desktop file\ndesktop-file-install --vendor fedora \t\t\t\\\n\t--dir $RPM_BUILD_ROOT%{_datadir}/applications\t\\\n\tnip2.desktop\n\n\n%post\n# scriptlet for icons\ntouch --no-create %{_datadir}/icons/hicolor || :\nif [ -x %{_bindir}/gtk-update-icon-cache ]; then\n\t%{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || :\nfi\n\n# scriptlet for desktop database\nupdate-desktop-database &> /dev/null || :\n\n# MIME\nupdate-mime-database %{_datadir}/mime &> /dev/null || :\n\n\n%postun\n# scriptlet for icons\ntouch --no-create %{_datadir}/icons/hicolor || :\nif [ -x %{_bindir}/gtk-update-icon-cache ]; then\n\t%{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || :\nfi\n\n# scriptlet for desktop database\nupdate-desktop-database &> /dev/null || :\n\n# MIME\nupdate-mime-database %{_datadir}/mime &> /dev/null || :\n\n\n%clean\nrm -rf $RPM_BUILD_ROOT\n\n\n%files -f nip2.lang\n%defattr(-,root,root,-)\n%doc doc/html doc/pdf AUTHORS ChangeLog COPYING NEWS THANKS TODO\n%{_bindir}/nip2\n%{_bindir}/run-nip2.sh\n%{_datadir}/nip2\n%{_mandir}/man1/nip2.1.gz\n%{_datadir}/icons/hicolor/*/apps/*\n%{_datadir}/applications/*\n%{_datadir}/mime/packages/nip2.xml\n\n\n%changelog\n* Sat Jun 10 2008 John Cupitt <jcupitt@gmail.com> - 8.7.0\n- Update URLs\n\n* Sat Jul 19 2008 Jesper Friis <jesper.friis(at)sintef.no> - 7.15.0-1\n- Added this spec file from the Fedora source rpm\n\n* Sat Mar 15 2008 Adam Goode <adam@spicenitz.org> - 7.14.1-1\n- New release\n\n* Mon Mar 10 2008 Adam Goode <adam@spicenitz.org> - 7.14.0-1\n- New release\n\n* Sat Feb  9 2008 Adam Goode <adam@spicenitz.org> - 7.12.5-4\n- GCC 4.3 mass rebuild\n\n* Wed Dec  5 2007 Adam Goode <adam@spicenitz.org> - 7.12.5-3\n- Fix desktop file validation\n\n* Tue Oct 16 2007 Adam Goode <adam@spicenitz.org> - 7.12.5-2\n- Rebuild for OpenEXR soname change\n\n* Fri Sep 21 2007 Adam Goode <adam@spicenitz.org> - 7.12.5-1\n- New upstream release\n\n* Thu Aug 16 2007 Adam Goode <adam@spicenitz.org> - 7.12.4-1\n- New upstream release\n- Update License tag\n\n* Wed Jul 25 2007 Adam Goode <adam@spicenitz.org> - 7.12.2-1\n- New stable release 7.12\n\n* Sat May  5 2007 Adam Goode <adam@spicenitz.org> - 7.12.0-1\n- New upstream release\n- Update desktop file\n- Remove X-Fedora category\n\n* Thu Aug 31 2006 Adam Goode <adam@spicenitz.org> - 7.10.21-1\n- New upstream release\n\n* Sun Aug 13 2006 Adam Goode <adam@spicenitz.org> - 7.10.20-2\n- Fix location of documentation in program so help works\n- Semicolon-terminate Category entry in desktop file\n\n* Sat Jul 22 2006 Adam Goode <adam@spicenitz.org> - 7.10.20-1\n- New upstream release\n- Updated for FC5\n\n* Thu Jan 30 2003 John Cupitt <john.cupitt@ng-london.org.uk> 7.8.6-1\n- first stab at an rpm package for nip\n"
  },
  {
    "path": "nip2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n  <mime-type type=\"image/x-vips\">\n    <comment>VIPS image</comment>\n    <comment xml:lang=\"en\">VIPS image</comment>\n    <magic priority=\"50\">\n      <match type=\"string\" value=\"\\xa6\\xb6\" offset=\"0\"/>\n      <match type=\"string\" value=\"\\x08\\xf2\" offset=\"0\"/>\n    </magic>\n    <glob pattern=\"*.v\"/>\n  </mime-type>\n</mime-info>\n"
  },
  {
    "path": "po/ChangeLog",
    "content": "+ en_UK translation\n"
  },
  {
    "path": "po/LINGUAS",
    "content": ""
  },
  {
    "path": "po/POTFILES.in",
    "content": "src/conversionview.c\nsrc/vector.c\nsrc/tslider.c\nsrc/fontnameview.c\nsrc/workspacegroup.c\nsrc/iobject.c\nsrc/plotview.c\nsrc/matrix.c\nsrc/option.c\nsrc/managed.c\nsrc/vipsobject.c\nsrc/optionview.c\nsrc/toolkitbrowser.c\nsrc/imagepresent.c\nsrc/secret.c\nsrc/paintboxview.c\nsrc/prefworkspaceview.c\nsrc/boxes.c\nsrc/toggleview.c\nsrc/columnview.c\nsrc/lex.c\nsrc/row.c\nsrc/nipmarshal.c\nsrc/imagemodel.c\nsrc/imagedisplay.c\nsrc/sliderview.c\nsrc/colourview.c\nsrc/matrixview.c\nsrc/subcolumn.c\nsrc/iwindow.c\nsrc/real.c\nsrc/pane.c\nsrc/log.c\nsrc/heap.c\nsrc/heapmodel.c\nsrc/prefs.c\nsrc/symbol.c\nsrc/imageview.c\nsrc/parse.c\nsrc/managedgvalue.c\nsrc/conversion.c\nsrc/trace.c\nsrc/gtkutil.c\nsrc/slider.c\nsrc/action.c\nsrc/rowview.c\nsrc/column.c\nsrc/model.c\nsrc/iregiongroupview.c\nsrc/pathname.c\nsrc/panechild.c\nsrc/stringview.c\nsrc/iregion.c\nsrc/expr.c\nsrc/itext.c\nsrc/iregiongroup.c\nsrc/predicate.c\nsrc/icontainer.c\nsrc/iarrow.c\nsrc/expressionview.c\nsrc/workspace.c\nsrc/toolkitgroup.c\nsrc/iimage.c\nsrc/main.c\nsrc/toolkitview.c\nsrc/imageinfo.c\nsrc/string.c\nsrc/editview.c\nsrc/tree.c\nsrc/plotpresent.c\nsrc/dump.c\nsrc/colour.c\nsrc/number.c\nsrc/mainw.c\nsrc/popupbutton.c\nsrc/iimageview.c\nsrc/managedstring.c\nsrc/regionview.c\nsrc/idialog.c\nsrc/call.c\nsrc/class.c\nsrc/preview.c\nsrc/filemodel.c\nsrc/builtin.c\nsrc/compile.c\nsrc/pathnameview.c\nsrc/spin.c\nsrc/error.c\nsrc/tool.c\nsrc/floatwindow.c\nsrc/util.c\nsrc/view.c\nsrc/plotmodel.c\nsrc/iregionview.c\nsrc/formula.c\nsrc/valueview.c\nsrc/colourdisplay.c\nsrc/plotwindow.c\nsrc/numberview.c\nsrc/path.c\nsrc/workspaceview.c\nsrc/rhsview.c\nsrc/imageheader.c\nsrc/toggle.c\nsrc/filesel.c\nsrc/toolkitgroupview.c\nsrc/link.c\nsrc/rhs.c\nsrc/classmodel.c\nsrc/toolview.c\nsrc/toolkit.c\nsrc/watch.c\nsrc/expression.c\nsrc/clock.c\nsrc/graphwindow.c\nsrc/managedgobject.c\nsrc/workspacedefs.c\nsrc/group.c\nsrc/statusview.c\nsrc/itextview.c\nsrc/graphicview.c\nsrc/reduce.c\nsrc/doubleclick.c\nsrc/nip2-cli.c\nsrc/defbrowser.c\nsrc/plotstatus.c\nsrc/vobject.c\nsrc/plot.c\nsrc/subcolumnview.c\nsrc/value.c\nsrc/program.c\nsrc/fontname.c\nsrc/prefcolumnview.c\nsrc/managedfile.c\nsrc/cache.c\nsrc/progress.c\n"
  },
  {
    "path": "po/POTFILES.skip",
    "content": "src/parse.c\nsrc/lex.c\n"
  },
  {
    "path": "po/POTFILES2",
    "content": "\t../src/action.c \\\n\t../src/action.h \\\n\t../src/boxes.c \\\n\t../src/boxes.h \\\n\t../src/browse.c \\\n\t../src/browse.h \\\n\t../src/builtin.c \\\n\t../src/builtin.h \\\n\t../src/class.c \\\n\t../src/class.h \\\n\t../src/classmodel.c \\\n\t../src/classmodel.h \\\n\t../src/colour.c \\\n\t../src/colour.h \\\n\t../src/colourdisplay.c \\\n\t../src/colourdisplay.h \\\n\t../src/colourview.c \\\n\t../src/colourview.h \\\n\t../src/column.c \\\n\t../src/column.h \\\n\t../src/columnview.c \\\n\t../src/columnview.h \\\n\t../src/compile.c \\\n\t../src/compile.h \\\n\t../src/conversion.c \\\n\t../src/conversion.h \\\n\t../src/conversionview.c \\\n\t../src/conversionview.h \\\n\t../src/doubleclick.c \\\n\t../src/doubleclick.h \\\n\t../src/dump.c \\\n\t../src/dump.h \\\n\t../src/editview.c \\\n\t../src/editview.h \\\n\t../src/expr.c \\\n\t../src/expr.h \\\n\t../src/expression.c \\\n\t../src/expression.h \\\n\t../src/expressionview.c \\\n\t../src/expressionview.h \\\n\t../src/filemodel.c \\\n\t../src/filemodel.h \\\n\t../src/filesel.c \\\n\t../src/filesel.h \\\n\t../src/fontname.c \\\n\t../src/fontname.h \\\n\t../src/fontnameview.c \\\n\t../src/fontnameview.h \\\n\t../src/formula.c \\\n\t../src/formula.h \\\n\t../src/graph.c \\\n\t../src/graph.h \\\n\t../src/graphicview.c \\\n\t../src/graphicview.h \\\n\t../src/group.c \\\n\t../src/group.h \\\n\t../src/groupview.c \\\n\t../src/groupview.h \\\n\t../src/gtkutil.c \\\n\t../src/gtkutil.h \\\n\t../src/heap.c \\\n\t../src/heap.h \\\n\t../src/heapmodel.c \\\n\t../src/heapmodel.h \\\n\t../src/helpindex.h \\\n\t../src/iarrow.c \\\n\t../src/iarrow.h \\\n\t../src/iarrowview.c \\\n\t../src/iarrowview.h \\\n\t../src/icontainer.c \\\n\t../src/icontainer.h \\\n\t../src/idialog.c \\\n\t../src/idialog.h \\\n\t../src/iimage.c \\\n\t../src/iimage.h \\\n\t../src/iimageview.c \\\n\t../src/iimageview.h \\\n\t../src/imagedisplay.c \\\n\t../src/imagedisplay.h \\\n\t../src/imageinfo.c \\\n\t../src/imageinfo.h \\\n\t../src/imagemodel.c \\\n\t../src/imagemodel.h \\\n\t../src/imagepresent.c \\\n\t../src/imagepresent.h \\\n\t../src/imageview.c \\\n\t../src/imageview.h \\\n\t../src/iobject.c \\\n\t../src/iobject.h \\\n\t../src/ip.h \\\n\t../src/iregion.c \\\n\t../src/iregion.h \\\n\t../src/iregiongroup.c \\\n\t../src/iregiongroup.h \\\n\t../src/iregiongroupview.c \\\n\t../src/iregiongroupview.h \\\n\t../src/iregionview.c \\\n\t../src/iregionview.h \\\n\t../src/istring.h \\\n\t../src/itext.c \\\n\t../src/itext.h \\\n\t../src/itextview.c \\\n\t../src/itextview.h \\\n\t../src/iwindow.c \\\n\t../src/iwindow.h \\\n\t../src/led.c \\\n\t../src/led.h \\\n\t../src/lex.l \\\n\t../src/link.c \\\n\t../src/link.h \\\n\t../src/main.c \\\n\t../src/main.h \\\n\t../src/mainw.c \\\n\t../src/mainw.h \\\n\t../src/matrix.c \\\n\t../src/matrix.h \\\n\t../src/matrixview.c \\\n\t../src/matrixview.h \\\n\t../src/model.c \\\n\t../src/model.h \\\n\t../src/nipmarshal.c \\\n\t../src/nipmarshal.h \\\n\t../src/number.c \\\n\t../src/number.h \\\n\t../src/numberview.c \\\n\t../src/numberview.h \\\n\t../src/option.c \\\n\t../src/option.h \\\n\t../src/optionview.c \\\n\t../src/optionview.h \\\n\t../src/orderitem.c \\\n\t../src/orderitem.h \\\n\t../src/orderlist.c \\\n\t../src/orderlist.h \\\n\t../src/paintboxview.c \\\n\t../src/paintboxview.h \\\n\t../src/parse.y \\\n\t../src/path.c \\\n\t../src/path.h \\\n\t../src/pathname.c \\\n\t../src/pathname.h \\\n\t../src/pathnameview.c \\\n\t../src/pathnameview.h \\\n\t../src/predicate.c \\\n\t../src/predicate.h \\\n\t../src/prefs.c \\\n\t../src/prefs.h \\\n\t../src/program.c \\\n\t../src/program.h \\\n\t../src/reduce.c \\\n\t../src/reduce.h \\\n\t../src/regionview.c \\\n\t../src/regionview.h \\\n\t../src/rhs.c \\\n\t../src/rhs.h \\\n\t../src/rhsview.c \\\n\t../src/rhsview.h \\\n\t../src/row.c \\\n\t../src/row.h \\\n\t../src/rowview.c \\\n\t../src/rowview.h \\\n\t../src/secret.c \\\n\t../src/secret.h \\\n\t../src/slider.c \\\n\t../src/slider.h \\\n\t../src/sliderview.c \\\n\t../src/sliderview.h \\\n\t../src/spin.c \\\n\t../src/spin.h \\\n\t../src/statusview.c \\\n\t../src/statusview.h \\\n\t../src/string.c \\\n\t../src/stringview.c \\\n\t../src/stringview.h \\\n\t../src/subcolumn.c \\\n\t../src/subcolumn.h \\\n\t../src/subcolumnview.c \\\n\t../src/subcolumnview.h \\\n\t../src/symbol.c \\\n\t../src/symbol.h \\\n\t../src/toggle.c \\\n\t../src/toggle.h \\\n\t../src/toggleview.c \\\n\t../src/toggleview.h \\\n\t../src/tool.c \\\n\t../src/tool.h \\\n\t../src/toolkit.c \\\n\t../src/toolkit.h \\\n\t../src/toolkitbrowser.c \\\n\t../src/toolkitbrowser.h \\\n\t../src/toolkitgroup.c \\\n\t../src/toolkitgroup.h \\\n\t../src/toolkitgroupview.c \\\n\t../src/toolkitgroupview.h \\\n\t../src/toolkitview.c \\\n\t../src/toolkitview.h \\\n\t../src/toolview.c \\\n\t../src/toolview.h \\\n\t../src/trace.c \\\n\t../src/trace.h \\\n\t../src/tree.c \\\n\t../src/tree.h \\\n\t../src/tslider.c \\\n\t../src/tslider.h \\\n\t../src/util.c \\\n\t../src/util.h \\\n\t../src/view.c \\\n\t../src/view.h \\\n\t../src/vips_call.c \\\n\t../src/vips_call.h \\\n\t../src/vobject.c \\\n\t../src/vobject.h \\\n\t../src/watch.c \\\n\t../src/watch.h \\\n\t../src/wild.c \\\n\t../src/wild.h \\\n\t../src/workspace.c \\\n\t../src/workspace.h \\\n\t../src/workspacegroup.c \\\n\t../src/workspacegroup.h \\\n\t../src/workspaceview.c \\\n\t../src/workspaceview.h \n"
  },
  {
    "path": "po/en_GB.po",
    "content": "# UK english translation ... just swap color for colour\n# Copyright (C) 2011\n# This file is distributed under the same license as the nip2 package.\n# John Cupitt <jcupitt@gmail.com>, 2011.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: nip2 7.26.0\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2011-07-26 12:33+0100\\n\"\n\"PO-Revision-Date: 2011-07-26 12:40+0100\\n\"\n\"Last-Translator: John Cupitt <jcupitt@gmail.com>\\n\"\n\"Language-Team: en_GB <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=n != 1;\\n\"\n\n#: ../src/action.c:87\nmsgid \"Bad arguments.\"\nmsgstr \"\"\n\n#. Expands to eg. 'bad args to \"+\", called from \"fred\"'\n#.\n#: ../src/action.c:102 ../src/action.c:186\nmsgid \"Called from\"\nmsgstr \"\"\n\n#: ../src/action.c:108\n#, c-format\nmsgid \"\"\n\"Error in binary \\\"%s\\\".\\n\"\n\"left = %s\\n\"\n\"right = %s\\n\"\n\"%s\"\nmsgstr \"\"\n\n#: ../src/action.c:142 ../src/class.c:190\n#, c-format\nmsgid \"Member \\\"%s\\\" not found in class \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/action.c:149\n#, c-format\nmsgid \"object = %s\"\nmsgstr \"\"\n\n#: ../src/action.c:153\n#, c-format\nmsgid \"tag = %s\"\nmsgstr \"\"\n\n#: ../src/action.c:158\n#, c-format\nmsgid \"Reference attempted in \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/action.c:162 ../src/class.c:189\nmsgid \"Member not found.\"\nmsgstr \"\"\n\n#: ../src/action.c:173 ../src/builtin.c:1008 ../src/call.c:249\n#: ../src/class.c:49 ../src/class.c:1027 ../src/reduce.c:898\n#: ../src/reduce.c:911\nmsgid \"Bad argument.\"\nmsgstr \"\"\n\n#: ../src/action.c:192\n#, c-format\nmsgid \"\"\n\"Error in unary \\\"%s\\\".\\n\"\n\"argument = %s\\n\"\n\"%s\"\nmsgstr \"\"\n\n#: ../src/action.c:359 ../src/action.c:377 ../src/action.c:407\nmsgid \"Bad right hand side of '.'.\"\nmsgstr \"\"\n\n#: ../src/action.c:369\nmsgid \"Symbol on left hand side of '.' is not scope\"\nmsgstr \"\"\n\n#: ../src/action.c:411\nmsgid \"Property not found.\"\nmsgstr \"\"\n\n#: ../src/action.c:425\nmsgid \"Bad left hand side of '.'.\"\nmsgstr \"\"\n\n#: ../src/action.c:937\nmsgid \"Division by zero.\"\nmsgstr \"\"\n\n#: ../src/action.c:1313 ../src/action.c:1593\nmsgid \"Unimplemented.\"\nmsgstr \"\"\n\n#: ../src/action.c:1677 ../src/action.c:1713 ../src/action.c:1971\nmsgid \"invoking method:\"\nmsgstr \"\"\n\n#: ../src/boxes.c:251\nmsgid \"Close _without Saving\"\nmsgstr \"\"\n\n#. Translators: translate this to a credit for you, and it'll appear in\n#. * the About box.\n#.\n#: ../src/boxes.c:270\nmsgid \"translator_credits\"\nmsgstr \"\"\n\n#: ../src/boxes.c:279\n#, c-format\nmsgid \"About %s.\"\nmsgstr \"\"\n\n#: ../src/boxes.c:282\n#, c-format\nmsgid \"%s is an image processing package.\"\nmsgstr \"\"\n\n#: ../src/boxes.c:286\n#, c-format\nmsgid \"\"\n\"%s comes with ABSOLUTELY NO WARRANTY. This is free software and you are \"\n\"welcome to redistribute it under certain conditions, see http://www.gnu.org.\"\nmsgstr \"\"\n\n#: ../src/boxes.c:305\nmsgid \"Personal start folder\"\nmsgstr \"\"\n\n#: ../src/boxes.c:309\nmsgid \"Homepage\"\nmsgstr \"\"\n\n#: ../src/boxes.c:312\nmsgid \"Linked to VIPS\"\nmsgstr \"\"\n\n#: ../src/boxes.c:315\nmsgid \"Built against VIPS\"\nmsgstr \"\"\n\n#: ../src/boxes.c:328\nmsgid \"Temp files in\"\nmsgstr \"\"\n\n#: ../src/boxes.c:394\nmsgid \"Help page not found.\"\nmsgstr \"\"\n\n#: ../src/boxes.c:395\n#, c-format\nmsgid \"No indexed help page found for tag \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/boxes.c:604\nmsgid \"Search for\"\nmsgstr \"\"\n\n#: ../src/boxes.c:605\nmsgid \"Case sensitive\"\nmsgstr \"\"\n\n#: ../src/boxes.c:607\nmsgid \"Regular expression\"\nmsgstr \"\"\n\n#: ../src/boxes.c:609\nmsgid \"Search from start\"\nmsgstr \"\"\n\n#: ../src/boxes.c:814\nmsgid \"Image header fields\"\nmsgstr \"\"\n\n#: ../src/boxes.c:830\nmsgid \"Image history\"\nmsgstr \"\"\n\n#: ../src/boxes.c:946 ../src/boxes.c:957 ../src/boxes.c:986\nmsgid \"Unable to view help file.\"\nmsgstr \"\"\n\n#: ../src/boxes.c:947\n#, c-format\nmsgid \"Unable to open URL \\\"%s\\\", windows error code = %d.\"\nmsgstr \"\"\n\n#: ../src/boxes.c:958\n#, c-format\nmsgid \"\"\n\"Attempt to view URL with xdg-open failed\\n\"\n\"%s\"\nmsgstr \"\"\n\n#: ../src/boxes.c:963 ../src/boxes.c:995\nmsgid \"Browser window opened.\"\nmsgstr \"\"\n\n#: ../src/boxes.c:965 ../src/boxes.c:997\nmsgid \"You may need to switch desktops to see the new window.\"\nmsgstr \"\"\n\n#: ../src/boxes.c:988\n#, c-format\nmsgid \"\"\n\"Attempted to launch browser with command:\\n\"\n\"  %s\\n\"\n\"You can change this command in Preferences.\"\nmsgstr \"\"\n\n#: ../src/boxes.c:1029\nmsgid \"Select Font\"\nmsgstr \"\"\n\n#: ../src/boxes.c:1087\nmsgid \"Font not found.\"\nmsgstr \"\"\n\n#: ../src/boxes.c:1088\n#, c-format\nmsgid \"Font \\\"%s\\\" not found on system.\"\nmsgstr \"\"\n\n#: ../src/boxes.c:1168\nmsgid \"Pick a font\"\nmsgstr \"\"\n\n#: ../src/boxes.c:1173\nmsgid \"Set Font\"\nmsgstr \"\"\n\n#: ../src/boxes.c:1219\nmsgid \"Click to select font\"\nmsgstr \"\"\n\n#: ../src/builtin.c:257\nmsgid \"Out of range.\"\nmsgstr \"\"\n\n#: ../src/builtin.c:258\nmsgid \"gammq arguments must be a > 0, x >= 0.\"\nmsgstr \"\"\n\n#: ../src/builtin.c:265\nmsgid \"Not available.\"\nmsgstr \"\"\n\n#: ../src/builtin.c:266\nmsgid \"No GSL library available for gammq.\"\nmsgstr \"\"\n\n#: ../src/builtin.c:422 ../src/classmodel.c:154 ../src/classmodel.c:227\n#: ../src/filemodel.c:100 ../src/filemodel.c:145 ../src/filemodel.c:357\n#: ../src/filemodel.c:583 ../src/filemodel.c:624 ../src/mainw.c:754\n#: ../src/mainw.c:762 ../src/model.c:313 ../src/model.c:368\n#: ../src/rowview.c:456 ../src/view.c:820\nmsgid \"Not implemented.\"\nmsgstr \"\"\n\n#: ../src/builtin.c:423\nmsgid \"Complex math ops not implemented.\"\nmsgstr \"\"\n\n#: ../src/builtin.c:498\nmsgid \"Macro error.\"\nmsgstr \"\"\n\n#: ../src/builtin.c:681\nmsgid \"No such type\"\nmsgstr \"\"\n\n#: ../src/builtin.c:682\n#, c-format\nmsgid \"GType %u not found.\"\nmsgstr \"\"\n\n#: ../src/builtin.c:905\nmsgid \"GSL library error.\"\nmsgstr \"\"\n\n#: ../src/builtin.c:954\n#, c-format\nmsgid \"Builtin \\\"%s\\\" takes %d argument.\"\nmsgid_plural \"Builtin \\\"%s\\\" takes %d arguments.\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\n#: ../src/builtin.c:1009\n#, c-format\nmsgid \"\"\n\"Argument %d to builtin \\\"%s\\\" should be \\\"%s\\\", you passed:\\n\"\n\"  %s\"\nmsgstr \"\"\n\n#: ../src/cache.c:923 ../src/call.c:144 ../src/class.c:862\nmsgid \"You passed:\"\nmsgstr \"\"\n\n#: ../src/cache.c:946 ../src/util.c:191 ../src/vipsobject.c:284\nmsgid \"VIPS library error.\"\nmsgstr \"\"\n\n#: ../src/cache.c:949 ../src/call.c:133\n#, c-format\nmsgid \"Error calling library function \\\"%s\\\" (%s).\"\nmsgstr \"\"\n\n#: ../src/cache.c:952\n#, c-format\nmsgid \"VIPS library: %s\"\nmsgstr \"\"\n\n#: ../src/call.c:132\nmsgid \"CALL library error.\"\nmsgstr \"\"\n\n#: ../src/call.c:192\nmsgid \"Usage:\"\nmsgstr \"\"\n\n#: ../src/call.c:194\n#, c-format\nmsgid \"CALL operator \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/call.c:196\n#, c-format\nmsgid \"%s, from package \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/call.c:201\n#, c-format\nmsgid \"\\\"%s\\\" takes %d argument:\"\nmsgid_plural \"\\\"%s\\\" takes %d arguments:\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\n#: ../src/call.c:208\n#, c-format\nmsgid \"And produces %d result:\"\nmsgid_plural \"And produces %d results:\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\n#. Print any flags this function has.\n#.\n#: ../src/call.c:216\nmsgid \"Flags:\"\nmsgstr \"\"\n\n#: ../src/call.c:220\nmsgid \"PIO function\"\nmsgstr \"\"\n\n#: ../src/call.c:222\nmsgid \"WIO function\"\nmsgstr \"\"\n\n#: ../src/call.c:225\nmsgid \"coordinate transformer\"\nmsgstr \"\"\n\n#: ../src/call.c:227\nmsgid \"no coordinate transformation\"\nmsgstr \"\"\n\n#: ../src/call.c:230\nmsgid \"point-to-point operation\"\nmsgstr \"\"\n\n#: ../src/call.c:232\nmsgid \"area operation\"\nmsgstr \"\"\n\n#: ../src/call.c:235\nmsgid \"uncacheable operation\"\nmsgstr \"\"\n\n#: ../src/call.c:237\nmsgid \"operation can be cached\"\nmsgstr \"\"\n\n#: ../src/call.c:252\n#, c-format\nmsgid \"Argument %d (%s) to \\\"%s\\\" is the wrong type.\"\nmsgstr \"\"\n\n#: ../src/call.c:269 ../src/class.c:657 ../src/class.c:889 ../src/class.c:986\n#: ../src/compile.c:1766 ../src/vipsobject.c:125\nmsgid \"Too many arguments.\"\nmsgstr \"\"\n\n#: ../src/call.c:272\n#, c-format\nmsgid \"Too many arguments to \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/call.c:290\nmsgid \"Unknown type.\"\nmsgstr \"\"\n\n#: ../src/call.c:291\n#, c-format\nmsgid \"CALL type \\\"%s\\\" not supported\"\nmsgstr \"\"\n\n#: ../src/call.c:1262 ../src/call.c:1346\n#, c-format\nmsgid \"image \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/call.c:1269\nmsgid \"no image\"\nmsgstr \"\"\n\n#: ../src/call.c:1300\nmsgid \"doublevec\"\nmsgstr \"\"\n\n#: ../src/call.c:1342\nmsgid \"imagevec\"\nmsgstr \"\"\n\n#: ../src/class.c:50\n#, c-format\nmsgid \"Object %s is not a class.\"\nmsgstr \"\"\n\n#: ../src/class.c:333\nmsgid \"No such secret.\"\nmsgstr \"\"\n\n#: ../src/class.c:334\nmsgid \"\"\n\"Editing local classes which reference non-local objects is a bit broken at \"\n\"the moment :-(\"\nmsgstr \"\"\n\n#: ../src/class.c:658\n#, c-format\nmsgid \"You can't have more than %d arguments to a superclass constructor.\"\nmsgstr \"\"\n\n#: ../src/class.c:794 ../src/class.c:854\nmsgid \"Bad superclass.\"\nmsgstr \"\"\n\n#: ../src/class.c:795\n#, c-format\nmsgid \"Superclass constructor \\\"%s\\\" refers to non-local symbols %s\"\nmsgstr \"\"\n\n#: ../src/class.c:803 ../src/workspace.c:1693\nmsgid \"Wrong number of arguments.\"\nmsgstr \"\"\n\n#: ../src/class.c:804\n#, c-format\nmsgid \"Superclass constructor \\\"%s\\\" expects %d arguments, not %d.\"\nmsgstr \"\"\n\n#: ../src/class.c:858\n#, c-format\nmsgid \"First element in superclass of \\\"%s\\\" must be class or constructor.\"\nmsgstr \"\"\n\n#: ../src/class.c:890 ../src/class.c:987\n#, c-format\nmsgid \"\"\n\"Too many arguments to class constructor \\\"%s\\\". No more than %d arguments \"\n\"are supported.\"\nmsgstr \"\"\n\n#: ../src/class.c:980\nmsgid \"Class not found.\"\nmsgstr \"\"\n\n#: ../src/class.c:981\n#, c-format\nmsgid \"Class \\\"%s\\\" not found.\"\nmsgstr \"\"\n\n#: ../src/class.c:1018\n#, c-format\nmsgid \"Member \\\"%s\\\" of class \\\"%s\\\" should be of type \\\"%s\\\", instead it's:\"\nmsgstr \"\"\n\n#: ../src/classmodel.c:155 ../src/classmodel.c:228\n#, c-format\nmsgid \"_%s() method not implemented for %s.\"\nmsgstr \"\"\n\n#: ../src/classmodel.c:163\n#, c-format\nmsgid \"Save %s \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/classmodel.c:237\n#, c-format\nmsgid \"Replace %s \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/classmodel.c:695\nmsgid \"Set boolean value here\"\nmsgstr \"\"\n\n#: ../src/classmodel.c:701\nmsgid \"Enter a floating point number here\"\nmsgstr \"\"\n\n#: ../src/classmodel.c:708\nmsgid \"Enter a string here\"\nmsgstr \"\"\n\n#. Expands to \"Edit Toggle A1\".\n#.\n#: ../src/classmodel.c:762\n#, c-format\nmsgid \"Edit %s %s\"\nmsgstr \"\"\n\n#: ../src/classmodel.c:773\n#, c-format\nmsgid \"Set %s\"\nmsgstr \"\"\n\n#: ../src/classmodel.c:1069\nmsgid \"Unknown option.\"\nmsgstr \"\"\n\n#: ../src/classmodel.c:1070\n#, c-format\nmsgid \"Option \\\"%s\\\" not known.\"\nmsgstr \"\"\n\n#: ../src/classmodel.c:1144 ../src/matrixview.c:189 ../src/matrixview.c:210\n#: ../src/plot.c:140 ../src/plot.c:150 ../src/plot.c:360 ../src/plot.c:379\n#: ../src/plot.c:392\nmsgid \"Bad value.\"\nmsgstr \"\"\n\n#: ../src/classmodel.c:1145\n#, c-format\nmsgid \"%d band value only\"\nmsgstr \"\"\n\n#: ../src/clock.c:59 ../src/clock.c:93 ../src/clock.c:190\nmsgid \"Interval\"\nmsgstr \"\"\n\n#: ../src/clock.c:60 ../src/clock.c:96\nmsgid \"Elapsed time\"\nmsgstr \"\"\n\n#: ../src/clock.c:93\nmsgid \"Interval between ticks (seconds)\"\nmsgstr \"\"\n\n#: ../src/clock.c:96\nmsgid \"Elapsed time (seconds)\"\nmsgstr \"\"\n\n#: ../src/clock.c:100\n#, c-format\nmsgid \"Edit Clock \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/clock.c:104\nmsgid \"Set Clock\"\nmsgstr \"\"\n\n#: ../src/clock.c:193 ../src/colour.c:305 ../src/fontname.c:61\n#: ../src/matrix.c:262 ../src/number.c:68 ../src/option.c:71\n#: ../src/pathname.c:84 ../src/plot.c:340 ../src/slider.c:57\n#: ../src/string.c:70 ../src/toggle.c:51\nmsgid \"Value\"\nmsgstr \"\"\n\n#: ../src/colour.c:264\n#, c-format\nmsgid \"Edit Color \\\"%s\\\"\"\nmsgstr \"Edit Colour \\\"%s\\\"\"\n\n#: ../src/colour.c:270\nmsgid \"Set Color\"\nmsgstr \"Set Colour\"\n\n#: ../src/colour.c:302\nmsgid \"Color Space\"\nmsgstr \"Colour Space\"\n\n#: ../src/colourdisplay.c:259\nmsgid \"Double-click to edit this color, or drag-and-drop between colors\"\nmsgstr \"Double-click to edit this colour, or drag-and-drop between colours\"\n\n#: ../src/column.c:326 ../src/tool.c:867 ../src/workspace.c:1529\n#: ../src/workspacegroup.c:145\nmsgid \"Name clash.\"\nmsgstr \"\"\n\n#: ../src/column.c:327\n#, c-format\nmsgid \"Can't create column \\\"%s\\\". A column with that name already exists.\"\nmsgstr \"\"\n\n#: ../src/column.c:364\nmsgid \"Empty column.\"\nmsgstr \"\"\n\n#: ../src/column.c:365\nmsgid \"There are no objects in the current column.\"\nmsgstr \"\"\n\n#: ../src/column.c:384\nmsgid \"Too few items.\"\nmsgstr \"\"\n\n#: ../src/column.c:385\n#, c-format\nmsgid \"This column only has %d items, but %s needs %d items.\"\nmsgstr \"\"\n\n#: ../src/columnview.c:133\n#, c-format\nmsgid \"Save Column \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/columnview.c:180 ../src/columnview.c:241 ../src/mainw.c:1369\n#: ../src/mainw.c:1407 ../src/program.c:596 ../src/program.c:625\n#: ../src/program.c:1052 ../src/program.c:1093 ../src/program.c:1139\n#: ../src/program.c:1171 ../src/program.c:1503 ../src/program.c:1544\n#: ../src/program.c:2201 ../src/row.c:480 ../src/workspacegroup.c:177\n#: ../src/workspacegroup.c:213\nmsgid \"Name\"\nmsgstr \"\"\n\n#: ../src/columnview.c:181 ../src/columnview.c:243\nmsgid \"Toolkit\"\nmsgstr \"\"\n\n#: ../src/columnview.c:182 ../src/columnview.c:245 ../src/matrix.c:271\n#: ../src/program.c:597 ../src/program.c:627 ../src/program.c:1140\n#: ../src/program.c:1173\nmsgid \"Filename\"\nmsgstr \"\"\n\n#: ../src/columnview.c:241\nmsgid \"Set menu item text here\"\nmsgstr \"\"\n\n#: ../src/columnview.c:243\nmsgid \"Add to this toolkit\"\nmsgstr \"\"\n\n#: ../src/columnview.c:245\nmsgid \"Store column in this file\"\nmsgstr \"\"\n\n#: ../src/columnview.c:248\n#, c-format\nmsgid \"New Menu Item from Column \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/columnview.c:253\nmsgid \"Menuize\"\nmsgstr \"\"\n\n#: ../src/columnview.c:648\nmsgid \"Edit caption, press enter to accept changes, press escape to cancel\"\nmsgstr \"\"\n\n#: ../src/columnview.c:701\nmsgid \"Enter expressions here\"\nmsgstr \"\"\n\n#: ../src/columnview.c:755\nmsgid \"doubleclick to set title\"\nmsgstr \"\"\n\n#: ../src/columnview.c:764\nmsgid \"Fold the column away\"\nmsgstr \"\"\n\n#: ../src/columnview.c:769\nmsgid \"Open the column\"\nmsgstr \"\"\n\n#: ../src/columnview.c:893\nmsgid \"Column menu\"\nmsgstr \"\"\n\n#: ../src/columnview.c:894\nmsgid \"_Edit Caption\"\nmsgstr \"\"\n\n#: ../src/columnview.c:896 ../src/mainw.c:1708 ../src/program.c:1719\nmsgid \"Select _All\"\nmsgstr \"\"\n\n#: ../src/columnview.c:903\nmsgid \"Make Column Into _Menu Item\"\nmsgstr \"\"\n\n#: ../src/columnview.c:940\nmsgid \"Left-drag to move, left-double-click to set title, right-click for menu\"\nmsgstr \"\"\n\n#: ../src/columnview.c:973\nmsgid \"Delete the column\"\nmsgstr \"\"\n\n#: ../src/compile.c:1448\nmsgid \"Too many shared nodes in graph.\"\nmsgstr \"\"\n\n#: ../src/compile.c:1450\nmsgid \"Raise MAX_RELOC\"\nmsgstr \"\"\n\n#: ../src/compile.c:1767\n#, c-format\nmsgid \"Member \\\"%s\\\" of class \\\"%s\\\" should have no arguments.\"\nmsgstr \"\"\n\n#: ../src/compile.c:2644\nmsgid \"pattern match failed\"\nmsgstr \"\"\n\n#: ../src/conversion.c:473\nmsgid \"not uncoded\"\nmsgstr \"\"\n\n#: ../src/conversion.c:1415\n#, c-format\nmsgid \"Header for \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/conversion.c:1417\nmsgid \"OK\"\nmsgstr \"\"\n\n#: ../src/conversionview.c:66\nmsgid \"Unable to find image range.\"\nmsgstr \"\"\n\n#: ../src/conversionview.c:67\nmsgid \"Find image range failed.\"\nmsgstr \"\"\n\n#: ../src/conversionview.c:90\nmsgid \"Unable to scale image.\"\nmsgstr \"\"\n\n#: ../src/conversionview.c:91\nmsgid \"Maximum and minimum pixel values are equal.\"\nmsgstr \"\"\n\n#. Build menu. One for each window, as we need to track falsecolour\n#. * etc. toggles. Could just have one, and modify pre-popup, but this\n#. * is easier.\n#.\n#: ../src/conversionview.c:229\nmsgid \"Convert menu\"\nmsgstr \"\"\n\n#: ../src/conversionview.c:230\nmsgid \"_Scale\"\nmsgstr \"\"\n\n#: ../src/conversionview.c:232\nmsgid \"_False Color\"\nmsgstr \"_False Colour\"\n\n#: ../src/conversionview.c:234\nmsgid \"_Interpret\"\nmsgstr \"\"\n\n#: ../src/conversionview.c:236 ../src/regionview.c:1020\nmsgid \"_Reset\"\nmsgstr \"\"\n\n#: ../src/conversionview.c:238\nmsgid \"Set As Workspace _Default\"\nmsgstr \"\"\n\n#: ../src/dump.c:186 ../src/expr.c:641\nmsgid \"value\"\nmsgstr \"\"\n\n#: ../src/dump.c:187\nmsgid \"parameter\"\nmsgstr \"\"\n\n#: ../src/dump.c:188\nmsgid \"zombie\"\nmsgstr \"\"\n\n#: ../src/dump.c:189 ../src/util.c:1349\nmsgid \"workspace\"\nmsgstr \"\"\n\n#: ../src/dump.c:190\nmsgid \"workspace group\"\nmsgstr \"\"\n\n#: ../src/dump.c:191\nmsgid \"root symbol\"\nmsgstr \"\"\n\n#: ../src/dump.c:192\nmsgid \"external symbol\"\nmsgstr \"\"\n\n#: ../src/dump.c:193\nmsgid \"built-in symbol\"\nmsgstr \"\"\n\n#: ../src/editview.c:79 ../src/fontnameview.c:80 ../src/formula.c:198\n#: ../src/gtkutil.c:756 ../src/gtkutil.c:791 ../src/gtkutil.c:845\n#: ../src/optionview.c:172 ../src/pathnameview.c:80 ../src/sliderview.c:74\n#, c-format\nmsgid \"%s:\"\nmsgstr \"\"\n\n#: ../src/editview.c:158\nmsgid \"Escape to cancel edit, press Return to accept edit and recalculate\"\nmsgstr \"\"\n\n#: ../src/error.c:60\nmsgid \"No ierrors found.\"\nmsgstr \"\"\n\n#: ../src/error.c:100\nmsgid \"No unresolved symbols found.\"\nmsgstr \"\"\n\n#: ../src/error.c:115 ../src/trace.c:230\nmsgid \"_Clear\"\nmsgstr \"\"\n\n#: ../src/error.c:116\nmsgid \"Clear ierror window\"\nmsgstr \"\"\n\n#: ../src/error.c:120\nmsgid \"List _iErrors\"\nmsgstr \"\"\n\n#: ../src/error.c:121\nmsgid \"Search for all ierrors\"\nmsgstr \"\"\n\n#: ../src/error.c:125\nmsgid \"List _Unresolved\"\nmsgstr \"\"\n\n#: ../src/error.c:126\nmsgid \"Search for all unresolved references\"\nmsgstr \"\"\n\n#: ../src/error.c:202\n#, c-format\nmsgid \"iError - %s\"\nmsgstr \"\"\n\n#: ../src/expr.c:64\n#, c-format\nmsgid \"error in \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/expr.c:346\nmsgid \"Error\"\nmsgstr \"\"\n\n#: ../src/expr.c:613\nmsgid \"top level\"\nmsgstr \"\"\n\n#: ../src/expr.c:618\nmsgid \"class\"\nmsgstr \"\"\n\n#: ../src/expr.c:621\nmsgid \"instance\"\nmsgstr \"\"\n\n#: ../src/expr.c:625\nmsgid \"definition\"\nmsgstr \"\"\n\n#: ../src/expr.c:632\n#, c-format\nmsgid \"parameter \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/expr.c:636\nmsgid \"member\"\nmsgstr \"\"\n\n#: ../src/expr.c:645 ../src/itext.c:446\nmsgid \"function\"\nmsgstr \"\"\n\n#: ../src/expr.c:654\nmsgid \"of\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:101 ../src/filemodel.c:146 ../src/filemodel.c:584\n#: ../src/filemodel.c:625 ../src/model.c:314 ../src/model.c:369\n#: ../src/model.c:388\n#, c-format\nmsgid \"_%s() not implemented for class \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:270 ../src/filemodel.c:285 ../src/model.c:419\nmsgid \"XML library error.\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:271\nmsgid \"model_save_filename: xmlNewDoc() failed\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:286\nmsgid \"model_save_filename: xmlNewDocNode() failed\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:302\nmsgid \"Save failed.\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:303\n#, c-format\nmsgid \"\"\n\"Save of %s \\\"%s\\\" to file \\\"%s\\\" failed.\\n\"\n\"%s\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:358\nmsgid \"filemodel_real_save_all: no save method\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:469 ../src/filemodel.c:478 ../src/filemodel.c:491\n#: ../src/mainw.c:1022 ../src/model.c:130\nmsgid \"Load failed.\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:470\n#, c-format\nmsgid \"Can't load XML file \\\"%s\\\", it's not a %s save file.\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:479\n#, c-format\nmsgid \"\"\n\"Can't load XML file \\\"%s\\\", unable to extract version information from \"\n\"namespace.\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:492\n#, c-format\nmsgid \"Can't load XML file \\\"%s\\\", the file does not contain a %s.\"\nmsgstr \"\"\n\n#. Expands to (eg.) \"Save Column A2\".\n#.\n#: ../src/filemodel.c:677\n#, c-format\nmsgid \"Save %s %s\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:753 ../src/filemodel.c:765\nmsgid \"Object has been modified.\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:754\n#, c-format\nmsgid \"\"\n\"%s \\\"%s\\\" has been modified since you loaded it from file \\\"%s\\\".\\n\"\n\"\\n\"\n\"Do you want to save your changes?\"\nmsgstr \"\"\n\n#: ../src/filemodel.c:766\n#, c-format\nmsgid \"%s \\\"%s\\\" has been modified. Do you want to save your changes?\"\nmsgstr \"\"\n\n#: ../src/filesel.c:86\nmsgid \"Workspace files (*.ws)\"\nmsgstr \"\"\n\n#: ../src/filesel.c:88\nmsgid \"Recombination matrix files (*.rec)\"\nmsgstr \"\"\n\n#: ../src/filesel.c:90\nmsgid \"Morphology matrix files (*.mor)\"\nmsgstr \"\"\n\n#: ../src/filesel.c:92\nmsgid \"Convolution matrix files (*.con)\"\nmsgstr \"\"\n\n#: ../src/filesel.c:94\nmsgid \"Matrix files (*.mat)\"\nmsgstr \"\"\n\n#: ../src/filesel.c:96\nmsgid \"Definition files (*.def)\"\nmsgstr \"\"\n\n#: ../src/filesel.c:98\nmsgid \"ICC profiles (*.icc, *.icm)\"\nmsgstr \"\"\n\n#: ../src/filesel.c:100\nmsgid \"All files (*)\"\nmsgstr \"\"\n\n#. Used as eg. \"VIPS image files (*.v)\"\n#.\n#: ../src/filesel.c:133\nmsgid \"image files\"\nmsgstr \"\"\n\n#: ../src/filesel.c:500\n#, c-format\nmsgid \"Unable to determine space free in \\\"%s\\\".\"\nmsgstr \"\"\n\n#. Expands to (eg.) '6GB free in \"/pics/tmp\"'\n#.\n#: ../src/filesel.c:511\n#, c-format\nmsgid \"free in \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/filesel.c:759 ../src/util.c:1932 ../src/util.c:1938\nmsgid \"Bad filename.\"\nmsgstr \"\"\n\n#: ../src/filesel.c:760\nmsgid \"No file selected.\"\nmsgstr \"\"\n\n#: ../src/filesel.c:973\nmsgid \"Increment filename\"\nmsgstr \"\"\n\n#: ../src/filesel.c:979\nmsgid \"After Save, add 1 to the last number in the file name\"\nmsgstr \"\"\n\n#: ../src/filesel.c:1220\n#, c-format\nmsgid \"%s Save Preferences\"\nmsgstr \"\"\n\n#: ../src/filesel.c:1281\nmsgid \"Overwrite\"\nmsgstr \"\"\n\n#: ../src/filesel.c:1282\nmsgid \"Overwrite file?\"\nmsgstr \"\"\n\n#: ../src/filesel.c:1283\n#, c-format\nmsgid \"File \\\"%s\\\" exists. OK to overwrite?\"\nmsgstr \"\"\n\n#: ../src/fontname.c:58 ../src/mainw.c:1370 ../src/mainw.c:1409\n#: ../src/number.c:65 ../src/option.c:65 ../src/pathname.c:81\n#: ../src/program.c:1053 ../src/program.c:1095 ../src/slider.c:48\n#: ../src/string.c:67 ../src/toggle.c:48 ../src/workspacegroup.c:178\n#: ../src/workspacegroup.c:215\nmsgid \"Caption\"\nmsgstr \"\"\n\n#: ../src/formula.c:143\nmsgid \"\"\n\"Press Escape to cancel edit, press Return to accept edit and recalculate\"\nmsgstr \"\"\n\n#: ../src/gtkutil.c:608\nmsgid \"Bad identifier.\"\nmsgstr \"\"\n\n#: ../src/gtkutil.c:610\nmsgid \"\"\n\"Enter an identifier. Identifiers start with a letter, and then contain only \"\n\"letters, numbers, apostrophy and underscore.\"\nmsgstr \"\"\n\n#: ../src/gtkutil.c:663 ../src/gtkutil.c:671 ../src/matrixview.c:96\nmsgid \"Bad floating point number.\"\nmsgstr \"\"\n\n#: ../src/gtkutil.c:664 ../src/matrixview.c:97\n#, c-format\nmsgid \"\\\"%s\\\" is not a floating point number.\"\nmsgstr \"\"\n\n#: ../src/gtkutil.c:672\n#, c-format\nmsgid \"Extra characters \\\"%s\\\" after number.\"\nmsgstr \"\"\n\n#: ../src/gtkutil.c:696\nmsgid \"Bad integer.\"\nmsgstr \"\"\n\n#: ../src/gtkutil.c:697\n#, c-format\nmsgid \"\\\"%s\\\" is not an integer.\"\nmsgstr \"\"\n\n#: ../src/gtkutil.c:715\nmsgid \"Bad unsigned integer.\"\nmsgstr \"\"\n\n#: ../src/gtkutil.c:731\nmsgid \"Bad positive integer.\"\nmsgstr \"\"\n\n#: ../src/gtkutil.c:853 ../src/toggleview.c:106\nmsgid \"Left-click to change value\"\nmsgstr \"\"\n\n#: ../src/heap.c:812\nmsgid \"Heap full.\"\nmsgstr \"\"\n\n#: ../src/heap.c:818\n#, c-format\nmsgid \"\"\n\"The compile heap for %s has filled. Make it smaller and less complicated.\"\nmsgstr \"\"\n\n#: ../src/heap.c:823\nmsgid \"\"\n\"The main calculation heap has filled. Raise the heap size limit in \"\n\"Preferences.\"\nmsgstr \"\"\n\n#: ../src/heap.c:1852\nmsgid \"Unimplemented list type.\"\nmsgstr \"\"\n\n#: ../src/heap.c:1947\nmsgid \"Unimplemented type.\"\nmsgstr \"\"\n\n#: ../src/heap.c:1948\n#, c-format\nmsgid \"Unable to convert %s to a nip type.\"\nmsgstr \"\"\n\n#: ../src/heap.c:2111\nmsgid \"circular\"\nmsgstr \"\"\n\n#: ../src/heap.c:2116\n#, c-format\nmsgid \"circular to label %d\"\nmsgstr \"\"\n\n#: ../src/heap.c:2126\n#, c-format\nmsgid \"label %d\"\nmsgstr \"\"\n\n#: ../src/heap.c:2143\nmsgid \"unevaluated\"\nmsgstr \"\"\n\n#: ../src/heap.c:2178\n#, c-format\nmsgid \"class (%p)\"\nmsgstr \"\"\n\n#: ../src/heap.c:2189\nmsgid \"members\"\nmsgstr \"\"\n\n#: ../src/heap.c:2200\nmsgid \"secret\"\nmsgstr \"\"\n\n#: ../src/heap.c:2253\n#, c-format\nmsgid \"no value (type %d)\"\nmsgstr \"\"\n\n#: ../src/heap.c:2261\nmsgid \"NULL pointer\"\nmsgstr \"\"\n\n#: ../src/heap.c:2270\nmsgid \"symbol\"\nmsgstr \"\"\n\n#: ../src/heap.c:2278\nmsgid \"constructor\"\nmsgstr \"\"\n\n#: ../src/heap.c:2286\nmsgid \"symref\"\nmsgstr \"\"\n\n#: ../src/heap.c:2294\nmsgid \"compileref\"\nmsgstr \"\"\n\n#: ../src/heap.c:2322\n#, c-format\nmsgid \"tag \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/heap.c:2337\n#, c-format\nmsgid \"unknown element tag %d\"\nmsgstr \"\"\n\n#: ../src/iarrow.c:117\nmsgid \"No image\"\nmsgstr \"\"\n\n#. Used in (eg.) \"Mark at (10, 10) on [A1, A2]\"\n#.\n#. Expands to (eg.) \"Region on A1 at (10, 10), size (50, 50)\"\n#.\n#: ../src/iarrow.c:130 ../src/iregion.c:156\nmsgid \"on\"\nmsgstr \"\"\n\n#: ../src/iarrow.c:148 ../src/iarrow.c:153\n#, c-format\nmsgid \"at %d\"\nmsgstr \"\"\n\n#: ../src/iarrow.c:158\n#, c-format\nmsgid \"at (%d, %d)\"\nmsgstr \"\"\n\n#: ../src/iarrow.c:165\n#, c-format\nmsgid \"at (%d, %d), offset (%d, %d)\"\nmsgstr \"\"\n\n#: ../src/idialog.c:432\nmsgid \"Pin up\"\nmsgstr \"\"\n\n#: ../src/idialog.c:434\nmsgid \"Check this to pin the dialog up\"\nmsgstr \"\"\n\n#: ../src/iimage.c:115\nmsgid \"Original filename\"\nmsgstr \"\"\n\n#: ../src/iimage.c:338\nmsgid \"Save timer.\"\nmsgstr \"\"\n\n#: ../src/iimage.c:339\n#, c-format\nmsgid \"Image save took %g seconds.\"\nmsgstr \"\"\n\n#: ../src/imageinfo.c:676\nmsgid \"User cancelled operation\"\nmsgstr \"\"\n\n#: ../src/imageinfo.c:976\nmsgid \"Unable to open image.\"\nmsgstr \"\"\n\n#: ../src/imageinfo.c:977\n#, c-format\nmsgid \"Unable to open file \\\"%s\\\" as image.\"\nmsgstr \"\"\n\n#: ../src/imageinfo.c:1105\nmsgid \"Unable to write to file.\"\nmsgstr \"\"\n\n#: ../src/imageinfo.c:1106\n#, c-format\nmsgid \"Error writing image to file \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/imageinfo.c:1122\nmsgid \"Unable to paint on image.\"\nmsgstr \"\"\n\n#: ../src/imageinfo.c:1123\n#, c-format\nmsgid \"\"\n\"Unable to get write permission for file \\\"%s\\\".\\n\"\n\"Check permission settings.\"\nmsgstr \"\"\n\n#: ../src/imageinfo.c:1167\nmsgid \"Modify\"\nmsgstr \"\"\n\n#: ../src/imageinfo.c:1168\nmsgid \"Modify disc file?\"\nmsgstr \"\"\n\n#: ../src/imageinfo.c:1169\n#, c-format\nmsgid \"\"\n\"This image is being shown directly from the disc file:\\n\"\n\"\\n\"\n\"   %s\\n\"\n\"\\n\"\n\"If you paint on this file, it will be permanently changed. If something goes \"\n\"wrong, you may lose work. Are you sure you want to modify this file?\"\nmsgstr \"\"\n\n#: ../src/imageinfo.c:1771\nmsgid \"Unable to paint text.\"\nmsgstr \"\"\n\n#: ../src/imageinfo.c:1772\n#, c-format\nmsgid \"Unable to paint text \\\"%s\\\" in font \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/imagemodel.c:510\nmsgid \"No text specified.\"\nmsgstr \"\"\n\n#: ../src/imagemodel.c:511\nmsgid \"Enter some text to paint in the entry widget at the top of the window.\"\nmsgstr \"\"\n\n#. Need one menu per image window (could have a single menu for all\n#. * windows, but then we'd have to set the state of the toggle buttons\n#. * before mapping)\n#.\n#: ../src/imagepresent.c:1579\nmsgid \"Ruler menu\"\nmsgstr \"\"\n\n#: ../src/imagepresent.c:1580\nmsgid \"Rulers In _mm\"\nmsgstr \"\"\n\n#: ../src/imagepresent.c:1582\nmsgid \"Show _Offset\"\nmsgstr \"\"\n\n#: ../src/imageview.c:457\nmsgid \"New _Mark\"\nmsgstr \"\"\n\n#: ../src/imageview.c:458\nmsgid \"Create a new mark\"\nmsgstr \"\"\n\n#: ../src/imageview.c:462\nmsgid \"New _Horizontal Guide\"\nmsgstr \"\"\n\n#: ../src/imageview.c:463\nmsgid \"Create a new horizontal guide\"\nmsgstr \"\"\n\n#: ../src/imageview.c:467\nmsgid \"New _Vertical Guide\"\nmsgstr \"\"\n\n#: ../src/imageview.c:468\nmsgid \"Create a new vertical guide\"\nmsgstr \"\"\n\n#: ../src/imageview.c:472\nmsgid \"New _Arrow\"\nmsgstr \"\"\n\n#: ../src/imageview.c:473\nmsgid \"Create a new arrow\"\nmsgstr \"\"\n\n#: ../src/imageview.c:477\nmsgid \"New _Region\"\nmsgstr \"\"\n\n#: ../src/imageview.c:478\nmsgid \"Create a new region\"\nmsgstr \"\"\n\n#: ../src/imageview.c:482\nmsgid \"Replace Image\"\nmsgstr \"\"\n\n#: ../src/imageview.c:483\nmsgid \"Replace image from file\"\nmsgstr \"\"\n\n#: ../src/imageview.c:487\nmsgid \"Save Image As\"\nmsgstr \"\"\n\n#: ../src/imageview.c:488\nmsgid \"Save image to file\"\nmsgstr \"\"\n\n#: ../src/imageview.c:492 ../src/mainw.c:868\nmsgid \"Recalculate\"\nmsgstr \"\"\n\n#: ../src/imageview.c:493\nmsgid \"Recalculate image\"\nmsgstr \"\"\n\n#: ../src/imageview.c:497\nmsgid \"Image _Header\"\nmsgstr \"\"\n\n#: ../src/imageview.c:498\nmsgid \"View image header\"\nmsgstr \"\"\n\n#: ../src/imageview.c:502 ../src/imageview.c:556\nmsgid \"Zoom _In\"\nmsgstr \"\"\n\n#: ../src/imageview.c:503 ../src/imageview.c:557\nmsgid \"Zoom in on mouse cursor\"\nmsgstr \"\"\n\n#: ../src/imageview.c:507 ../src/imageview.c:561\nmsgid \"Zoom _Out\"\nmsgstr \"\"\n\n#. IMAGEMODEL_MAGIN\n#: ../src/imageview.c:508 ../src/imageview.c:562 ../src/paintboxview.c:249\nmsgid \"Zoom out\"\nmsgstr \"\"\n\n#: ../src/imageview.c:512\nmsgid \"Zoom _100%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:513 ../src/imageview.c:576\nmsgid \"Zoom to 100%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:517\nmsgid \"Zoom to _Fit\"\nmsgstr \"\"\n\n#: ../src/imageview.c:518\nmsgid \"Zoom to fit image to window\"\nmsgstr \"\"\n\n#: ../src/imageview.c:524 ../src/plotwindow.c:167\nmsgid \"_Status\"\nmsgstr \"\"\n\n#: ../src/imageview.c:525 ../src/plotwindow.c:168\nmsgid \"Show status bar\"\nmsgstr \"\"\n\n#: ../src/imageview.c:529\nmsgid \"_Display Control\"\nmsgstr \"\"\n\n#: ../src/imageview.c:530\nmsgid \"Show display control bar\"\nmsgstr \"\"\n\n#: ../src/imageview.c:534\nmsgid \"_Paint\"\nmsgstr \"\"\n\n#: ../src/imageview.c:535\nmsgid \"Show paint bar\"\nmsgstr \"\"\n\n#: ../src/imageview.c:539\nmsgid \"_Rulers\"\nmsgstr \"\"\n\n#: ../src/imageview.c:540\nmsgid \"Show rulers\"\nmsgstr \"\"\n\n#: ../src/imageview.c:546\nmsgid \"_Select\"\nmsgstr \"\"\n\n#: ../src/imageview.c:547\nmsgid \"Select and modify selections\"\nmsgstr \"\"\n\n#: ../src/imageview.c:551\nmsgid \"_Pan\"\nmsgstr \"\"\n\n#: ../src/imageview.c:552\nmsgid \"Pan image\"\nmsgstr \"\"\n\n#: ../src/imageview.c:568\nmsgid \"6%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:568\nmsgid \"Zoom to 6%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:570\nmsgid \"12%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:570\nmsgid \"Zoom to 12%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:572\nmsgid \"25%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:572\nmsgid \"Zoom to 25%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:574\nmsgid \"50%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:574\nmsgid \"Zoom to 50%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:576\nmsgid \"100%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:578\nmsgid \"200%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:578\nmsgid \"Zoom to 200%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:580\nmsgid \"400%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:580\nmsgid \"Zoom to 400%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:582\nmsgid \"800%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:582\nmsgid \"Zoom to 800%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:584\nmsgid \"1600%\"\nmsgstr \"\"\n\n#: ../src/imageview.c:584\nmsgid \"Zoom to 1600%\"\nmsgstr \"\"\n\n#: ../src/iregion.c:166\n#, c-format\nmsgid \"at (%d, %d), size (%d, %d)\"\nmsgstr \"\"\n\n#: ../src/iregion.c:181 ../src/iregion.c:223\nmsgid \"Left\"\nmsgstr \"\"\n\n#: ../src/iregion.c:182 ../src/iregion.c:226\nmsgid \"Top\"\nmsgstr \"\"\n\n#: ../src/iregion.c:183 ../src/iregion.c:229\nmsgid \"Width\"\nmsgstr \"\"\n\n#: ../src/iregion.c:184 ../src/iregion.c:232\nmsgid \"Height\"\nmsgstr \"\"\n\n#: ../src/iregion.c:223\nmsgid \"Left edge of region\"\nmsgstr \"\"\n\n#: ../src/iregion.c:226\nmsgid \"Top edge of region\"\nmsgstr \"\"\n\n#: ../src/iregion.c:229\nmsgid \"Width of region\"\nmsgstr \"\"\n\n#: ../src/iregion.c:232\nmsgid \"Height of region\"\nmsgstr \"\"\n\n#: ../src/iregion.c:237\n#, c-format\nmsgid \"Edit \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/iregion.c:241\nmsgid \"Set Region\"\nmsgstr \"\"\n\n#: ../src/itext.c:67\nmsgid \"Formula\"\nmsgstr \"\"\n\n#: ../src/itext.c:184 ../src/itext.c:325\nmsgid \"no value\"\nmsgstr \"\"\n\n#: ../src/itext.c:503 ../src/itext.c:536\nmsgid \"Dirty value\"\nmsgstr \"\"\n\n#. Common menus.\n#.\n#: ../src/iwindow.c:659\nmsgid \"_File\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:660\nmsgid \"_New\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:661 ../src/mainw.c:1765 ../src/program.c:727\n#: ../src/regionview.c:1016 ../src/rowview.c:586\nmsgid \"_Edit\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:662\nmsgid \"_View\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:663\nmsgid \"_Help\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:668\nmsgid \"_Close\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:669\nmsgid \"Close\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:673\nmsgid \"_Quit\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:674\nmsgid \"Quit nip2\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:677\nmsgid \"_Contents\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:678\nmsgid \"Open the users guide\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:682\nmsgid \"_About\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:683\nmsgid \"About this program\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:687\nmsgid \"_Website\"\nmsgstr \"\"\n\n#: ../src/iwindow.c:688\nmsgid \"Open the VIPS Homepage\"\nmsgstr \"\"\n\n#: lex.l:91 lex.l:101\nmsgid \"line too long\"\nmsgstr \"\"\n\n#: lex.l:109\nmsgid \"end of line inside string\"\nmsgstr \"\"\n\n#: lex.l:111\nmsgid \"no end of string\"\nmsgstr \"\"\n\n#: lex.l:132 lex.l:142 lex.l:150\nmsgid \"bad char constant\"\nmsgstr \"\"\n\n#: lex.l:175\nmsgid \"nested comment\"\nmsgstr \"\"\n\n#: lex.l:181\nmsgid \"no end of comment\"\nmsgstr \"\"\n\n#: lex.l:311\n#, c-format\nmsgid \"bad number %s\"\nmsgstr \"\"\n\n#: lex.l:364\n#, c-format\nmsgid \"illegal character \\\"%c\\\"\"\nmsgstr \"\"\n\n#: ../src/link.c:578\nmsgid \"Circular dependency.\"\nmsgstr \"\"\n\n#: ../src/link.c:579\n#, c-format\nmsgid \"Circular dependency detected near symbol \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/main.c:116\nmsgid \"evaluate and print EXPRESSION\"\nmsgstr \"\"\n\n#: ../src/main.c:119\nmsgid \"load FILE as a set of definitions\"\nmsgstr \"\"\n\n#: ../src/main.c:122\nmsgid \"write value of 'main' to FILE\"\nmsgstr \"\"\n\n#: ../src/main.c:124\nmsgid \"run in batch mode\"\nmsgstr \"\"\n\n#: ../src/main.c:126\nmsgid \"set values\"\nmsgstr \"\"\n\n#: ../src/main.c:128\nmsgid \"verbose error output\"\nmsgstr \"\"\n\n#: ../src/main.c:131\nmsgid \"don't load menu definitions\"\nmsgstr \"\"\n\n#: ../src/main.c:133\nmsgid \"don't try to load command-line arguments\"\nmsgstr \"\"\n\n#: ../src/main.c:135\nmsgid \"load stdin as a workspace\"\nmsgstr \"\"\n\n#: ../src/main.c:137\nmsgid \"load stdin as a set of definitions\"\nmsgstr \"\"\n\n#: ../src/main.c:139\nmsgid \"print value of 'main' to stdout\"\nmsgstr \"\"\n\n#: ../src/main.c:142\nmsgid \"start up and shut down\"\nmsgstr \"\"\n\n#: ../src/main.c:145\nmsgid \"time image save operations\"\nmsgstr \"\"\n\n#: ../src/main.c:148\nmsgid \"start as if installed to PREFIX\"\nmsgstr \"\"\n\n#: ../src/main.c:150\nmsgid \"output strings for internationalisation\"\nmsgstr \"\"\n\n#: ../src/main.c:153\nmsgid \"print version number\"\nmsgstr \"\"\n\n#: ../src/main.c:156\nmsgid \"test for errors and quit\"\nmsgstr \"\"\n\n#: ../src/main.c:235\n#, c-format\nmsgid \"error calculating \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/main.c:243\n#, c-format\nmsgid \"error saving \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/main.c:297\nmsgid \"no \\\"main\\\" found\"\nmsgstr \"\"\n\n#: ../src/main.c:475\nmsgid \"Unknown file type.\"\nmsgstr \"\"\n\n#: ../src/main.c:476\n#, c-format\nmsgid \"Unable to load \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/main.c:487\nmsgid \"Unable to load.\"\nmsgstr \"\"\n\n#: ../src/main.c:488\n#, c-format\nmsgid \"Error loading plug-in \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/main.c:696\nmsgid \"Next _Error\"\nmsgstr \"\"\n\n#: ../src/main.c:697\nmsgid \"Ink dropper\"\nmsgstr \"\"\n\n#: ../src/main.c:698\nmsgid \"D_uplicate\"\nmsgstr \"\"\n\n#: ../src/main.c:699\nmsgid \"Pen\"\nmsgstr \"\"\n\n#: ../src/main.c:700 ../src/plot.c:94\nmsgid \"Line\"\nmsgstr \"\"\n\n#: ../src/main.c:701 ../src/matrix.c:149\nmsgid \"Text\"\nmsgstr \"\"\n\n#. IMAGEMODEL_TEXT\n#: ../src/main.c:702 ../src/paintboxview.c:259\nmsgid \"Smudge\"\nmsgstr \"\"\n\n#: ../src/main.c:703\nmsgid \"Flood\"\nmsgstr \"\"\n\n#: ../src/main.c:704\nmsgid \"Flood Blob\"\nmsgstr \"\"\n\n#: ../src/main.c:705\nmsgid \"Fill Rectangle\"\nmsgstr \"\"\n\n#: ../src/main.c:706\nmsgid \"Pan\"\nmsgstr \"\"\n\n#: ../src/main.c:707\nmsgid \"Select\"\nmsgstr \"\"\n\n#. And the LEDs we use.\n#.\n#: ../src/main.c:711\nmsgid \"Red LED\"\nmsgstr \"\"\n\n#: ../src/main.c:712\nmsgid \"Green LED\"\nmsgstr \"\"\n\n#: ../src/main.c:713\nmsgid \"Blue LED\"\nmsgstr \"\"\n\n#: ../src/main.c:714\nmsgid \"Yellow LED\"\nmsgstr \"\"\n\n#: ../src/main.c:715\nmsgid \"Cyan LED\"\nmsgstr \"\"\n\n#: ../src/main.c:716\nmsgid \"Off LED\"\nmsgstr \"\"\n\n#: ../src/main.c:895\nmsgid \"Empty temp area\"\nmsgstr \"\"\n\n#: ../src/main.c:896\nmsgid \"Many files in temp area.\"\nmsgstr \"\"\n\n#: ../src/main.c:897\n#, c-format\nmsgid \"\"\n\"The temp area \\\"%s\\\" contains %s of files. Would you like to empty the temp \"\n\"area? This will delete any workspace backups and cannot be undone.\"\nmsgstr \"\"\n\n#: ../src/main.c:913\n#, c-format\nmsgid \"unable to make %s %s: %s\"\nmsgstr \"\"\n\n#: ../src/main.c:1095\nmsgid \"- image processing spreadsheet\"\nmsgstr \"\"\n\n#: ../src/main.c:1127\n#, c-format\nmsgid \"linked to vips-%s\"\nmsgstr \"\"\n\n#. -1 means can't-be-set, at least on os x, so don't\n#. * warn.\n#.\n#: ../src/main.c:1187\n#, c-format\nmsgid \"\"\n\"unable to change max file descriptors\\n\"\n\"max file descriptors still set to %d\"\nmsgstr \"\"\n\n#: ../src/main.c:1193\nmsgid \"unable to read max file descriptors\"\nmsgstr \"\"\n\n#: ../src/main.c:1417 ../src/main.c:1463\n#, c-format\nmsgid \"\"\n\"Startup error log:\\n\"\n\"%s\"\nmsgstr \"\"\n\n#: ../src/main.c:1462\nmsgid \"Startup error.\"\nmsgstr \"\"\n\n#: ../src/main.c:1473\n#, c-format\nmsgid \"Welcome to %s-%s!\"\nmsgstr \"\"\n\n#: ../src/main.c:1478\n#, c-format\nmsgid \"\"\n\"A new directory has been created to hold startup, data and temporary files:\\n\"\n\"\\n\"\n\"     %s\\n\"\n\"\\n\"\n\"If you've used previous versions of %s, you might want to copy files over \"\n\"from your old work area.\"\nmsgstr \"\"\n\n#: ../src/mainw.c:173\nmsgid \"Compatibility mode.\"\nmsgstr \"\"\n\n#: ../src/mainw.c:174\n#, c-format\nmsgid \"\"\n\"This workspace was created by version %d.%d.%d. A set of compatibility menus \"\n\"have been loaded for this window.\"\nmsgstr \"\"\n\n#: ../src/mainw.c:350\nmsgid \"No temp area\"\nmsgstr \"\"\n\n#: ../src/mainw.c:356\n#, c-format\nmsgid \"%s free\"\nmsgstr \"\"\n\n#: ../src/mainw.c:369\n#, c-format\nmsgid \"%d cells free\"\nmsgstr \"\"\n\n#. Display select message instead.\n#.\n#: ../src/mainw.c:384\nmsgid \"Selected:\"\nmsgstr \"\"\n\n#: ../src/mainw.c:414\nmsgid \"compatibility mode\"\nmsgstr \"\"\n\n#: ../src/mainw.c:424\nmsgid \"unsaved workspace\"\nmsgstr \"\"\n\n#. Expands to (eg.) \"14GB free in /pics/tmp\"\n#: ../src/mainw.c:607\n#, c-format\nmsgid \" in \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/mainw.c:611\n#, c-format\nmsgid \"%d cells in heap, %d cells free, %d cells maximum\"\nmsgstr \"\"\n\n#: ../src/mainw.c:615\n#, c-format\nmsgid \"%d objects in workspace\"\nmsgstr \"\"\n\n#: ../src/mainw.c:619\n#, c-format\nmsgid \"%d vips calls cached\"\nmsgstr \"\"\n\n#: ../src/mainw.c:623\n#, c-format\nmsgid \"using %d threads\"\nmsgstr \"\"\n\n#: ../src/mainw.c:755\nmsgid \"Find in workspace not implemented yet.\"\nmsgstr \"\"\n\n#: ../src/mainw.c:763\nmsgid \"Find again in workspace not implemented yet.\"\nmsgstr \"\"\n\n#: ../src/mainw.c:798\nmsgid \"No errors.\"\nmsgstr \"\"\n\n#: ../src/mainw.c:799\nmsgid \"There are no errors (that I can see) in this workspace.\"\nmsgstr \"\"\n\n#: ../src/mainw.c:869\nmsgid \"Completely recalculate?\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1023\n#, c-format\nmsgid \"\"\n\"Unable to execute:\\n\"\n\"   %s\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1041 ../src/mainw.c:1074\nmsgid \"Open File\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1188\nmsgid \"Recent Images\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1196\nmsgid \"Recent Workspaces\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1204\nmsgid \"Recent Matricies\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1213\nmsgid \"No recent items\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1219\nmsgid \"Clear Recent Menu\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1279\nmsgid \"Merge Workspace from File\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1407\nmsgid \"Set column name here\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1409\nmsgid \"Set column caption here\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1411\nmsgid \"New Column\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1415\nmsgid \"Create Column\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1554\nmsgid \"Revert to Defaults\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1555\nmsgid \"Revert to installation defaults?\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1556\nmsgid \"\"\n\"Would you like to reset all preferences to their factory settings? This will \"\n\"delete any changes you have ever made to your preferences and may take a few \"\n\"seconds.\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1573\nmsgid \"Preferences\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1578\nmsgid \"Revert to Defaults ...\"\nmsgstr \"\"\n\n#. Menu items.\n#.\n#: ../src/mainw.c:1641\nmsgid \"Open _Recent\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1642 ../src/mainw.c:2107\nmsgid \"Jump to _Column\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1643\nmsgid \"_Toolkits\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1653 ../src/mainw.c:2104\nmsgid \"New C_olumn\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1654\nmsgid \"Create a new column\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1658\nmsgid \"New Named C_olumn\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1659\nmsgid \"Create a new column with a specified name\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1663 ../src/program.c:1669\nmsgid \"New _Workspace\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1664\nmsgid \"Create a new workspace\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1668\nmsgid \"_Open\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1669\nmsgid \"Open a file\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1673\nmsgid \"Open _Examples\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1674\nmsgid \"Open example workspaces\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1678\nmsgid \"_Duplicate Workspace\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1679\nmsgid \"Duplicate workspace\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1683\nmsgid \"_Merge Workspace\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1684\nmsgid \"Merge workspace into this workspace\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1688\nmsgid \"_Save Workspace\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1689\nmsgid \"Save workspace\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1693\nmsgid \"_Save Workspace As\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1694\nmsgid \"Save workspace as\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1698\nmsgid \"Search for Workspace _Backups\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1699\nmsgid \"Load last automatically backed-up workspace\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1703 ../src/program.c:1714\nmsgid \"_Delete\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1704\nmsgid \"Delete selected items\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1709\nmsgid \"Select all items\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1713\nmsgid \"D_uplicate Selected\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1714\nmsgid \"Duplicate selected items\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1718 ../src/rowview.c:596\nmsgid \"_Recalculate\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1719\nmsgid \"Recalculate selected items\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1723 ../src/mainw.c:2108\nmsgid \"Align _Columns\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1724\nmsgid \"Align columns to grid\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1728 ../src/program.c:1739\nmsgid \"_Find\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1729\nmsgid \"Find in workspace\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1733 ../src/program.c:1744\nmsgid \"Find _Next\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1734\nmsgid \"Find again in workspace\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1739\nmsgid \"Jump to next error\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1743\nmsgid \"_Group\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1744\nmsgid \"Group selected items\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1748 ../src/rowview.c:590\nmsgid \"U_ngroup\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1749\nmsgid \"Ungroup selected items\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1753\nmsgid \"_Preferences\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1754\nmsgid \"Edit preferences\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1759\nmsgid \"Workspace as Grap_h\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1760\nmsgid \"Show a graph of workspace dependencies\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1766\nmsgid \"Edit toolkits\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1772\nmsgid \"Au_to Recalculate\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1773\nmsgid \"Recalculate automatically on change\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1777\nmsgid \"_Toolbar\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1778\nmsgid \"Show window toolbar\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1782\nmsgid \"_Statusbar\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1783\nmsgid \"Show window statusbar\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1787\nmsgid \"Toolkit _Browser\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1788\nmsgid \"Show toolkit browser\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1792\nmsgid \"Workspace _Definitions\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1793\nmsgid \"Show workspace definitions\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1799\nmsgid \"_Normal\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1800\nmsgid \"Normal view mode\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1804\nmsgid \"Show _Formula\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1805\nmsgid \"Show formula view mode\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1809\nmsgid \"No _Edits\"\nmsgstr \"\"\n\n#: ../src/mainw.c:1810\nmsgid \"No edits view mode\"\nmsgstr \"\"\n\n#: ../src/mainw.c:2103\nmsgid \"Workspace menu\"\nmsgstr \"\"\n\n#: ../src/mainw.c:2113\nmsgid \"_Merge Workspace from File\"\nmsgstr \"\"\n\n#: ../src/mainw.c:2116\nmsgid \"_Group Selected\"\nmsgstr \"\"\n\n#. Toolkit Browser pane.\n#.\n#: ../src/mainw.c:2125\nmsgid \"Toolkit Browser\"\nmsgstr \"\"\n\n#. Workspace-local defs pane.\n#.\n#: ../src/mainw.c:2144\nmsgid \"Workspace Definitions\"\nmsgstr \"\"\n\n#: ../src/matrix.c:150\nmsgid \"Sliders\"\nmsgstr \"\"\n\n#: ../src/matrix.c:151\nmsgid \"Toggle buttons\"\nmsgstr \"\"\n\n#: ../src/matrix.c:152\nmsgid \"Text, plus scale and offset\"\nmsgstr \"\"\n\n#: ../src/matrix.c:163\nmsgid \"Display as\"\nmsgstr \"\"\n\n#: ../src/matrix.c:194\n#, c-format\nmsgid \"Edit Matrix \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/matrix.c:199\nmsgid \"Set Matrix\"\nmsgstr \"\"\n\n#: ../src/matrix.c:265 ../src/matrixview.c:425\nmsgid \"Scale\"\nmsgstr \"\"\n\n#: ../src/matrix.c:268 ../src/matrixview.c:430\nmsgid \"Offset\"\nmsgstr \"\"\n\n#: ../src/matrix.c:274\nmsgid \"Display\"\nmsgstr \"\"\n\n#: ../src/matrixview.c:190 ../src/matrixview.c:211\n#, c-format\nmsgid \"\"\n\"Cell (%d, %d):\\n\"\n\"%s\"\nmsgstr \"\"\n\n#. Expands to (eg) \"A2: cell (1,2): 45\" ... status line display during\n#. * matrix traverse.\n#.\n#: ../src/matrixview.c:622\n#, c-format\nmsgid \": cell (%d, %d): %s\"\nmsgstr \"\"\n\n#: ../src/model.c:131\n#, c-format\nmsgid \"\"\n\"Unable to load from file \\\"%s\\\". Error log is:\\n\"\n\"%s\"\nmsgstr \"\"\n\n#: ../src/model.c:420\nmsgid \"model_save: xmlNewChild() failed\"\nmsgstr \"\"\n\n#: ../src/model.c:487\nmsgid \"XML load error.\"\nmsgstr \"\"\n\n#: ../src/model.c:488\n#, c-format\nmsgid \"Can't load node of type \\\"%s\\\" into object of type \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/model.c:716\nmsgid \"Delete?\"\nmsgstr \"\"\n\n#: ../src/model.c:717\n#, c-format\nmsgid \"Are you sure you want to delete %s \\\"%s\\\"?\"\nmsgstr \"\"\n\n#: ../src/option.c:68\nmsgid \"Labels\"\nmsgstr \"\"\n\n#. Create signals.\n#.\n#. Init methods.\n#.\n#: ../src/paintboxview.c:109\nmsgid \"Paintbox bar menu\"\nmsgstr \"\"\n\n#: ../src/paintboxview.c:210\nmsgid \"Clear undo history?\"\nmsgstr \"\"\n\n#: ../src/paintboxview.c:211\nmsgid \"\"\n\"Are you sure you want to clear all undo and redo? This will free up memory, \"\n\"but you will no longer be able to undo or redo any of the painting you have \"\n\"done so far.\"\nmsgstr \"\"\n\n#: ../src/paintboxview.c:246\nmsgid \"Manipulate regions\"\nmsgstr \"\"\n\n#. IMAGEMODEL_SELECT\n#: ../src/paintboxview.c:247\nmsgid \"Pan window\"\nmsgstr \"\"\n\n#. IMAGEMODEL_PAN\n#: ../src/paintboxview.c:248\nmsgid \"Zoom in on mouse\"\nmsgstr \"\"\n\n#. IMAGEMODEL_MAGOUT\n#: ../src/paintboxview.c:250\nmsgid \"Read pixel into inkwell\"\nmsgstr \"\"\n\n#. IMAGEMODEL_DROPPER\n#: ../src/paintboxview.c:251\nmsgid \"Freehand draw \"\nmsgstr \"\"\n\n#. IMAGEMODEL_PEN\n#: ../src/paintboxview.c:252\nmsgid \"Draw straight lines\"\nmsgstr \"\"\n\n#. IMAGEMODEL_LINE\n#: ../src/paintboxview.c:253\nmsgid \"Fill rectangles\"\nmsgstr \"\"\n\n#. IMAGEMODEL_RECT\n#: ../src/paintboxview.c:254\nmsgid \"Flood while pixel not equal to ink\"\nmsgstr \"\"\n\n#. IMAGEMODEL_FLOOD\n#: ../src/paintboxview.c:256\nmsgid \"Flood while pixel equal to click\"\nmsgstr \"\"\n\n#. IMAGEMODEL_BLOB\n#: ../src/paintboxview.c:258\nmsgid \"Draw text\"\nmsgstr \"\"\n\n#: ../src/paintboxview.c:309\nmsgid \"Undo last paint action\"\nmsgstr \"\"\n\n#: ../src/paintboxview.c:318\nmsgid \"Redo last paint action\"\nmsgstr \"\"\n\n#: ../src/paintboxview.c:327\nmsgid \"Clear all undo and redo buffers\"\nmsgstr \"\"\n\n#: ../src/paintboxview.c:376\nmsgid \"Enter text for text tool\"\nmsgstr \"\"\n\n#: ../src/panechild.c:108\nmsgid \"Close the pane\"\nmsgstr \"\"\n\n#: parse.y:244 parse.y:255\nmsgid \"not top level\"\nmsgstr \"\"\n\n#: parse.y:260\nmsgid \"not strings\"\nmsgstr \"\"\n\n#: parse.y:318\nmsgid \"left-hand-side pattern contains no identifiers\"\nmsgstr \"\"\n\n#: parse.y:1064 ../src/program.c:1421\nmsgid \"Parse error.\"\nmsgstr \"\"\n\n#: parse.y:1067\n#, c-format\nmsgid \"Error in %s: %s\"\nmsgstr \"\"\n\n#: parse.y:1070\n#, c-format\nmsgid \"Error: %s\"\nmsgstr \"\"\n\n#: parse.y:1183\nmsgid \"definition is too long\"\nmsgstr \"\"\n\n#: parse.y:1607\nmsgid \"no leading identifier\"\nmsgstr \"\"\n\n#: parse.y:1613\nmsgid \"'=' missing\"\nmsgstr \"\"\n\n#: parse.y:1643\nmsgid \"identifier expected\"\nmsgstr \"\"\n\n#: parse.y:1653\n#, c-format\nmsgid \"'%s' does not exist\"\nmsgstr \"\"\n\n#: parse.y:1655\n#, c-format\nmsgid \"'%s' has no members\"\nmsgstr \"\"\n\n#: parse.y:1670\nmsgid \"'.' or '=' expected\"\nmsgstr \"\"\n\n#. Not found? Maybe - error message anyway.\n#.\n#: ../src/path.c:332 ../src/path.c:360 ../src/program.c:1440\n#: ../src/program.c:1492 ../src/program.c:1514 ../src/program.c:1522\n#: ../src/symbol.c:502\nmsgid \"Not found.\"\nmsgstr \"\"\n\n#: ../src/path.c:333\n#, c-format\nmsgid \"File \\\"%s\\\" not found.\"\nmsgstr \"\"\n\n#: ../src/path.c:361\n#, c-format\nmsgid \"File \\\"%s\\\" not found on path\"\nmsgstr \"\"\n\n#: ../src/pathnameview.c:173\nmsgid \"Select a new file name\"\nmsgstr \"\"\n\n#: ../src/plot.c:80\nmsgid \"YYYY\"\nmsgstr \"\"\n\n#: ../src/plot.c:81\nmsgid \"XYYY\"\nmsgstr \"\"\n\n#: ../src/plot.c:82\nmsgid \"XYXY\"\nmsgstr \"\"\n\n#: ../src/plot.c:93\nmsgid \"Point\"\nmsgstr \"\"\n\n#: ../src/plot.c:95\nmsgid \"Spline\"\nmsgstr \"\"\n\n#: ../src/plot.c:96\nmsgid \"Bar\"\nmsgstr \"\"\n\n#: ../src/plot.c:141\nmsgid \"More than one column needed or XY plots\"\nmsgstr \"\"\n\n#: ../src/plot.c:151\nmsgid \"Even number of columns only for XY format plots\"\nmsgstr \"\"\n\n#: ../src/plot.c:316\nmsgid \"Format\"\nmsgstr \"\"\n\n#: ../src/plot.c:319\nmsgid \"Style\"\nmsgstr \"\"\n\n#: ../src/plot.c:322\nmsgid \"Xmin\"\nmsgstr \"\"\n\n#: ../src/plot.c:325\nmsgid \"Xmax\"\nmsgstr \"\"\n\n#: ../src/plot.c:328\nmsgid \"Ymin\"\nmsgstr \"\"\n\n#: ../src/plot.c:331\nmsgid \"Ymax\"\nmsgstr \"\"\n\n#: ../src/plot.c:337\nmsgid \"Options\"\nmsgstr \"\"\n\n#: ../src/plot.c:361\nmsgid \"1xn or nx1 images only for Plot\"\nmsgstr \"\"\n\n#: ../src/plot.c:380\nmsgid \"Unable to prepare image.\"\nmsgstr \"\"\n\n#: ../src/plot.c:393\nmsgid \"1xn or nx1 images only\"\nmsgstr \"\"\n\n#. Create signals.\n#.\n#. Init methods.\n#.\n#: ../src/plotstatus.c:99 ../src/statusview.c:108\nmsgid \"Status bar menu\"\nmsgstr \"\"\n\n#: ../src/plotstatus.c:190 ../src/statusview.c:223 ../src/statusview.c:226\nmsgid \"Magnification\"\nmsgstr \"\"\n\n#. Probably failed to load prefs on startup for some reason.\n#.\n#: ../src/prefs.c:207\nmsgid \"Unable to display preferences.\"\nmsgstr \"\"\n\n#: ../src/prefs.c:208\n#, c-format\nmsgid \"\"\n\"No preferences workspace was found. Preferences probably failed to load when \"\n\"%s started.\"\nmsgstr \"\"\n\n#: ../src/program.c:73\nmsgid \"Edit window\"\nmsgstr \"\"\n\n#: ../src/program.c:263 ../src/workspacedefs.c:108\nmsgid \"modified\"\nmsgstr \"\"\n\n#: ../src/program.c:625\nmsgid \"Menu item text\"\nmsgstr \"\"\n\n#: ../src/program.c:628\nmsgid \"Load column from this file\"\nmsgstr \"\"\n\n#: ../src/program.c:630\n#, c-format\nmsgid \"Edit Column Item \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/program.c:635\nmsgid \"Set column item\"\nmsgstr \"\"\n\n#: ../src/program.c:656 ../src/program.c:662\nmsgid \"Unable to save.\"\nmsgstr \"\"\n\n#: ../src/program.c:657\nmsgid \"You can only save toolkits, not tools.\"\nmsgstr \"\"\n\n#: ../src/program.c:663\nmsgid \"You can't save auto-generated toolkits.\"\nmsgstr \"\"\n\n#. Create signals.\n#.\n#. Init methods.\n#.\n#: ../src/program.c:726\nmsgid \"Toolkit menu\"\nmsgstr \"\"\n\n#: ../src/program.c:1093\nmsgid \"Set toolkit name here\"\nmsgstr \"\"\n\n#: ../src/program.c:1095\nmsgid \"Set toolkit caption here\"\nmsgstr \"\"\n\n#: ../src/program.c:1096\nmsgid \"New Toolkit\"\nmsgstr \"\"\n\n#: ../src/program.c:1100 ../src/program.c:1178\nmsgid \"Create\"\nmsgstr \"\"\n\n#: ../src/program.c:1111\nmsgid \"Nothing selected.\"\nmsgstr \"\"\n\n#: ../src/program.c:1112\nmsgid \"No toolkit selected.\"\nmsgstr \"\"\n\n#: ../src/program.c:1171\nmsgid \"Display this name\"\nmsgstr \"\"\n\n#: ../src/program.c:1173\nmsgid \"Load this file\"\nmsgstr \"\"\n\n#: ../src/program.c:1241\nmsgid \"Load Definition\"\nmsgstr \"\"\n\n#: ../src/program.c:1295\nmsgid \"Reload\"\nmsgstr \"\"\n\n#: ../src/program.c:1296\nmsgid \"Reload startup objects?\"\nmsgstr \"\"\n\n#: ../src/program.c:1297\nmsgid \"\"\n\"Would you like to reload all startup menus, workspaces and plugins now? This \"\n\"may take a few seconds.\"\nmsgstr \"\"\n\n#: ../src/program.c:1379\nmsgid \"No tool selected\"\nmsgstr \"\"\n\n#: ../src/program.c:1422\nmsgid \"Bad regular expression.\"\nmsgstr \"\"\n\n#: ../src/program.c:1441\n#, c-format\nmsgid \"No match found for \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/program.c:1454\nmsgid \"Find in all Toolkits\"\nmsgstr \"\"\n\n#: ../src/program.c:1464\nmsgid \"Enter search string here\"\nmsgstr \"\"\n\n#: ../src/program.c:1515\n#, c-format\nmsgid \"No top-level symbol called \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/program.c:1523\n#, c-format\nmsgid \"Symbol \\\"%s\\\" has no tool inforation.\"\nmsgstr \"\"\n\n#: ../src/program.c:1544\nmsgid \"Go to definition of this symbol\"\nmsgstr \"\"\n\n#: ../src/program.c:1546\nmsgid \"Go to Definition\"\nmsgstr \"\"\n\n#: ../src/program.c:1576\nmsgid \"Object information.\"\nmsgstr \"\"\n\n#: ../src/program.c:1627\nmsgid \"No documentation available.\"\nmsgstr \"\"\n\n#: ../src/program.c:1628\nmsgid \"\"\n\"On-line documentation is only currently available for VIPS functions and nip \"\n\"builtins.\"\nmsgstr \"\"\n\n#: ../src/program.c:1644\nmsgid \"New _Tool\"\nmsgstr \"\"\n\n#: ../src/program.c:1645\nmsgid \"Make a new tool\"\nmsgstr \"\"\n\n#: ../src/program.c:1649\nmsgid \"New Tool_kit\"\nmsgstr \"\"\n\n#: ../src/program.c:1650\nmsgid \"Make a new toolkit\"\nmsgstr \"\"\n\n#: ../src/program.c:1654\nmsgid \"New _Separator\"\nmsgstr \"\"\n\n#: ../src/program.c:1655\nmsgid \"Make a new separator\"\nmsgstr \"\"\n\n#: ../src/program.c:1659\nmsgid \"New _Column Item\"\nmsgstr \"\"\n\n#: ../src/program.c:1660\nmsgid \"Make a new column item\"\nmsgstr \"\"\n\n#: ../src/program.c:1664\nmsgid \"New _Program Window\"\nmsgstr \"\"\n\n#: ../src/program.c:1665\nmsgid \"Make a new program window\"\nmsgstr \"\"\n\n#: ../src/program.c:1670\nmsgid \"Make a new workspace\"\nmsgstr \"\"\n\n#: ../src/program.c:1674\nmsgid \"_Open Toolkit\"\nmsgstr \"\"\n\n#: ../src/program.c:1675\nmsgid \"_Open toolkit\"\nmsgstr \"\"\n\n#: ../src/program.c:1679\nmsgid \"Save Toolkit\"\nmsgstr \"\"\n\n#: ../src/program.c:1680\nmsgid \"_Save toolkit\"\nmsgstr \"\"\n\n#: ../src/program.c:1684\nmsgid \"Save Toolkit _As\"\nmsgstr \"\"\n\n#: ../src/program.c:1685\nmsgid \"Save toolkit as\"\nmsgstr \"\"\n\n#: ../src/program.c:1689\nmsgid \"_Process\"\nmsgstr \"\"\n\n#: ../src/program.c:1690\nmsgid \"Process text\"\nmsgstr \"\"\n\n#: ../src/program.c:1694\nmsgid \"_Reload All Toolkits\"\nmsgstr \"\"\n\n#: ../src/program.c:1695\nmsgid \"Remove and reload all startup data\"\nmsgstr \"\"\n\n#: ../src/program.c:1699\nmsgid \"C_ut\"\nmsgstr \"\"\n\n#: ../src/program.c:1700\nmsgid \"Cut selected text\"\nmsgstr \"\"\n\n#: ../src/program.c:1704\nmsgid \"_Copy\"\nmsgstr \"\"\n\n#: ../src/program.c:1705\nmsgid \"Copy selected text\"\nmsgstr \"\"\n\n#: ../src/program.c:1709\nmsgid \"_Paste\"\nmsgstr \"\"\n\n#: ../src/program.c:1710\nmsgid \"Paste selected text\"\nmsgstr \"\"\n\n#: ../src/program.c:1715\nmsgid \"Delete selected text\"\nmsgstr \"\"\n\n#: ../src/program.c:1720\nmsgid \"Select all text\"\nmsgstr \"\"\n\n#: ../src/program.c:1724\nmsgid \"Dese_lect All\"\nmsgstr \"\"\n\n#: ../src/program.c:1725\nmsgid \"Deselect all text\"\nmsgstr \"\"\n\n#: ../src/program.c:1729\nmsgid \"Delete _Tool\"\nmsgstr \"\"\n\n#: ../src/program.c:1730\nmsgid \"Delete current tool\"\nmsgstr \"\"\n\n#: ../src/program.c:1734\nmsgid \"Delete Tool_kit\"\nmsgstr \"\"\n\n#: ../src/program.c:1735\nmsgid \"Delete current toolkit\"\nmsgstr \"\"\n\n#: ../src/program.c:1740\nmsgid \"Find text in toolkits\"\nmsgstr \"\"\n\n#: ../src/program.c:1745\nmsgid \"Find text again\"\nmsgstr \"\"\n\n#: ../src/program.c:1749\nmsgid \"_Jump To Definition\"\nmsgstr \"\"\n\n#: ../src/program.c:1750\nmsgid \"Jump to definition\"\nmsgstr \"\"\n\n#: ../src/program.c:1754\nmsgid \"_Info\"\nmsgstr \"\"\n\n#: ../src/program.c:1755\nmsgid \"Info on selected object\"\nmsgstr \"\"\n\n#: ../src/program.c:1759\nmsgid \"_Trace\"\nmsgstr \"\"\n\n#: ../src/program.c:1760\nmsgid \"Make a new trace window\"\nmsgstr \"\"\n\n#: ../src/program.c:1764\nmsgid \"_Errors\"\nmsgstr \"\"\n\n#: ../src/program.c:1765\nmsgid \"Show all errors\"\nmsgstr \"\"\n\n#: ../src/program.c:1769\nmsgid \"Help on _Tool\"\nmsgstr \"\"\n\n#: ../src/program.c:1770\nmsgid \"View docs for this tool\"\nmsgstr \"\"\n\n#: ../src/program.c:2015\nmsgid \"Bad drag.\"\nmsgstr \"\"\n\n#: ../src/program.c:2017\nmsgid \"\"\n\"Sorry, you can only drag tools between toolkits. You can't reorder toolkits, \"\n\"you can't nest toolkits and you can't drag tools to the top level.\"\nmsgstr \"\"\n\n#: ../src/program.c:2196\nmsgid \"Tool\"\nmsgstr \"\"\n\n#: ../src/progress.c:120\nmsgid \"Cancelling\"\nmsgstr \"\"\n\n#: ../src/progress.c:153\n#, c-format\nmsgid \"%d minute left\"\nmsgid_plural \"%d minutes left\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\n#: ../src/progress.c:158\n#, c-format\nmsgid \"%d second left\"\nmsgid_plural \"%d seconds left\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\n#: ../src/progress.c:179\nmsgid \"Calculating\"\nmsgstr \"\"\n\n#: ../src/progress.c:198\nmsgid \"Loading\"\nmsgstr \"\"\n\n#: ../src/reduce.c:135\nmsgid \"Typecheck error.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:137\n#, c-format\nmsgid \"%s expected %s, instead saw:\"\nmsgstr \"\"\n\n#: ../src/reduce.c:148 ../src/reduce.c:1056 ../src/trace.c:126\n#: ../src/workspace.c:1704\nmsgid \"Overflow error.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:149\n#, c-format\nmsgid \"%s too long.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:532 ../src/reduce.c:597\nmsgid \"Not rectangular.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:533 ../src/reduce.c:598\n#, c-format\nmsgid \"\"\n\"Matrix of real is not rectangular. Found row of length %d, should be %d.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:557\nmsgid \"Zero dimension.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:558\n#, c-format\nmsgid \"Matrix has width %d, height %d.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:850\nmsgid \"List length\"\nmsgstr \"\"\n\n#: ../src/reduce.c:899\n#, c-format\nmsgid \"List index must be positive, not %d\"\nmsgstr \"\"\n\n#: ../src/reduce.c:907\nmsgid \"List index\"\nmsgstr \"\"\n\n#: ../src/reduce.c:912\n#, c-format\nmsgid \"List only has %d elements, unable to get element %d.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:955\nmsgid \"No arguments allowed.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:956\n#, c-format\nmsgid \"Object \\\"%s\\\" should have no arguments.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:1057\nmsgid \"C stack overflow. Expression too complex.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:1073\nmsgid \"Cancelled.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:1074\nmsgid \"Evaluation cancelled.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:1169\nmsgid \"No value.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:1170\n#, c-format\nmsgid \"Symbol \\\"%s\\\" has no value.\"\nmsgstr \"\"\n\n#: ../src/reduce.c:1645 ../src/reduce.c:1650 ../src/reduce.c:1656\nmsgid \"List generator\"\nmsgstr \"\"\n\n#: ../src/reduce.h:75 ../src/reduce.h:105\nmsgid \"Stack overflow.\"\nmsgstr \"\"\n\n#: ../src/reduce.h:76\nmsgid \"Spine stack overflow, runaway recursion?\"\nmsgstr \"\"\n\n#: ../src/reduce.h:106\nmsgid \"Frame stack overflow, expression too complex.\"\nmsgstr \"\"\n\n#: ../src/reduce.h:119 ../src/reduce.h:131\nmsgid \"Stack underflow.\"\nmsgstr \"\"\n\n#: ../src/reduce.h:120\nmsgid \"Frame stack underflow, you've found a bug!\"\nmsgstr \"\"\n\n#: ../src/reduce.h:132\nmsgid \"Spine stack underflow, you've found a bug!\"\nmsgstr \"\"\n\n#: ../src/regionview.c:935 ../src/rowview.c:302\nmsgid \"Can't duplicate.\"\nmsgstr \"\"\n\n#: ../src/regionview.c:937\nmsgid \"You can only duplicate top level regions.\"\nmsgstr \"\"\n\n#: ../src/regionview.c:979\nmsgid \"Can't delete.\"\nmsgstr \"\"\n\n#: ../src/regionview.c:980\nmsgid \"You can only delete top level regions.\"\nmsgstr \"\"\n\n#: ../src/regionview.c:989\nmsgid \"Delete Region?\"\nmsgstr \"\"\n\n#: ../src/regionview.c:990\n#, c-format\nmsgid \"Are you sure you want to delete Region \\\"%s\\\"?\"\nmsgstr \"\"\n\n#. Other init.\n#.\n#: ../src/regionview.c:1015\nmsgid \"Region menu\"\nmsgstr \"\"\n\n#: ../src/row.c:288\nmsgid \"Error in row.\"\nmsgstr \"\"\n\n#. Elements are name of row, principal error,\n#. * secondary error.\n#.\n#: ../src/row.c:292\n#, c-format\nmsgid \"\"\n\"Error in row %s: %s\\n\"\n\"%s\"\nmsgstr \"\"\n\n#. Expands to eg. \"B1 refers to: B2, B3\".\n#.\n#: ../src/row.c:497\nmsgid \"refers to\"\nmsgstr \"\"\n\n#. Expands to eg. \"B1 is referred to by: B2, B3\".\n#.\n#: ../src/row.c:508\nmsgid \"is referred to by\"\nmsgstr \"\"\n\n#: ../src/row.c:521\nmsgid \"is blocked on\"\nmsgstr \"\"\n\n#: ../src/rowview.c:304\nmsgid \"You can only duplicate top level rows.\"\nmsgstr \"\"\n\n#: ../src/rowview.c:457\nmsgid \"Drag between columns not yet implemented.\"\nmsgstr \"\"\n\n#. Other init.\n#.\n#: ../src/rowview.c:585\nmsgid \"Row menu\"\nmsgstr \"\"\n\n#: ../src/rowview.c:594 ../src/workspacedefs.c:262\nmsgid \"Replace From _File\"\nmsgstr \"\"\n\n#: ../src/rowview.c:598\nmsgid \"Re_set\"\nmsgstr \"\"\n\n#: ../src/rowview.c:664\nmsgid \"Click to open or close class\"\nmsgstr \"\"\n\n#: ../src/slider.c:51\nmsgid \"From\"\nmsgstr \"\"\n\n#: ../src/slider.c:54\nmsgid \"To\"\nmsgstr \"\"\n\n#: ../src/spin.c:223\nmsgid \"Expand or collapse row\"\nmsgstr \"\"\n\n#: ../src/symbol.c:503\n#, c-format\nmsgid \"Symbol %s is not defined.\"\nmsgstr \"\"\n\n#: ../src/symbol.c:507\n#, c-format\nmsgid \"%s is referred to by\"\nmsgstr \"\"\n\n#: ../src/symbol.c:721\n#, c-format\nmsgid \"Redefinition of \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/symbol.c:725\n#, c-format\nmsgid \"Previously defined at line %d.\"\nmsgstr \"\"\n\n#: ../src/symbol.c:748\n#, c-format\nmsgid \"Attempt to redefine root symbol \\\"%s\\\".\"\nmsgstr \"\"\n\n#. Parameter, workspace, etc.\n#.\n#: ../src/symbol.c:773\n#, c-format\nmsgid \"Can't redefine %s \\\"%s\\\".\"\nmsgstr \"\"\n\n#. used as in \"fred refers to undefined symbol jim\"\n#.\n#: ../src/tool.c:75\nmsgid \"refers to undefined symbol\"\nmsgstr \"\"\n\n#: ../src/tool.c:868\n#, c-format\nmsgid \"\"\n\"Can't create dialog with name \\\"%s\\\", an object with that name already \"\n\"exists in kit \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/toolkitbrowser.c:242\nmsgid \"Search:\"\nmsgstr \"\"\n\n#: ../src/toolkitbrowser.c:267\nmsgid \"Action\"\nmsgstr \"\"\n\n#: ../src/toolkitbrowser.c:275\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../src/toolkitbrowser.c:283\nmsgid \"Menu Item\"\nmsgstr \"\"\n\n#: ../src/toolkitgroup.c:139\n#, c-format\nmsgid \"Toolkits for %s\"\nmsgstr \"\"\n\n#: ../src/trace.c:127\nmsgid \"Trace buffer stack overflow.\"\nmsgstr \"\"\n\n#: ../src/trace.c:231\nmsgid \"Clear trace window\"\nmsgstr \"\"\n\n#: ../src/trace.c:237\nmsgid \"_Operators\"\nmsgstr \"\"\n\n#: ../src/trace.c:238\nmsgid \"trace operators\"\nmsgstr \"\"\n\n#: ../src/trace.c:242\nmsgid \"_Builtin Functions\"\nmsgstr \"\"\n\n#: ../src/trace.c:243\nmsgid \"trace calls to built in functions\"\nmsgstr \"\"\n\n#: ../src/trace.c:247\nmsgid \"_Class Construction\"\nmsgstr \"\"\n\n#: ../src/trace.c:248\nmsgid \"trace class constructors\"\nmsgstr \"\"\n\n#: ../src/trace.c:252\nmsgid \"_VIPS Operations\"\nmsgstr \"\"\n\n#: ../src/trace.c:253\nmsgid \"trace calls to VIPS\"\nmsgstr \"\"\n\n#: ../src/trace.c:331\nmsgid \"Trace\"\nmsgstr \"\"\n\n#: ../src/tslider.c:369\nmsgid \"Slider value ... edit!\"\nmsgstr \"\"\n\n#: ../src/tslider.c:390\nmsgid \"Left-drag to set number\"\nmsgstr \"\"\n\n#: ../src/util.c:211\nmsgid \"Unable to set XML property.\"\nmsgstr \"\"\n\n#: ../src/util.c:212\n#, c-format\nmsgid \"Unable to set property \\\"%s\\\" to value \\\"%s\\\".\"\nmsgstr \"\"\n\n#: ../src/util.c:830\nmsgid \"(no image)\"\nmsgstr \"\"\n\n#: ../src/util.c:844\n#, c-format\nmsgid \"%dx%d %s, %d band, %s\"\nmsgid_plural \"%dx%d %s, %d bands, %s\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\n#: ../src/util.c:1257\nmsgid \"8-bit unsigned integer\"\nmsgstr \"\"\n\n#. IM_BANDFMT_UCHAR\n#: ../src/util.c:1258\nmsgid \"8-bit signed integer\"\nmsgstr \"\"\n\n#. IM_BANDFMT_CHAR\n#: ../src/util.c:1259\nmsgid \"16-bit unsigned integer\"\nmsgstr \"\"\n\n#. IM_BANDFMT_USHORT\n#: ../src/util.c:1260\nmsgid \"16-bit signed integer\"\nmsgstr \"\"\n\n#. IM_BANDFMT_SHORT\n#: ../src/util.c:1261\nmsgid \"32-bit unsigned integer\"\nmsgstr \"\"\n\n#. IM_BANDFMT_UINT\n#: ../src/util.c:1262\nmsgid \"32-bit signed integer\"\nmsgstr \"\"\n\n#. IM_BANDFMT_INT\n#: ../src/util.c:1263\nmsgid \"32-bit float\"\nmsgstr \"\"\n\n#. IM_BANDFMT_FLOAT\n#: ../src/util.c:1264\nmsgid \"64-bit complex\"\nmsgstr \"\"\n\n#. IM_BANDFMT_COMPLEX\n#: ../src/util.c:1265\nmsgid \"64-bit float\"\nmsgstr \"\"\n\n#. IM_BANDFMT_DOUBLE\n#: ../src/util.c:1266\nmsgid \"128-bit complex\"\nmsgstr \"\"\n\n#: ../src/util.c:1274\nmsgid \"<unknown format>\"\nmsgstr \"\"\n\n#: ../src/util.c:1316\nmsgid \"<unknown type>\"\nmsgstr \"\"\n\n#: ../src/util.c:1340\nmsgid \"directory\"\nmsgstr \"\"\n\n#: ../src/util.c:1599\nmsgid \"Unable to find install area.\"\nmsgstr \"\"\n\n#: ../src/util.c:1775\nmsgid \"<charset conversion error>\"\nmsgstr \"\"\n\n#: ../src/util.c:1933\nmsgid \"Filename is too long.\"\nmsgstr \"\"\n\n#: ../src/util.c:1939\nmsgid \"Filename contains only blank characters.\"\nmsgstr \"\"\n\n#: ../src/util.c:2002 ../src/util.c:2011 ../src/util.c:2066\nmsgid \"Unable to open.\"\nmsgstr \"\"\n\n#: ../src/util.c:2003 ../src/util.c:2012\n#, c-format\nmsgid \"\"\n\"Unable to open file \\\"%s\\\" for reading.\\n\"\n\"%s.\"\nmsgstr \"\"\n\n#: ../src/util.c:2067\n#, c-format\nmsgid \"\"\n\"Unable to open file \\\"%s\\\" for writing.\\n\"\n\"%s.\"\nmsgstr \"\"\n\n#: ../src/util.c:2088\nmsgid \"Unable to write.\"\nmsgstr \"\"\n\n#: ../src/util.c:2089\n#, c-format\nmsgid \"\"\n\"Unable to write to file \\\"%s\\\".\\n\"\n\"%s.\"\nmsgstr \"\"\n\n#: ../src/util.c:2124 ../src/util.c:2137 ../src/util.c:2162\nmsgid \"Unable to read.\"\nmsgstr \"\"\n\n#: ../src/util.c:2125\n#, c-format\nmsgid \"File \\\"%s\\\" too large.\"\nmsgstr \"\"\n\n#: ../src/util.c:2138 ../src/util.c:2163\n#, c-format\nmsgid \"\"\n\"Unable to read from file \\\"%s\\\".\\n\"\n\"%s.\"\nmsgstr \"\"\n\n#. File length unit.\n#.\n#: ../src/util.c:2454\nmsgid \"bytes\"\nmsgstr \"\"\n\n#. Kilo byte unit.\n#.\n#: ../src/util.c:2458\nmsgid \"KB\"\nmsgstr \"\"\n\n#. Mega byte unit.\n#.\n#: ../src/util.c:2462\nmsgid \"MB\"\nmsgstr \"\"\n\n#. Giga byte unit.\n#.\n#: ../src/util.c:2466\nmsgid \"GB\"\nmsgstr \"\"\n\n#. Tera byte unit.\n#.\n#: ../src/util.c:2470\nmsgid \"TB\"\nmsgstr \"\"\n\n#: ../src/util.c:2513\nmsgid \"Unable to create temporary file.\"\nmsgstr \"\"\n\n#: ../src/util.c:2514\n#, c-format\nmsgid \"\"\n\"Unable to make file \\\"%s\\\"\\n\"\n\"%s\"\nmsgstr \"\"\n\n#: ../src/util.c:2721\nmsgid \"Out of memory.\"\nmsgstr \"\"\n\n#: ../src/util.c:2722\n#, c-format\nmsgid \"Request for %s of RAM triggered memory allocation failure.\"\nmsgstr \"\"\n\n#: ../src/vipsobject.c:94\nmsgid \"No such type.\"\nmsgstr \"\"\n\n#: ../src/vipsobject.c:95\n#, c-format\nmsgid \"Type \\\"%s\\\" not found as a subclass of VipsObject.\"\nmsgstr \"\"\n\n#: ../src/vipsobject.c:126\n#, c-format\nmsgid \"No more than %d arguments allowed.\"\nmsgstr \"\"\n\n#: ../src/vipsobject.c:253\nmsgid \"Wrong number of required arguments.\"\nmsgstr \"\"\n\n#: ../src/vipsobject.c:254\n#, c-format\nmsgid \"Operation \\\"%s\\\" has %d required arguments, you supplied %d.\"\nmsgstr \"\"\n\n#: ../src/vipsobject.c:285\nmsgid \"Unable to build object.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:156\nmsgid \"No objects selected.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:157 ../src/workspace.c:162\nmsgid \"Select exactly one object and try again.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:161\nmsgid \"More than one object selected.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:791 ../src/workspace.c:799\nmsgid \"No backup workspaces found.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:793\nmsgid \"\"\n\"You need to enable \\\"Auto workspace save\\\" in Preferences before automatic \"\n\"recovery works.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:800\n#, c-format\nmsgid \"No suitable workspace save files found in \\\"%s\\\"\"\nmsgstr \"\"\n\n#: ../src/workspace.c:816\nmsgid \"Open workspace backup?\"\nmsgstr \"\"\n\n#: ../src/workspace.c:817\n#, c-format\nmsgid \"\"\n\"Found workspace \\\"%s\\\", dated %s. Do you want to recover this workspace?\"\nmsgstr \"\"\n\n#: ../src/workspace.c:1327\nmsgid \"Version mismatch.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:1328\n#, c-format\nmsgid \"\"\n\"File \\\"%s\\\" was saved from %s-%d.%d.%d. You may see compatibility problems.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:1485\nmsgid \"// private definitions for this workspace\\n\"\nmsgstr \"\"\n\n#: ../src/workspace.c:1530\n#, c-format\nmsgid \"Can't create workspace \\\"%s\\\". A symbol with that name already exists.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:1621\nmsgid \"Default empty workspace\"\nmsgstr \"\"\n\n#: ../src/workspace.c:1694\n#, c-format\nmsgid \"%s needs %d arguments, there are %d selected.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:1705\nmsgid \"Too many names selected.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:1845\nmsgid \"You can only remove top level rows.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:1846\nmsgid \"Not all selected objects are top level rows.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:1896\nmsgid \"Delete selected objects?\"\nmsgstr \"\"\n\n#: ../src/workspace.c:1897\n#, c-format\nmsgid \"Are you sure you want to delete %s?\"\nmsgstr \"\"\n\n#: ../src/workspace.c:1955\nmsgid \"Unable to ungroup.\"\nmsgstr \"\"\n\n#: ../src/workspace.c:1956\n#, c-format\nmsgid \"Row \\\"%s\\\" is not a Group or a list.\"\nmsgstr \"\"\n\n#: ../src/workspacedefs.c:97\n#, c-format\nmsgid \"%d definition\"\nmsgid_plural \"%d definitions\"\nmsgstr[0] \"\"\nmsgstr[1] \"\"\n\n#: ../src/workspacedefs.c:103\nmsgid \"errors\"\nmsgstr \"\"\n\n#: ../src/workspacedefs.c:181\nmsgid \"Replace Definition From File\"\nmsgstr \"\"\n\n#: ../src/workspacedefs.c:261\nmsgid \"Workspace definitions\"\nmsgstr \"\"\n\n#: ../src/workspacedefs.c:282\nmsgid \"Process\"\nmsgstr \"\"\n\n#: ../src/workspacegroup.c:146\n#, c-format\nmsgid \"\"\n\"Can't create workspacegroup \\\"%s\\\". A symbol with that name already exists.\"\nmsgstr \"\"\n\n#: ../src/workspacegroup.c:213\nmsgid \"Set workspace name here\"\nmsgstr \"\"\n\n#: ../src/workspacegroup.c:215\nmsgid \"Set workspace caption here\"\nmsgstr \"\"\n\n#: ../src/workspacegroup.c:217\nmsgid \"New Workspace\"\nmsgstr \"\"\n\n#: ../src/workspacegroup.c:221\nmsgid \"Create Workspace\"\nmsgstr \"\"\n"
  },
  {
    "path": "po/malkovich.po",
    "content": "# test translation file\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: nip2 7.11.11\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2010-06-09 21:25+0100\\n\"\n\"PO-Revision-Date: 2006-09-06 12:30+0000\\n\"\n\"Last-Translator: john <jcupitt@gmail.com>\\n\"\n\"Language-Team: dk <LL@li.org>\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=n != 1;\\n\"\n\n#. Create signals.\n#.\n#. Init methods.\n#.\n#: src/plotstatus.c:99 src/statusview.c:108\nmsgid \"Status bar menu\"\nmsgstr \"Malkovich\"\n\n#: src/plotstatus.c:190 src/statusview.c:223 src/statusview.c:226\nmsgid \"Magnification\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:186\nmsgid \"circular\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:191\n#, fuzzy, c-format\nmsgid \"circular to label %d\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:201\n#, fuzzy, c-format\nmsgid \"label %d\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:218\nmsgid \"unevaluated\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:253\n#, fuzzy, c-format\nmsgid \"class (%p)\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:264\nmsgid \"members\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:275\nmsgid \"secret\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:328\n#, fuzzy, c-format\nmsgid \"no value (type %d)\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:336\nmsgid \"NULL pointer\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:345\nmsgid \"symbol\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:353\nmsgid \"constructor\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:361\nmsgid \"symref\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:369\nmsgid \"compileref\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:397\n#, fuzzy, c-format\nmsgid \"tag \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/graph.c:412\n#, fuzzy, c-format\nmsgid \"unknown element tag %d\"\nmsgstr \"Malkovich\"\n\n#: src/pathnameview.c:80 src/gtkutil.c:756 src/gtkutil.c:791 src/gtkutil.c:845\n#: src/editview.c:79 src/formula.c:198 src/fontnameview.c:80\n#: src/optionview.c:172 src/sliderview.c:74\n#, fuzzy, c-format\nmsgid \"%s:\"\nmsgstr \"Malkovich\"\n\n#: src/pathnameview.c:173\nmsgid \"Select a new file name\"\nmsgstr \"Malkovich\"\n\n#: src/pathname.c:81 src/slider.c:48 src/option.c:65 src/string.c:67\n#: src/toggle.c:48 src/number.c:65 src/fontname.c:58 src/mainw.c:1335\n#: src/mainw.c:1374 src/program.c:1053 src/program.c:1095\n#: src/workspacegroup.c:178 src/workspacegroup.c:215\nmsgid \"Caption\"\nmsgstr \"Malkovich\"\n\n#: src/pathname.c:84 src/slider.c:57 src/option.c:71 src/string.c:70\n#: src/toggle.c:51 src/clock.c:193 src/number.c:68 src/fontname.c:61\n#: src/colour.c:302 src/matrix.c:260 src/plot.c:340\nmsgid \"Value\"\nmsgstr \"Malkovich\"\n\n#: src/iarrow.c:117\nmsgid \"No image\"\nmsgstr \"Malkovich\"\n\n#. Used in (eg.) \"Mark at (10, 10) on [A1, A2]\"\n#.\n#. Expands to (eg.) \"Region on A1 at (10, 10), size (50, 50)\"\n#.\n#: src/iarrow.c:130 src/iregion.c:156\nmsgid \"on\"\nmsgstr \"Malkovich\"\n\n#: src/iarrow.c:148 src/iarrow.c:153\n#, fuzzy, c-format\nmsgid \"at %d\"\nmsgstr \"Malkovich\"\n\n#: src/iarrow.c:158\n#, fuzzy, c-format\nmsgid \"at (%d, %d)\"\nmsgstr \"Malkovich\"\n\n#: src/iarrow.c:165\n#, fuzzy, c-format\nmsgid \"at (%d, %d), offset (%d, %d)\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:174 src/vips_call.c:1106 src/vipsobject.c:284\n#: src/util.c:191\nmsgid \"VIPS library error.\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:175 src/vips_call.c:1109\n#, fuzzy, c-format\nmsgid \"Error calling library function \\\"%s\\\" (%s).\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:190\nmsgid \"Unknown type.\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:191\n#, fuzzy, c-format\nmsgid \"VIPS type \\\"%s\\\" not supported\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:955 src/vips_call.c:975 src/class.c:854\nmsgid \"You passed:\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1028\nmsgid \"Usage:\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1030\n#, fuzzy, c-format\nmsgid \"VIPS operator \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1032\n#, fuzzy, c-format\nmsgid \"%s, from package \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1037\n#, fuzzy, c-format\nmsgid \"\\\"%s\\\" takes %d argument:\"\nmsgid_plural \"\\\"%s\\\" takes %d arguments:\"\nmsgstr[0] \"Malkovich\"\nmsgstr[1] \"Malkovich\"\n\n#: src/vips_call.c:1044\n#, fuzzy, c-format\nmsgid \"And produces %d result:\"\nmsgid_plural \"And produces %d results:\"\nmsgstr[0] \"Malkovich\"\nmsgstr[1] \"Malkovich\"\n\n#. Print any flags this function has.\n#.\n#: src/vips_call.c:1052\nmsgid \"Flags:\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1056\nmsgid \"PIO function\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1058\nmsgid \"WIO function\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1061\nmsgid \"coordinate transformer\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1063\nmsgid \"no coordinate transformation\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1066\nmsgid \"point-to-point operation\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1068\nmsgid \"area operation\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1071\nmsgid \"uncacheable operation\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1073\nmsgid \"operation can be cached\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1085 src/action.c:173 src/reduce.c:878 src/reduce.c:891\n#: src/builtin.c:990 src/class.c:49 src/class.c:1019\nmsgid \"Bad argument.\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1088\n#, fuzzy, c-format\nmsgid \"Argument %d (%s) to \\\"%s\\\" is the wrong type.\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:1112\n#, fuzzy, c-format\nmsgid \"VIPS library: %s\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:2166 src/vips_call.c:2215\n#, fuzzy, c-format\nmsgid \"image \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:2173\nmsgid \"no image\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:2189\nmsgid \"doublevec\"\nmsgstr \"Malkovich\"\n\n#: src/vips_call.c:2212\nmsgid \"imagevec\"\nmsgstr \"Malkovich\"\n\n#: src/matrixview.c:105 src/gtkutil.c:663 src/gtkutil.c:671\nmsgid \"Bad floating point number.\"\nmsgstr \"Malkovich\"\n\n#: src/matrixview.c:106 src/gtkutil.c:664\n#, fuzzy, c-format\nmsgid \"\\\"%s\\\" is not a floating point number.\"\nmsgstr \"Malkovich\"\n\n#: src/matrixview.c:198 src/matrixview.c:219 src/classmodel.c:1161\n#: src/plot.c:140 src/plot.c:150 src/plot.c:360 src/plot.c:379 src/plot.c:392\nmsgid \"Bad value.\"\nmsgstr \"Malkovich\"\n\n#: src/matrixview.c:199 src/matrixview.c:220\n#, fuzzy, c-format\nmsgid \"\"\n\"Cell (%d, %d):\\n\"\n\"%s\"\nmsgstr \"Malkovich\"\n\n#: src/matrixview.c:434 src/matrix.c:263\nmsgid \"Scale\"\nmsgstr \"Malkovich\"\n\n#: src/matrixview.c:439 src/matrix.c:266\nmsgid \"Offset\"\nmsgstr \"Malkovich\"\n\n#. Expands to (eg) \"A2: cell (1,2): 45\" ... status line display during\n#. * matrix traverse.\n#.\n#: src/matrixview.c:649\n#, fuzzy, c-format\nmsgid \": cell (%d, %d): %s\"\nmsgstr \"Malkovich\"\n\n#: src/slider.c:51\nmsgid \"From\"\nmsgstr \"Malkovich\"\n\n#: src/slider.c:54\nmsgid \"To\"\nmsgstr \"Malkovich\"\n\n#. Need one menu per image window (could have a single menu for all\n#. * windows, but then we'd have to set the state of the toggle buttons\n#. * before mapping)\n#.\n#: src/imagepresent.c:1562\nmsgid \"Ruler menu\"\nmsgstr \"Malkovich\"\n\n#: src/imagepresent.c:1563\nmsgid \"Rulers In _mm\"\nmsgstr \"Malkovich\"\n\n#: src/imagepresent.c:1565\nmsgid \"Show _Offset\"\nmsgstr \"Malkovich\"\n\n#: src/option.c:68\nmsgid \"Labels\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:86\nmsgid \"Workspace files (*.ws)\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:88\nmsgid \"Recombination matrix files (*.rec)\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:90\nmsgid \"Morphology matrix files (*.mor)\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:92\nmsgid \"Convolution matrix files (*.con)\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:94\nmsgid \"Matrix files (*.mat)\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:96\nmsgid \"Definition files (*.def)\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:98\nmsgid \"ICC profiles (*.icc, *.icm)\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:100\nmsgid \"All files (*)\"\nmsgstr \"Malkovich\"\n\n#. Used as eg. \"VIPS image files (*.v)\"\n#.\n#: src/filesel.c:133\n#, fuzzy\nmsgid \"image files\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:500\n#, fuzzy, c-format\nmsgid \"Unable to determine space free in \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#. Expands to (eg.) '6GB free in \"/pics/tmp\"'\n#.\n#: src/filesel.c:511\n#, fuzzy, c-format\nmsgid \"free in \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:759 src/util.c:1932 src/util.c:1938\nmsgid \"Bad filename.\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:760\nmsgid \"No file selected.\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:990\nmsgid \"Increment filename\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:996\nmsgid \"After Save, add 1 to the last number in the file name\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:1235\n#, fuzzy, c-format\nmsgid \"%s Save Preferences\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:1296\nmsgid \"Overwrite\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:1297\nmsgid \"Overwrite file?\"\nmsgstr \"Malkovich\"\n\n#: src/filesel.c:1298\n#, fuzzy, c-format\nmsgid \"File \\\"%s\\\" exists. OK to overwrite?\"\nmsgstr \"Malkovich\"\n\n#: src/gtkutil.c:608\nmsgid \"Bad identifier.\"\nmsgstr \"Malkovich\"\n\n#: src/gtkutil.c:610\nmsgid \"\"\n\"Enter an identifier. Identifiers start with a letter, and then contain only \"\n\"letters, numbers, apostrophy and underscore.\"\nmsgstr \"Malkovich\"\n\n#: src/gtkutil.c:672\n#, fuzzy, c-format\nmsgid \"Extra characters \\\"%s\\\" after number.\"\nmsgstr \"Malkovich\"\n\n#: src/gtkutil.c:696\nmsgid \"Bad integer.\"\nmsgstr \"Malkovich\"\n\n#: src/gtkutil.c:697\n#, fuzzy, c-format\nmsgid \"\\\"%s\\\" is not an integer.\"\nmsgstr \"Malkovich\"\n\n#: src/gtkutil.c:715\nmsgid \"Bad unsigned integer.\"\nmsgstr \"Malkovich\"\n\n#: src/gtkutil.c:731\nmsgid \"Bad positive integer.\"\nmsgstr \"Malkovich\"\n\n#: src/gtkutil.c:853 src/toggleview.c:106\nmsgid \"Left-click to change value\"\nmsgstr \"Malkovich\"\n\n#: src/vipsobject.c:94\n#, fuzzy\nmsgid \"No such type.\"\nmsgstr \"Malkovich\"\n\n#: src/vipsobject.c:95\n#, fuzzy, c-format\nmsgid \"Type \\\"%s\\\" not found as a subclass of VipsObject.\"\nmsgstr \"Malkovich\"\n\n#: src/vipsobject.c:125 src/compile.c:1767 src/class.c:657 src/class.c:881\n#: src/class.c:978\nmsgid \"Too many arguments.\"\nmsgstr \"Malkovich\"\n\n#: src/vipsobject.c:126\n#, fuzzy, c-format\nmsgid \"No more than %d arguments allowed.\"\nmsgstr \"Malkovich\"\n\n#: src/vipsobject.c:253\nmsgid \"Wrong number of required arguments.\"\nmsgstr \"Malkovich\"\n\n#: src/vipsobject.c:254\n#, fuzzy, c-format\nmsgid \"Operation \\\"%s\\\" has %d required arguments, you supplied %d.\"\nmsgstr \"Malkovich\"\n\n#: src/vipsobject.c:285\n#, fuzzy\nmsgid \"Unable to build object.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:211\nmsgid \"Unable to set XML property.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:212\n#, fuzzy, c-format\nmsgid \"Unable to set property \\\"%s\\\" to value \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:830\nmsgid \"(no image)\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:844\n#, fuzzy, c-format\nmsgid \"%dx%d %s, %d band, %s\"\nmsgid_plural \"%dx%d %s, %d bands, %s\"\nmsgstr[0] \"Malkovich\"\nmsgstr[1] \"Malkovich\"\n\n#: src/util.c:1257\nmsgid \"8-bit unsigned integer\"\nmsgstr \"Malkovich\"\n\n#. IM_BANDFMT_UCHAR\n#: src/util.c:1258\nmsgid \"8-bit signed integer\"\nmsgstr \"Malkovich\"\n\n#. IM_BANDFMT_CHAR\n#: src/util.c:1259\nmsgid \"16-bit unsigned integer\"\nmsgstr \"Malkovich\"\n\n#. IM_BANDFMT_USHORT\n#: src/util.c:1260\nmsgid \"16-bit signed integer\"\nmsgstr \"Malkovich\"\n\n#. IM_BANDFMT_SHORT\n#: src/util.c:1261\nmsgid \"32-bit unsigned integer\"\nmsgstr \"Malkovich\"\n\n#. IM_BANDFMT_UINT\n#: src/util.c:1262\nmsgid \"32-bit signed integer\"\nmsgstr \"Malkovich\"\n\n#. IM_BANDFMT_INT\n#: src/util.c:1263\nmsgid \"32-bit float\"\nmsgstr \"Malkovich\"\n\n#. IM_BANDFMT_FLOAT\n#: src/util.c:1264\nmsgid \"64-bit complex\"\nmsgstr \"Malkovich\"\n\n#. IM_BANDFMT_COMPLEX\n#: src/util.c:1265\nmsgid \"64-bit float\"\nmsgstr \"Malkovich\"\n\n#. IM_BANDFMT_DOUBLE\n#: src/util.c:1266\nmsgid \"128-bit complex\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:1274\nmsgid \"<unknown format>\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:1316\nmsgid \"<unknown type>\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:1340\nmsgid \"directory\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:1349 src/dump.c:189\nmsgid \"workspace\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:1599\nmsgid \"Unable to find install area.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:1775\nmsgid \"<charset conversion error>\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:1933\nmsgid \"Filename is too long.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:1939\nmsgid \"Filename contains only blank characters.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:2002 src/util.c:2011 src/util.c:2066\nmsgid \"Unable to open.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:2003 src/util.c:2012\n#, fuzzy, c-format\nmsgid \"\"\n\"Unable to open file \\\"%s\\\" for reading.\\n\"\n\"%s.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:2067\n#, fuzzy, c-format\nmsgid \"\"\n\"Unable to open file \\\"%s\\\" for writing.\\n\"\n\"%s.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:2088\nmsgid \"Unable to write.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:2089\n#, fuzzy, c-format\nmsgid \"\"\n\"Unable to write to file \\\"%s\\\".\\n\"\n\"%s.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:2124 src/util.c:2137 src/util.c:2162\nmsgid \"Unable to read.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:2125\n#, fuzzy, c-format\nmsgid \"File \\\"%s\\\" too large.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:2138 src/util.c:2163\n#, fuzzy, c-format\nmsgid \"\"\n\"Unable to read from file \\\"%s\\\".\\n\"\n\"%s.\"\nmsgstr \"Malkovich\"\n\n#. File length unit.\n#.\n#: src/util.c:2454\nmsgid \"bytes\"\nmsgstr \"Malkovich\"\n\n#. Kilo byte unit.\n#.\n#: src/util.c:2458\nmsgid \"KB\"\nmsgstr \"Malkovich\"\n\n#. Mega byte unit.\n#.\n#: src/util.c:2462\nmsgid \"MB\"\nmsgstr \"Malkovich\"\n\n#. Giga byte unit.\n#.\n#: src/util.c:2466\nmsgid \"GB\"\nmsgstr \"Malkovich\"\n\n#. Tera byte unit.\n#.\n#: src/util.c:2470\nmsgid \"TB\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:2513\nmsgid \"Unable to create temporary file.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:2514\n#, fuzzy, c-format\nmsgid \"\"\n\"Unable to make file \\\"%s\\\"\\n\"\n\"%s\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:2721\nmsgid \"Out of memory.\"\nmsgstr \"Malkovich\"\n\n#: src/util.c:2722\n#, fuzzy, c-format\nmsgid \"Request for %s of RAM triggered memory allocation failure.\"\nmsgstr \"Malkovich\"\n\n#: src/view.c:820 src/classmodel.c:154 src/classmodel.c:227 src/builtin.c:410\n#: src/mainw.c:739 src/mainw.c:747 src/model.c:313 src/model.c:368\n#: src/filemodel.c:100 src/filemodel.c:130 src/filemodel.c:342\n#: src/filemodel.c:566 src/filemodel.c:607 src/rowview.c:456\nmsgid \"Not implemented.\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:126 src/reduce.c:128 src/reduce.c:1036 src/workspace.c:1597\nmsgid \"Overflow error.\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:127\nmsgid \"Trace buffer stack overflow.\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:238 src/error.c:123\nmsgid \"_Clear\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:239\nmsgid \"Clear trace window\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:243 src/imageview.c:499 src/mainw.c:1662 src/program.c:1700\n#: src/plotwindow.c:175 src/error.c:138\nmsgid \"_Close\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:244\nmsgid \"Close trace window\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:248 src/imageview.c:529 src/mainw.c:1732 src/program.c:1780\n#: src/plotwindow.c:180 src/error.c:143\nmsgid \"_Contents\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:249 src/imageview.c:530 src/mainw.c:1733 src/program.c:1781\n#: src/plotwindow.c:181 src/error.c:144\nmsgid \"Open the users guide\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:253 src/imageview.c:534 src/mainw.c:1727 src/program.c:1775\n#: src/plotwindow.c:185 src/error.c:148\nmsgid \"_About\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:254 src/imageview.c:535 src/mainw.c:1728 src/program.c:1776\n#: src/plotwindow.c:186 src/error.c:149\nmsgid \"About this program\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:260\nmsgid \"_Operators\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:261\nmsgid \"trace operators\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:265\nmsgid \"_Builtin Functions\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:266\nmsgid \"trace calls to built in functions\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:270\nmsgid \"_Class Construction\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:271\nmsgid \"trace class constructors\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:275\nmsgid \"_VIPS Operations\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:276\nmsgid \"trace calls to VIPS\"\nmsgstr \"Malkovich\"\n\n#: src/trace.c:352\nmsgid \"Trace\"\nmsgstr \"Malkovich\"\n\n#. Not found? Maybe - error message anyway.\n#.\n#: src/symbol.c:486 src/program.c:1440 src/program.c:1489 src/program.c:1511\n#: src/program.c:1519 src/path.c:278 src/path.c:305\nmsgid \"Not found.\"\nmsgstr \"Malkovich\"\n\n#: src/symbol.c:487\n#, fuzzy, c-format\nmsgid \"Symbol %s is not defined.\"\nmsgstr \"Malkovich\"\n\n#: src/symbol.c:491\n#, fuzzy, c-format\nmsgid \"%s is referred to by\"\nmsgstr \"Malkovich\"\n\n#: src/symbol.c:707\n#, fuzzy, c-format\nmsgid \"Redefinition of \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: src/symbol.c:711\n#, fuzzy, c-format\nmsgid \"Previously defined at line %d.\"\nmsgstr \"Malkovich\"\n\n#: src/symbol.c:734\n#, fuzzy, c-format\nmsgid \"Attempt to redefine root symbol \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#. Parameter, workspace, etc.\n#.\n#: src/symbol.c:759\n#, fuzzy, c-format\nmsgid \"Can't redefine %s \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: parse.y:244 parse.y:255\nmsgid \"not top level\"\nmsgstr \"Malkovich\"\n\n#: parse.y:260\nmsgid \"not strings\"\nmsgstr \"Malkovich\"\n\n#: parse.y:318\nmsgid \"left-hand-side pattern contains no identifiers\"\nmsgstr \"\"\n\n#: parse.y:1064 src/program.c:1421\nmsgid \"Parse error.\"\nmsgstr \"Malkovich\"\n\n#: parse.y:1067\n#, fuzzy, c-format\nmsgid \"Error in %s: %s\"\nmsgstr \"Malkovich\"\n\n#: parse.y:1070\n#, fuzzy, c-format\nmsgid \"Error: %s\"\nmsgstr \"Malkovich\"\n\n#: parse.y:1183\n#, fuzzy\nmsgid \"definition is too long\"\nmsgstr \"Malkovich\"\n\n#: parse.y:1607\n#, fuzzy\nmsgid \"no leading identifier\"\nmsgstr \"Malkovich\"\n\n#: parse.y:1613\nmsgid \"'=' missing\"\nmsgstr \"\"\n\n#: parse.y:1643\nmsgid \"identifier expected\"\nmsgstr \"\"\n\n#: parse.y:1653\n#, c-format\nmsgid \"'%s' does not exist\"\nmsgstr \"\"\n\n#: parse.y:1655\n#, c-format\nmsgid \"'%s' has no members\"\nmsgstr \"\"\n\n#: parse.y:1670\nmsgid \"'.' or '=' expected\"\nmsgstr \"\"\n\n#: src/editview.c:158\nmsgid \"Escape to cancel edit, press Return to accept edit and recalculate\"\nmsgstr \"Malkovich\"\n\n#: src/classmodel.c:155 src/classmodel.c:228\n#, fuzzy, c-format\nmsgid \"_%s() method not implemented for %s.\"\nmsgstr \"Malkovich\"\n\n#: src/classmodel.c:163\n#, fuzzy, c-format\nmsgid \"Save %s \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/classmodel.c:237\n#, fuzzy, c-format\nmsgid \"Replace %s \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/classmodel.c:695\nmsgid \"Set boolean value here\"\nmsgstr \"Malkovich\"\n\n#: src/classmodel.c:701\nmsgid \"Enter a floating point number here\"\nmsgstr \"Malkovich\"\n\n#: src/classmodel.c:708\nmsgid \"Enter a string here\"\nmsgstr \"Malkovich\"\n\n#. Expands to \"Edit Toggle A1\".\n#.\n#: src/classmodel.c:762\n#, fuzzy, c-format\nmsgid \"Edit %s %s\"\nmsgstr \"Malkovich\"\n\n#: src/classmodel.c:773\n#, fuzzy, c-format\nmsgid \"Set %s\"\nmsgstr \"Malkovich\"\n\n#: src/classmodel.c:1086\n#, fuzzy\nmsgid \"Unknown option.\"\nmsgstr \"Malkovich\"\n\n#: src/classmodel.c:1087\n#, fuzzy, c-format\nmsgid \"Option \\\"%s\\\" not known.\"\nmsgstr \"Malkovich\"\n\n#: src/classmodel.c:1162\n#, fuzzy, c-format\nmsgid \"%d band value only\"\nmsgstr \"Malkovich\"\n\n#: src/heap.c:812\nmsgid \"Heap full.\"\nmsgstr \"Malkovich\"\n\n#: src/heap.c:818\n#, fuzzy, c-format\nmsgid \"\"\n\"The compile heap for %s has filled. Make it smaller and less complicated.\"\nmsgstr \"Malkovich\"\n\n#: src/heap.c:823\nmsgid \"\"\n\"The main calculation heap has filled. Raise the heap size limit in \"\n\"Preferences.\"\nmsgstr \"Malkovich\"\n\n#: src/heap.c:1837\nmsgid \"Unimplemented list type.\"\nmsgstr \"Malkovich\"\n\n#: src/heap.c:1932\nmsgid \"Unimplemented type.\"\nmsgstr \"Malkovich\"\n\n#: src/heap.c:1933\n#, fuzzy, c-format\nmsgid \"Unable to convert %s to a nip type.\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:87\nmsgid \"Bad arguments.\"\nmsgstr \"Malkovich\"\n\n#. Expands to eg. 'bad args to \"+\", called from \"fred\"'\n#.\n#: src/action.c:102 src/action.c:186\nmsgid \"Called from\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:108\n#, fuzzy, c-format\nmsgid \"\"\n\"Error in binary \\\"%s\\\".\\n\"\n\"left = %s\\n\"\n\"right = %s\\n\"\n\"%s\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:142 src/class.c:190\n#, fuzzy, c-format\nmsgid \"Member \\\"%s\\\" not found in class \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:149\n#, fuzzy, c-format\nmsgid \"object = %s\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:153\n#, fuzzy, c-format\nmsgid \"tag = %s\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:158\n#, fuzzy, c-format\nmsgid \"Reference attempted in \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:162 src/class.c:189\nmsgid \"Member not found.\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:192\n#, fuzzy, c-format\nmsgid \"\"\n\"Error in unary \\\"%s\\\".\\n\"\n\"argument = %s\\n\"\n\"%s\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:359 src/action.c:377 src/action.c:407\n#, fuzzy\nmsgid \"Bad right hand side of '.'.\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:369\nmsgid \"Symbol on left hand side of '.' is not scope\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:411\n#, fuzzy\nmsgid \"Property not found.\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:425\nmsgid \"Bad left hand side of '.'.\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:937\nmsgid \"Division by zero.\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:1313 src/action.c:1593\nmsgid \"Unimplemented.\"\nmsgstr \"Malkovich\"\n\n#: src/action.c:1677 src/action.c:1713 src/action.c:1971\nmsgid \"invoking method:\"\nmsgstr \"Malkovich\"\n\n#. Create signals.\n#.\n#. Init methods.\n#.\n#: src/paintboxview.c:109\nmsgid \"Paintbox bar menu\"\nmsgstr \"Malkovich\"\n\n#: src/paintboxview.c:212\nmsgid \"Clear undo history?\"\nmsgstr \"Malkovich\"\n\n#: src/paintboxview.c:213\nmsgid \"\"\n\"Are you sure you want to clear all undo and redo? This will free up memory, \"\n\"but you will no longer be able to undo or redo any of the painting you have \"\n\"done so far.\"\nmsgstr \"Malkovich\"\n\n#: src/paintboxview.c:248\nmsgid \"1 round\"\nmsgstr \"Malkovich\"\n\n#. PAINTBOX_1ROUND\n#: src/paintboxview.c:249\nmsgid \"2 round\"\nmsgstr \"Malkovich\"\n\n#. PAINTBOX_2ROUND\n#: src/paintboxview.c:250\nmsgid \"3 round\"\nmsgstr \"Malkovich\"\n\n#. PAINTBOX_3ROUND\n#: src/paintboxview.c:251\nmsgid \"4 round\"\nmsgstr \"Malkovich\"\n\n#. PAINTBOX_4ROUND\n#: src/paintboxview.c:252\nmsgid \"5 round\"\nmsgstr \"Malkovich\"\n\n#. PAINTBOX_5ROUND\n#: src/paintboxview.c:253\nmsgid \"6 round\"\nmsgstr \"Malkovich\"\n\n#. PAINTBOX_6ROUND\n#: src/paintboxview.c:254\nmsgid \"10 round\"\nmsgstr \"Malkovich\"\n\n#. PAINTBOX_10ROUND\n#: src/paintboxview.c:255\nmsgid \"2 italic\"\nmsgstr \"Malkovich\"\n\n#. PAINTBOX_2ITALIC\n#: src/paintboxview.c:256\nmsgid \"3 italic\"\nmsgstr \"Malkovich\"\n\n#. PAINTBOX_3ITALIC\n#: src/paintboxview.c:257\nmsgid \"4 italic\"\nmsgstr \"Malkovich\"\n\n#. PAINTBOX_4ITALIC\n#: src/paintboxview.c:258\nmsgid \"5 italic\"\nmsgstr \"Malkovich\"\n\n#. PAINTBOX_5ITALIC\n#: src/paintboxview.c:259\nmsgid \"6 italic\"\nmsgstr \"Malkovich\"\n\n#. PAINTBOX_6ITALIC\n#: src/paintboxview.c:260\nmsgid \"10 italic\"\nmsgstr \"Malkovich\"\n\n#: src/paintboxview.c:264\nmsgid \"Manipulate regions\"\nmsgstr \"Malkovich\"\n\n#. IMAGEMODEL_SELECT\n#: src/paintboxview.c:265\nmsgid \"Pan window\"\nmsgstr \"Malkovich\"\n\n#. IMAGEMODEL_PAN\n#: src/paintboxview.c:266\nmsgid \"Zoom in on mouse\"\nmsgstr \"Malkovich\"\n\n#. IMAGEMODEL_MAGIN\n#: src/paintboxview.c:267 src/imageview.c:515 src/imageview.c:579\nmsgid \"Zoom out\"\nmsgstr \"Malkovich\"\n\n#. IMAGEMODEL_MAGOUT\n#: src/paintboxview.c:268\nmsgid \"Read pixel into inkwell\"\nmsgstr \"Malkovich\"\n\n#. IMAGEMODEL_DROPPER\n#: src/paintboxview.c:269\nmsgid \"Freehand draw \"\nmsgstr \"Malkovich\"\n\n#. IMAGEMODEL_PEN\n#: src/paintboxview.c:270\nmsgid \"Draw straight lines\"\nmsgstr \"Malkovich\"\n\n#. IMAGEMODEL_LINE\n#: src/paintboxview.c:271\nmsgid \"Fill rectangles\"\nmsgstr \"Malkovich\"\n\n#. IMAGEMODEL_RECT\n#: src/paintboxview.c:272\nmsgid \"Flood while pixel not equal to ink\"\nmsgstr \"Malkovich\"\n\n#. IMAGEMODEL_FLOOD\n#: src/paintboxview.c:274\nmsgid \"Flood while pixel equal to click\"\nmsgstr \"Malkovich\"\n\n#. IMAGEMODEL_BLOB\n#: src/paintboxview.c:276\nmsgid \"Draw text\"\nmsgstr \"Malkovich\"\n\n#. IMAGEMODEL_TEXT\n#: src/paintboxview.c:277 src/main.c:683\nmsgid \"Smudge\"\nmsgstr \"Malkovich\"\n\n#: src/paintboxview.c:327\nmsgid \"Undo last paint action\"\nmsgstr \"Malkovich\"\n\n#: src/paintboxview.c:336\nmsgid \"Redo last paint action\"\nmsgstr \"Malkovich\"\n\n#: src/paintboxview.c:345\nmsgid \"Clear all undo and redo buffers\"\nmsgstr \"Malkovich\"\n\n#: src/paintboxview.c:365\nmsgid \"Nib\"\nmsgstr \"Malkovich\"\n\n#: src/paintboxview.c:386\nmsgid \"Enter text for text tool\"\nmsgstr \"Malkovich\"\n\n#: src/clock.c:59 src/clock.c:93 src/clock.c:190\nmsgid \"Interval\"\nmsgstr \"Malkovich\"\n\n#: src/clock.c:60 src/clock.c:96\nmsgid \"Elapsed time\"\nmsgstr \"Malkovich\"\n\n#: src/clock.c:93\nmsgid \"Interval between ticks (seconds)\"\nmsgstr \"Malkovich\"\n\n#: src/clock.c:96\nmsgid \"Elapsed time (seconds)\"\nmsgstr \"Malkovich\"\n\n#: src/clock.c:100\n#, fuzzy, c-format\nmsgid \"Edit Clock \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/clock.c:104\nmsgid \"Set Clock\"\nmsgstr \"Malkovich\"\n\n#: src/workspacedefs.c:97\n#, fuzzy, c-format\nmsgid \"%d definition\"\nmsgid_plural \"%d definitions\"\nmsgstr[0] \"Malkovich\"\nmsgstr[1] \"Malkovich\"\n\n#: src/workspacedefs.c:103\n#, fuzzy\nmsgid \"errors\"\nmsgstr \"Malkovich\"\n\n#: src/workspacedefs.c:108 src/program.c:263\nmsgid \"modified\"\nmsgstr \"Malkovich\"\n\n#: src/workspacedefs.c:181\n#, fuzzy\nmsgid \"Replace Definition From File\"\nmsgstr \"Malkovich\"\n\n#: src/workspacedefs.c:261\n#, fuzzy\nmsgid \"Workspace definitions\"\nmsgstr \"Malkovich\"\n\n#: src/workspacedefs.c:262 src/rowview.c:594\nmsgid \"Replace From _File\"\nmsgstr \"Malkovich\"\n\n#: src/workspacedefs.c:282\n#, fuzzy\nmsgid \"Process\"\nmsgstr \"Malkovich\"\n\n#: lex.l:91 lex.l:101\nmsgid \"line too long\"\nmsgstr \"Malkovich\"\n\n#: lex.l:109\nmsgid \"end of line inside string\"\nmsgstr \"Malkovich\"\n\n#: lex.l:111\nmsgid \"no end of string\"\nmsgstr \"Malkovich\"\n\n#: lex.l:132 lex.l:142 lex.l:150\nmsgid \"bad char constant\"\nmsgstr \"Malkovich\"\n\n#: lex.l:175\n#, fuzzy\nmsgid \"nested comment\"\nmsgstr \"Malkovich\"\n\n#: lex.l:181\n#, fuzzy\nmsgid \"no end of comment\"\nmsgstr \"Malkovich\"\n\n#: lex.l:311\n#, fuzzy, c-format\nmsgid \"bad number %s\"\nmsgstr \"Malkovich\"\n\n#: lex.l:364\n#, fuzzy, c-format\nmsgid \"illegal character \\\"%c\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/formula.c:143\nmsgid \"\"\n\"Press Escape to cancel edit, press Return to accept edit and recalculate\"\nmsgstr \"Malkovich\"\n\n#: src/toolkitbrowser.c:242\nmsgid \"Search:\"\nmsgstr \"Malkovich\"\n\n#: src/toolkitbrowser.c:267\nmsgid \"Action\"\nmsgstr \"Malkovich\"\n\n#: src/toolkitbrowser.c:275\nmsgid \"Parameters\"\nmsgstr \"Malkovich\"\n\n#: src/toolkitbrowser.c:283\nmsgid \"Menu Item\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:112\nmsgid \"evaluate and print EXPRESSION\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:115\nmsgid \"load FILE as a set of definitions\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:118\nmsgid \"write value of 'main' to FILE\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:120\nmsgid \"run in batch mode\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:122\n#, fuzzy\nmsgid \"set values\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:124\nmsgid \"verbose error output\"\nmsgstr \"\"\n\n#: src/main.c:127\nmsgid \"don't load menu definitions\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:129\n#, fuzzy\nmsgid \"don't try to load command-line arguments\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:131\nmsgid \"load stdin as a workspace\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:133\nmsgid \"load stdin as a set of definitions\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:135\nmsgid \"print value of 'main' to stdout\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:138\nmsgid \"start up and shut down\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:141\nmsgid \"time image save operations\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:144\nmsgid \"start as if installed to PREFIX\"\nmsgstr \"\"\n\n#: src/main.c:146\nmsgid \"output strings for internationalisation\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:149\nmsgid \"print version number\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:152\nmsgid \"test for errors and quit\"\nmsgstr \"\"\n\n#: src/main.c:231\n#, fuzzy, c-format\nmsgid \"error calculating \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:239\n#, fuzzy, c-format\nmsgid \"error saving \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:293\n#, fuzzy\nmsgid \"no \\\"main\\\" found\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:456\nmsgid \"Unknown file type.\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:457\n#, fuzzy, c-format\nmsgid \"Unable to load \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:468\nmsgid \"Unable to load.\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:469\n#, fuzzy, c-format\nmsgid \"Error loading plug-in \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:677\nmsgid \"Next _Error\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:678\nmsgid \"Ink dropper\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:679\nmsgid \"D_uplicate\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:680\nmsgid \"Pen\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:681 src/plot.c:94\nmsgid \"Line\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:682 src/matrix.c:147\nmsgid \"Text\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:684\nmsgid \"Flood\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:685\nmsgid \"Flood Blob\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:686\nmsgid \"Fill Rectangle\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:687\nmsgid \"Pan\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:688\nmsgid \"Select\"\nmsgstr \"Malkovich\"\n\n#. And the LEDs we use.\n#.\n#: src/main.c:692\nmsgid \"Red LED\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:693\nmsgid \"Green LED\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:694\nmsgid \"Blue LED\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:695\nmsgid \"Yellow LED\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:696\nmsgid \"Cyan LED\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:697\nmsgid \"Off LED\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:884\nmsgid \"Empty temp area\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:885\nmsgid \"Many files in temp area.\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:886\n#, fuzzy, c-format\nmsgid \"\"\n\"The temp area \\\"%s\\\" contains %s of files. Would you like to empty the temp \"\n\"area? This will delete any workspace backups and cannot be undone.\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:902\n#, fuzzy, c-format\nmsgid \"unable to make %s %s: %s\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:1080\nmsgid \"- image processing spreadsheet\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:1112\n#, fuzzy, c-format\nmsgid \"linked to vips-%s\"\nmsgstr \"Malkovich\"\n\n#. -1 means can't-be-set, at least on os x, so don't\n#. * warn.\n#.\n#: src/main.c:1172\n#, fuzzy, c-format\nmsgid \"\"\n\"unable to change max file descriptors\\n\"\n\"max file descriptors still set to %d\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:1178\nmsgid \"unable to read max file descriptors\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:1402 src/main.c:1455\n#, fuzzy, c-format\nmsgid \"\"\n\"Startup error log:\\n\"\n\"%s\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:1454\nmsgid \"Startup error.\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:1465\n#, fuzzy, c-format\nmsgid \"Welcome to %s-%s!\"\nmsgstr \"Malkovich\"\n\n#: src/main.c:1470\n#, fuzzy, c-format\nmsgid \"\"\n\"A new directory has been created in your home directory to hold startup, \"\n\"data and temporary files:\\n\"\n\"\\n\"\n\"     %s\\n\"\n\"\\n\"\n\"If you've used previous versions of %s, you will probably want to move any \"\n\"files over from your old work area and remove any old temps.\"\nmsgstr \"Malkovich\"\n\n#: src/conversion.c:464\nmsgid \"not uncoded\"\nmsgstr \"Malkovich\"\n\n#: src/conversion.c:1406\n#, fuzzy, c-format\nmsgid \"Header for \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/conversion.c:1408\nmsgid \"OK\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:115\nmsgid \"Typecheck error.\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:117\n#, fuzzy, c-format\nmsgid \"%s expected %s, instead saw:\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:129\n#, fuzzy, c-format\nmsgid \"%s too long.\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:512 src/reduce.c:577\nmsgid \"Not rectangular.\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:513 src/reduce.c:578\n#, fuzzy, c-format\nmsgid \"\"\n\"Matrix of real is not rectangular. Found row of length %d, should be %d.\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:537\nmsgid \"Zero dimension.\"\nmsgstr \"\"\n\n#: src/reduce.c:538\n#, c-format\nmsgid \"Matrix has width %d, height %d.\"\nmsgstr \"\"\n\n#: src/reduce.c:830\nmsgid \"List length\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:879\n#, fuzzy, c-format\nmsgid \"List index must be positive, not %d\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:887\nmsgid \"List index\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:892\n#, fuzzy, c-format\nmsgid \"List only has %d elements, unable to get element %d.\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:935\nmsgid \"No arguments allowed.\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:936\n#, fuzzy, c-format\nmsgid \"Object \\\"%s\\\" should have no arguments.\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:1037\nmsgid \"C stack overflow. Expression too complex.\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:1053\n#, fuzzy\nmsgid \"Cancelled.\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:1054\nmsgid \"Evaluation cancelled.\"\nmsgstr \"\"\n\n#: src/reduce.c:1139\nmsgid \"No value.\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:1140\n#, fuzzy, c-format\nmsgid \"Symbol \\\"%s\\\" has no value.\"\nmsgstr \"Malkovich\"\n\n#: src/reduce.c:1612 src/reduce.c:1617 src/reduce.c:1623\nmsgid \"List generator\"\nmsgstr \"Malkovich\"\n\n#: src/builtin.c:257\nmsgid \"Out of range.\"\nmsgstr \"Malkovich\"\n\n#: src/builtin.c:258\nmsgid \"gammq arguments must be a > 0, x >= 0.\"\nmsgstr \"Malkovich\"\n\n#: src/builtin.c:265\nmsgid \"Not available.\"\nmsgstr \"Malkovich\"\n\n#: src/builtin.c:266\nmsgid \"No GSL library available for gammq.\"\nmsgstr \"Malkovich\"\n\n#: src/builtin.c:411\nmsgid \"Complex math ops not implemented.\"\nmsgstr \"Malkovich\"\n\n#: src/builtin.c:486\nmsgid \"Macro error.\"\nmsgstr \"Malkovich\"\n\n#: src/builtin.c:669\n#, fuzzy\nmsgid \"No such type\"\nmsgstr \"Malkovich\"\n\n#: src/builtin.c:670\n#, fuzzy, c-format\nmsgid \"GType %u not found.\"\nmsgstr \"Malkovich\"\n\n#: src/builtin.c:887\nmsgid \"GSL library error.\"\nmsgstr \"Malkovich\"\n\n#: src/builtin.c:936\n#, fuzzy, c-format\nmsgid \"Builtin \\\"%s\\\" takes %d argument.\"\nmsgid_plural \"Builtin \\\"%s\\\" takes %d arguments.\"\nmsgstr[0] \"Malkovich\"\nmsgstr[1] \"Malkovich\"\n\n#: src/builtin.c:991\n#, fuzzy, c-format\nmsgid \"\"\n\"Argument %d to builtin \\\"%s\\\" should be \\\"%s\\\", you passed:\\n\"\n\"  %s\"\nmsgstr \"Malkovich\"\n\n#: src/conversionview.c:66\nmsgid \"Unable to find image range.\"\nmsgstr \"Malkovich\"\n\n#: src/conversionview.c:67\nmsgid \"Find image range failed.\"\nmsgstr \"Malkovich\"\n\n#: src/conversionview.c:90\nmsgid \"Unable to scale image.\"\nmsgstr \"Malkovich\"\n\n#: src/conversionview.c:91\nmsgid \"Maximum and minimum pixel values are equal.\"\nmsgstr \"Malkovich\"\n\n#. Build menu. One for each window, as we need to track falsecolour\n#. * etc. toggles. Could just have one, and modify pre-popup, but this\n#. * is easier.\n#.\n#: src/conversionview.c:229\nmsgid \"Convert menu\"\nmsgstr \"Malkovich\"\n\n#: src/conversionview.c:230\nmsgid \"_Scale\"\nmsgstr \"Malkovich\"\n\n#: src/conversionview.c:232\nmsgid \"_False Color\"\nmsgstr \"Malkovich\"\n\n#: src/conversionview.c:234\nmsgid \"_Interpret\"\nmsgstr \"Malkovich\"\n\n#: src/conversionview.c:236 src/regionview.c:1027\nmsgid \"_Reset\"\nmsgstr \"Malkovich\"\n\n#: src/conversionview.c:238\nmsgid \"Set As Workspace _Default\"\nmsgstr \"Malkovich\"\n\n#: src/progress.c:111\n#, fuzzy\nmsgid \"Cancelling\"\nmsgstr \"Malkovich\"\n\n#: src/progress.c:144\n#, fuzzy, c-format\nmsgid \"%d minute left\"\nmsgid_plural \"%d minutes left\"\nmsgstr[0] \"Malkovich\"\nmsgstr[1] \"Malkovich\"\n\n#: src/progress.c:149\n#, fuzzy, c-format\nmsgid \"%d second left\"\nmsgid_plural \"%d seconds left\"\nmsgstr[0] \"Malkovich\"\nmsgstr[1] \"Malkovich\"\n\n#: src/progress.c:170\nmsgid \"Calculating\"\nmsgstr \"Malkovich\"\n\n#: src/progress.c:189\n#, fuzzy\nmsgid \"Loading\"\nmsgstr \"Malkovich\"\n\n#: src/expr.c:64\n#, fuzzy, c-format\nmsgid \"error in \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/expr.c:347\nmsgid \"Error\"\nmsgstr \"Malkovich\"\n\n#: src/expr.c:614\nmsgid \"top level\"\nmsgstr \"Malkovich\"\n\n#: src/expr.c:619\nmsgid \"class\"\nmsgstr \"Malkovich\"\n\n#: src/expr.c:622\nmsgid \"instance\"\nmsgstr \"Malkovich\"\n\n#: src/expr.c:626\nmsgid \"definition\"\nmsgstr \"Malkovich\"\n\n#: src/expr.c:633\n#, fuzzy, c-format\nmsgid \"parameter \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/expr.c:637\nmsgid \"member\"\nmsgstr \"Malkovich\"\n\n#: src/expr.c:642 src/dump.c:186\nmsgid \"value\"\nmsgstr \"Malkovich\"\n\n#: src/expr.c:646 src/itext.c:446\nmsgid \"function\"\nmsgstr \"Malkovich\"\n\n#: src/expr.c:655\nmsgid \"of\"\nmsgstr \"Malkovich\"\n\n#: src/imagemodel.c:505\nmsgid \"No text specified.\"\nmsgstr \"Malkovich\"\n\n#: src/imagemodel.c:506\nmsgid \"Enter some text to paint in the entry widget at the top of the window.\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:459\nmsgid \"New _Mark\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:460\nmsgid \"Create a new mark\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:464\nmsgid \"New _Horizontal Guide\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:465\nmsgid \"Create a new horizontal guide\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:469\nmsgid \"New _Vertical Guide\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:470\nmsgid \"Create a new vertical guide\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:474\nmsgid \"New _Arrow\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:475\nmsgid \"Create a new arrow\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:479\nmsgid \"New _Region\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:480\nmsgid \"Create a new region\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:484\nmsgid \"Replace Image\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:485\nmsgid \"Replace image from file\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:489\nmsgid \"Save Image As\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:490\nmsgid \"Save image to file\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:494 src/mainw.c:853\nmsgid \"Recalculate\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:495\nmsgid \"Recalculate image\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:500 src/program.c:1701 src/plotwindow.c:176\nmsgid \"Close\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:504\nmsgid \"Image _Header\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:505\nmsgid \"View image header\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:509 src/imageview.c:573\nmsgid \"Zoom _In\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:510 src/imageview.c:574\nmsgid \"Zoom in on mouse cursor\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:514 src/imageview.c:578\nmsgid \"Zoom _Out\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:519\nmsgid \"Zoom _100%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:520 src/imageview.c:593\nmsgid \"Zoom to 100%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:524\nmsgid \"Zoom to _Fit\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:525\nmsgid \"Zoom to fit image to window\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:541 src/plotwindow.c:192\nmsgid \"_Status\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:542 src/plotwindow.c:193\nmsgid \"Show status bar\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:546\nmsgid \"_Display Control\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:547\nmsgid \"Show display control bar\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:551\nmsgid \"_Paint\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:552\nmsgid \"Show paint bar\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:556\nmsgid \"_Rulers\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:557\nmsgid \"Show rulers\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:563\nmsgid \"_Select\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:564\nmsgid \"Select and modify selections\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:568\nmsgid \"_Pan\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:569\nmsgid \"Pan image\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:585\nmsgid \"6%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:585\nmsgid \"Zoom to 6%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:587\nmsgid \"12%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:587\nmsgid \"Zoom to 12%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:589\nmsgid \"25%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:589\nmsgid \"Zoom to 25%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:591\nmsgid \"50%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:591\nmsgid \"Zoom to 50%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:593\nmsgid \"100%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:595\nmsgid \"200%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:595\nmsgid \"Zoom to 200%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:597\nmsgid \"400%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:597\nmsgid \"Zoom to 400%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:599\nmsgid \"800%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:599\nmsgid \"Zoom to 800%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:601\nmsgid \"1600%\"\nmsgstr \"Malkovich\"\n\n#: src/imageview.c:601\nmsgid \"Zoom to 1600%\"\nmsgstr \"Malkovich\"\n\n#: src/colour.c:261\n#, fuzzy, c-format\nmsgid \"Edit Color \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/colour.c:267\nmsgid \"Set Color\"\nmsgstr \"Malkovich\"\n\n#: src/colour.c:299\n#, fuzzy\nmsgid \"Color Space\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:169\nmsgid \"Compatibility mode.\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:170\n#, fuzzy, c-format\nmsgid \"\"\n\"This workspace was created by version %d.%d.%d. A set of compatibility menus \"\n\"have been loaded for this window.\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:342\nmsgid \"No temp area\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:348\n#, fuzzy, c-format\nmsgid \"%s free\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:361\n#, fuzzy, c-format\nmsgid \"%d cells free\"\nmsgstr \"Malkovich\"\n\n#. Display select message instead.\n#.\n#: src/mainw.c:376\nmsgid \"Selected:\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:406\nmsgid \"compatibility mode\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:415\n#, fuzzy\nmsgid \"unsaved workspace\"\nmsgstr \"Malkovich\"\n\n#. Expands to (eg.) \"14GB free in /pics/tmp\"\n#: src/mainw.c:596\n#, fuzzy, c-format\nmsgid \" in \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:600\n#, fuzzy, c-format\nmsgid \"%d cells in heap, %d cells free, %d cells maximum\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:604\n#, fuzzy, c-format\nmsgid \"%d objects in workspace\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:608\n#, fuzzy, c-format\nmsgid \"%d vips calls cached\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:740\nmsgid \"Find in workspace not implemented yet.\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:748\nmsgid \"Find again in workspace not implemented yet.\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:783\nmsgid \"No errors.\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:784\nmsgid \"There are no errors (that I can see) in this workspace.\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:854\nmsgid \"Completely recalculate?\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:994 src/model.c:130 src/filemodel.c:452 src/filemodel.c:461\n#: src/filemodel.c:474\nmsgid \"Load failed.\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:995\n#, fuzzy, c-format\nmsgid \"\"\n\"Unable to execute:\\n\"\n\"   %s\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1012 src/mainw.c:1045\nmsgid \"Open File\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1159\nmsgid \"Recent Images\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1167\nmsgid \"Recent Workspaces\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1175\nmsgid \"Recent Matricies\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1184\nmsgid \"No recent items\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1190\nmsgid \"Clear Recent Menu\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1250\n#, fuzzy\nmsgid \"Merge Workspace from File\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1334 src/mainw.c:1372 src/program.c:596 src/program.c:625\n#: src/program.c:1052 src/program.c:1093 src/program.c:1139 src/program.c:1171\n#: src/program.c:1500 src/program.c:1541 src/program.c:2224 src/row.c:479\n#: src/workspacegroup.c:177 src/workspacegroup.c:213 src/columnview.c:180\n#: src/columnview.c:241\nmsgid \"Name\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1372\n#, fuzzy\nmsgid \"Set column name here\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1374\n#, fuzzy\nmsgid \"Set column caption here\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1376\n#, fuzzy\nmsgid \"New Column\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1380\n#, fuzzy\nmsgid \"Create Column\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1519\nmsgid \"Revert to Defaults\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1520\nmsgid \"Revert to installation defaults?\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1521\nmsgid \"\"\n\"Would you like to reset all preferences to their factory settings? This will \"\n\"delete any changes you have ever made to your preferences and may take a few \"\n\"seconds.\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1538\nmsgid \"Preferences\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1543\n#, fuzzy\nmsgid \"Revert to Defaults ...\"\nmsgstr \"Malkovich\"\n\n#. Menu items.\n#.\n#: src/mainw.c:1595\nmsgid \"_File\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1596\nmsgid \"_New\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1597\nmsgid \"Open _Recent\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1598 src/mainw.c:1722 src/regionview.c:1023 src/program.c:727\n#: src/rowview.c:586\nmsgid \"_Edit\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1599 src/mainw.c:2085\nmsgid \"Jump to _Column\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1600\nmsgid \"_View\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1601\nmsgid \"_Toolkits\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1602\nmsgid \"_Help\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1612 src/mainw.c:2082\nmsgid \"New C_olumn\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1613\nmsgid \"Create a new column\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1617\n#, fuzzy\nmsgid \"New Named C_olumn\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1618\n#, fuzzy\nmsgid \"Create a new column with a specified name\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1622 src/program.c:1670\nmsgid \"New _Workspace\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1623\nmsgid \"Create a new workspace\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1627\nmsgid \"_Open\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1628\nmsgid \"Open a file\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1632\nmsgid \"Open _Examples\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1633\nmsgid \"Open example workspaces\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1637\nmsgid \"_Duplicate Workspace\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1638\nmsgid \"Duplicate workspace\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1642\nmsgid \"_Merge Workspace\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1643\nmsgid \"Merge workspace into this workspace\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1647\nmsgid \"_Save Workspace\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1648\nmsgid \"Save workspace\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1652\nmsgid \"_Save Workspace As\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1653\nmsgid \"Save workspace as\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1657\n#, fuzzy\nmsgid \"Search for Workspace _Backups\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1658\nmsgid \"Load last automatically backed-up workspace\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1663\nmsgid \"Close workspace\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1667 src/program.c:1720\nmsgid \"_Delete\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1668\nmsgid \"Delete selected items\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1672 src/program.c:1725 src/columnview.c:896\nmsgid \"Select _All\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1673\nmsgid \"Select all items\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1677\nmsgid \"D_uplicate Selected\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1678\nmsgid \"Duplicate selected items\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1682 src/rowview.c:596\nmsgid \"_Recalculate\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1683\nmsgid \"Recalculate selected items\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1687 src/mainw.c:2086\nmsgid \"Align _Columns\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1688\nmsgid \"Align columns to grid\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1692 src/program.c:1745\nmsgid \"_Find\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1693\nmsgid \"Find in workspace\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1697 src/program.c:1750\nmsgid \"Find _Next\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1698\nmsgid \"Find again in workspace\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1703\nmsgid \"Jump to next error\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1707\nmsgid \"_Group\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1708\nmsgid \"Group selected items\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1712 src/rowview.c:590\nmsgid \"U_ngroup\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1713\nmsgid \"Ungroup selected items\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1717\nmsgid \"_Preferences\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1718\nmsgid \"Edit preferences\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1723\nmsgid \"Edit toolkits\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1737\nmsgid \"_Website\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1738\nmsgid \"Open the VIPS Homepage\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1744\nmsgid \"Au_to Recalculate\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1745\nmsgid \"Recalculate automatically on change\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1749\nmsgid \"_Toolbar\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1750\nmsgid \"Show window toolbar\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1754\nmsgid \"_Statusbar\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1755\nmsgid \"Show window statusbar\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1759\nmsgid \"Toolkit _Browser\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1760\nmsgid \"Show toolkit browser\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1764\n#, fuzzy\nmsgid \"Workspace _Definitions\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1765\n#, fuzzy\nmsgid \"Show workspace definitions\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1771\nmsgid \"_Normal\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1772\nmsgid \"Normal view mode\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1776\nmsgid \"Show _Formula\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1777\nmsgid \"Show formula view mode\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1781\nmsgid \"No _Edits\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:1782\nmsgid \"No edits view mode\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:2081\n#, fuzzy\nmsgid \"Workspace menu\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:2091\n#, fuzzy\nmsgid \"_Merge Workspace from File\"\nmsgstr \"Malkovich\"\n\n#: src/mainw.c:2094\n#, fuzzy\nmsgid \"_Group Selected\"\nmsgstr \"Malkovich\"\n\n#. Toolkit Browser pane.\n#.\n#: src/mainw.c:2103\n#, fuzzy\nmsgid \"Toolkit Browser\"\nmsgstr \"Malkovich\"\n\n#. Workspace-local defs pane.\n#.\n#: src/mainw.c:2122\n#, fuzzy\nmsgid \"Workspace Definitions\"\nmsgstr \"Malkovich\"\n\n#. Probably failed to load prefs on startup for some reason.\n#.\n#: src/prefs.c:207\nmsgid \"Unable to display preferences.\"\nmsgstr \"Malkovich\"\n\n#: src/prefs.c:208\n#, fuzzy, c-format\nmsgid \"\"\n\"No preferences workspace was found. Preferences probably failed to load when \"\n\"%s started.\"\nmsgstr \"Malkovich\"\n\n#: src/regionview.c:942 src/rowview.c:302\nmsgid \"Can't duplicate.\"\nmsgstr \"Malkovich\"\n\n#: src/regionview.c:944\nmsgid \"You can only duplicate top level regions.\"\nmsgstr \"Malkovich\"\n\n#: src/regionview.c:986\nmsgid \"Can't delete.\"\nmsgstr \"Malkovich\"\n\n#: src/regionview.c:987\nmsgid \"You can only delete top level regions.\"\nmsgstr \"Malkovich\"\n\n#: src/regionview.c:996\nmsgid \"Delete Region?\"\nmsgstr \"Malkovich\"\n\n#: src/regionview.c:997\n#, fuzzy, c-format\nmsgid \"Are you sure you want to delete Region \\\"%s\\\"?\"\nmsgstr \"Malkovich\"\n\n#. Other init.\n#.\n#: src/regionview.c:1022\nmsgid \"Region menu\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:73\nmsgid \"Edit window\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:597 src/program.c:627 src/program.c:1140 src/program.c:1173\n#: src/matrix.c:269 src/columnview.c:182 src/columnview.c:245\nmsgid \"Filename\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:625\nmsgid \"Menu item text\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:628\nmsgid \"Load column from this file\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:630\n#, fuzzy, c-format\nmsgid \"Edit Column Item \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:635\nmsgid \"Set column item\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:656 src/program.c:662\nmsgid \"Unable to save.\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:657\nmsgid \"You can only save toolkits, not tools.\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:663\nmsgid \"You can't save auto-generated toolkits.\"\nmsgstr \"Malkovich\"\n\n#. Create signals.\n#.\n#. Init methods.\n#.\n#: src/program.c:726\nmsgid \"Toolkit menu\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1093\nmsgid \"Set toolkit name here\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1095\nmsgid \"Set toolkit caption here\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1096\nmsgid \"New Toolkit\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1100 src/program.c:1178\nmsgid \"Create\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1111\nmsgid \"Nothing selected.\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1112\nmsgid \"No toolkit selected.\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1171\nmsgid \"Display this name\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1173\nmsgid \"Load this file\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1241\nmsgid \"Load Definition\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1295\nmsgid \"Reload\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1296\nmsgid \"Reload startup objects?\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1297\nmsgid \"\"\n\"Would you like to reload all startup menus, workspaces and plugins now? This \"\n\"may take a few seconds.\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1379\nmsgid \"No tool selected\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1422\nmsgid \"Bad regular expression.\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1441\n#, fuzzy, c-format\nmsgid \"No match found for \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1454\nmsgid \"Find in all Toolkits\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1464\nmsgid \"Enter search string here\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1512\n#, fuzzy, c-format\nmsgid \"No top-level symbol called \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1520\n#, fuzzy, c-format\nmsgid \"Symbol \\\"%s\\\" has no tool inforation.\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1541\nmsgid \"Go to definition of this symbol\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1543\nmsgid \"Go to Definition\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1573\nmsgid \"Object information.\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1624\nmsgid \"No documentation available.\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1625\nmsgid \"\"\n\"On-line documentation is only currently available for VIPS functions and nip \"\n\"builtins.\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1645\nmsgid \"New _Tool\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1646\nmsgid \"Make a new tool\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1650\nmsgid \"New Tool_kit\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1651\nmsgid \"Make a new toolkit\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1655\nmsgid \"New _Separator\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1656\nmsgid \"Make a new separator\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1660\nmsgid \"New _Column Item\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1661\nmsgid \"Make a new column item\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1665\nmsgid \"New _Program Window\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1666\nmsgid \"Make a new program window\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1671\nmsgid \"Make a new workspace\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1675\nmsgid \"_Open Toolkit\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1676\nmsgid \"_Open toolkit\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1680\nmsgid \"Save Toolkit\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1681\nmsgid \"_Save toolkit\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1685\nmsgid \"Save Toolkit _As\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1686\nmsgid \"Save toolkit as\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1690\nmsgid \"_Process\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1691\nmsgid \"Process text\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1695\nmsgid \"_Reload Start Stuff\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1696\nmsgid \"Remove and reload all startup data\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1705\nmsgid \"C_ut\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1706\nmsgid \"Cut selected text\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1710\nmsgid \"_Copy\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1711\nmsgid \"Copy selected text\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1715\nmsgid \"_Paste\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1716\nmsgid \"Paste selected text\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1721\nmsgid \"Delete selected text\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1726\nmsgid \"Select all text\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1730\nmsgid \"Dese_lect All\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1731\nmsgid \"Deselect all text\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1735\nmsgid \"Delete _Tool\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1736\nmsgid \"Delete current tool\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1740\nmsgid \"Delete Tool_kit\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1741\nmsgid \"Delete current toolkit\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1746\nmsgid \"Find text in toolkits\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1751\nmsgid \"Find text again\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1755\nmsgid \"_Jump To Definition\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1756\nmsgid \"Jump to definition\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1760\nmsgid \"_Info\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1761\nmsgid \"Info on selected object\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1765\nmsgid \"_Trace\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1766\nmsgid \"Make a new trace window\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1770\nmsgid \"_Errors\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1771\nmsgid \"Show all errors\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1785\nmsgid \"Help on _Tool\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:1786\nmsgid \"View docs for this tool\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:2028\nmsgid \"Bad drag.\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:2030\nmsgid \"\"\n\"Sorry, you can only drag tools between toolkits. You can't reorder toolkits, \"\n\"you can't nest toolkits and you can't drag tools to the top level.\"\nmsgstr \"Malkovich\"\n\n#: src/program.c:2219\nmsgid \"Tool\"\nmsgstr \"Malkovich\"\n\n#: src/itext.c:67\nmsgid \"Formula\"\nmsgstr \"Malkovich\"\n\n#: src/itext.c:184 src/itext.c:325\nmsgid \"no value\"\nmsgstr \"Malkovich\"\n\n#: src/itext.c:503 src/itext.c:536\nmsgid \"Dirty value\"\nmsgstr \"Malkovich\"\n\n#: src/model.c:131\n#, fuzzy, c-format\nmsgid \"\"\n\"Unable to load from file \\\"%s\\\". Error log is:\\n\"\n\"%s\"\nmsgstr \"Malkovich\"\n\n#: src/model.c:314 src/model.c:369 src/model.c:388 src/filemodel.c:101\n#: src/filemodel.c:131 src/filemodel.c:567 src/filemodel.c:608\n#, fuzzy, c-format\nmsgid \"_%s() not implemented for class \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: src/model.c:419 src/filemodel.c:255 src/filemodel.c:270\nmsgid \"XML library error.\"\nmsgstr \"Malkovich\"\n\n#: src/model.c:420\nmsgid \"model_save: xmlNewChild() failed\"\nmsgstr \"Malkovich\"\n\n#: src/model.c:477\nmsgid \"XML load error.\"\nmsgstr \"Malkovich\"\n\n#: src/model.c:478\n#, fuzzy, c-format\nmsgid \"Can't load node of type \\\"%s\\\" into object of type \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/model.c:693\nmsgid \"Delete?\"\nmsgstr \"Malkovich\"\n\n#: src/model.c:694\n#, fuzzy, c-format\nmsgid \"Are you sure you want to delete %s \\\"%s\\\"?\"\nmsgstr \"Malkovich\"\n\n#: src/panechild.c:108\n#, fuzzy\nmsgid \"Close the pane\"\nmsgstr \"Malkovich\"\n\n#: src/imageinfo.c:679\n#, fuzzy\nmsgid \"User cancelled operation\"\nmsgstr \"Malkovich\"\n\n#: src/imageinfo.c:979\nmsgid \"Unable to open image.\"\nmsgstr \"Malkovich\"\n\n#: src/imageinfo.c:980\n#, fuzzy, c-format\nmsgid \"Unable to open file \\\"%s\\\" as image.\"\nmsgstr \"Malkovich\"\n\n#: src/imageinfo.c:1110 src/imageinfo.c:1118\nmsgid \"Unable to write to file.\"\nmsgstr \"Malkovich\"\n\n#: src/imageinfo.c:1111\n#, fuzzy, c-format\nmsgid \"File \\\"%s\\\" is already open for read.\"\nmsgstr \"Malkovich\"\n\n#: src/imageinfo.c:1119\n#, fuzzy, c-format\nmsgid \"Error writing image to file \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: src/imageinfo.c:1135\nmsgid \"Unable to paint on image.\"\nmsgstr \"Malkovich\"\n\n#: src/imageinfo.c:1136\n#, fuzzy, c-format\nmsgid \"\"\n\"Unable to get write permission for file \\\"%s\\\".\\n\"\n\"Check permission settings.\"\nmsgstr \"Malkovich\"\n\n#: src/imageinfo.c:1180\nmsgid \"Modify\"\nmsgstr \"Malkovich\"\n\n#: src/imageinfo.c:1181\nmsgid \"Modify disc file?\"\nmsgstr \"Malkovich\"\n\n#: src/imageinfo.c:1182\n#, fuzzy, c-format\nmsgid \"\"\n\"This image is being shown directly from the disc file:\\n\"\n\"\\n\"\n\"   %s\\n\"\n\"\\n\"\n\"If you paint on this file, it will be permanently changed. If something goes \"\n\"wrong, you may lose work. Are you sure you want to modify this file?\"\nmsgstr \"Malkovich\"\n\n#: src/imageinfo.c:1883\nmsgid \"Unable to paint text.\"\nmsgstr \"Malkovich\"\n\n#: src/imageinfo.c:1884\n#, fuzzy, c-format\nmsgid \"Unable to paint text \\\"%s\\\" in font \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: src/row.c:287\nmsgid \"Error in row.\"\nmsgstr \"Malkovich\"\n\n#. Elements are name of row, principal error,\n#. * secondary error.\n#.\n#: src/row.c:291\n#, fuzzy, c-format\nmsgid \"\"\n\"Error in row %s: %s\\n\"\n\"%s\"\nmsgstr \"Malkovich\"\n\n#. Expands to eg. \"B1 refers to: B2, B3\".\n#.\n#: src/row.c:496\nmsgid \"refers to\"\nmsgstr \"Malkovich\"\n\n#. Expands to eg. \"B1 is referred to by: B2, B3\".\n#.\n#: src/row.c:507\nmsgid \"is referred to by\"\nmsgstr \"Malkovich\"\n\n#: src/row.c:520\nmsgid \"is blocked on\"\nmsgstr \"Malkovich\"\n\n#: src/error.c:60\n#, fuzzy\nmsgid \"No ierrors found.\"\nmsgstr \"Malkovich\"\n\n#: src/error.c:100\nmsgid \"No unresolved symbols found.\"\nmsgstr \"Malkovich\"\n\n#: src/error.c:124\n#, fuzzy\nmsgid \"Clear ierror window\"\nmsgstr \"Malkovich\"\n\n#: src/error.c:128\n#, fuzzy\nmsgid \"List _iErrors\"\nmsgstr \"Malkovich\"\n\n#: src/error.c:129\n#, fuzzy\nmsgid \"Search for all ierrors\"\nmsgstr \"Malkovich\"\n\n#: src/error.c:133\nmsgid \"List _Unresolved\"\nmsgstr \"\"\n\n#: src/error.c:134\nmsgid \"Search for all unresolved references\"\nmsgstr \"\"\n\n#: src/error.c:139\n#, fuzzy\nmsgid \"Close ierror window\"\nmsgstr \"Malkovich\"\n\n#: src/error.c:222\n#, fuzzy, c-format\nmsgid \"iError - %s\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:156\nmsgid \"No objects selected.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:157 src/workspace.c:162\nmsgid \"Select exactly one object and try again.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:161\nmsgid \"More than one object selected.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:493\n#, fuzzy\nmsgid \"File does not exist.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:494\n#, fuzzy, c-format\nmsgid \"File \\\"%s\\\" cannot be read.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:776 src/workspace.c:784\nmsgid \"No backup workspaces found.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:778\nmsgid \"\"\n\"You need to enable \\\"Auto workspace save\\\" in Preferences before automatic \"\n\"recovery works.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:785\n#, fuzzy, c-format\nmsgid \"No suitable workspace save files found in \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:801\nmsgid \"Open workspace backup?\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:802\n#, fuzzy, c-format\nmsgid \"\"\n\"Found workspace \\\"%s\\\", dated %s. Do you want to recover this workspace?\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1220\nmsgid \"Version mismatch.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1221\n#, fuzzy, c-format\nmsgid \"\"\n\"File \\\"%s\\\" was saved from %s-%d.%d.%d. You may see compatibility problems.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1378\n#, fuzzy\nmsgid \"// private definitions for this workspace\\n\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1422 src/workspacegroup.c:145 src/tool.c:869\n#: src/column.c:326\nmsgid \"Name clash.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1423\n#, fuzzy, c-format\nmsgid \"Can't create workspace \\\"%s\\\". A symbol with that name already exists.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1514\nmsgid \"Default empty workspace\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1586 src/class.c:795\nmsgid \"Wrong number of arguments.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1587\n#, fuzzy, c-format\nmsgid \"%s needs %d arguments, there are %d selected.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1598\nmsgid \"Too many names selected.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1738\nmsgid \"You can only remove top level rows.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1739\nmsgid \"Not all selected objects are top level rows.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1789\nmsgid \"Delete selected objects?\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1790\n#, fuzzy, c-format\nmsgid \"Are you sure you want to delete %s?\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1848\nmsgid \"Unable to ungroup.\"\nmsgstr \"Malkovich\"\n\n#: src/workspace.c:1849\n#, fuzzy, c-format\nmsgid \"Row \\\"%s\\\" is not a Group or a list.\"\nmsgstr \"Malkovich\"\n\n#: src/iimage.c:115\nmsgid \"Original filename\"\nmsgstr \"Malkovich\"\n\n#: src/iimage.c:338\nmsgid \"Save timer.\"\nmsgstr \"Malkovich\"\n\n#: src/iimage.c:339\n#, fuzzy, c-format\nmsgid \"Image save took %g seconds.\"\nmsgstr \"Malkovich\"\n\n#: src/tslider.c:369\nmsgid \"Slider value ... edit!\"\nmsgstr \"Malkovich\"\n\n#: src/tslider.c:390\nmsgid \"Left-drag to set number\"\nmsgstr \"Malkovich\"\n\n#: src/path.c:279\n#, fuzzy, c-format\nmsgid \"File \\\"%s\\\" not found.\"\nmsgstr \"Malkovich\"\n\n#: src/path.c:306\n#, fuzzy, c-format\nmsgid \"File \\\"%s\\\" not found on path\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:252\nmsgid \"Close _without Saving\"\nmsgstr \"Malkovich\"\n\n#. Translators: translate this to a credit for you, and it'll appear in\n#. * the About box.\n#.\n#: src/boxes.c:271\nmsgid \"translator_credits\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:280\n#, fuzzy, c-format\nmsgid \"About %s.\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:283\n#, fuzzy, c-format\nmsgid \"%s is an image processing package.\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:287\n#, fuzzy, c-format\nmsgid \"\"\n\"%s comes with ABSOLUTELY NO WARRANTY. This is free software and you are \"\n\"welcome to redistribute it under certain conditions, see http://www.gnu.org.\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:306\n#, fuzzy\nmsgid \"Personal start folder\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:310\n#, fuzzy\nmsgid \"Homepage\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:313\n#, fuzzy\nmsgid \"Linked to VIPS\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:316\n#, fuzzy\nmsgid \"Built against VIPS\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:329\n#, fuzzy\nmsgid \"Temp files in\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:395\nmsgid \"Help page not found.\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:396\n#, fuzzy, c-format\nmsgid \"No indexed help page found for tag \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:605\nmsgid \"Search for\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:606\nmsgid \"Case sensitive\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:608\nmsgid \"Regular expression\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:610\nmsgid \"Search from start\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:810\nmsgid \"Image header fields\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:826\nmsgid \"Image history\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:942 src/boxes.c:953 src/boxes.c:982\n#, fuzzy\nmsgid \"Unable to view help file.\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:943\n#, fuzzy, c-format\nmsgid \"Unable to open URL \\\"%s\\\", windows error code = %d.\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:954\n#, c-format\nmsgid \"\"\n\"Attempt to view URL with xdg-open failed\\n\"\n\"%s\"\nmsgstr \"\"\n\n#: src/boxes.c:959 src/boxes.c:991\nmsgid \"Browser window opened.\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:961 src/boxes.c:993\n#, fuzzy\nmsgid \"You may need to switch desktops to see the new window.\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:984\n#, fuzzy, c-format\nmsgid \"\"\n\"Attempted to launch browser with command:\\n\"\n\"  %s\\n\"\n\"You can change this command in Preferences.\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:1084\n#, fuzzy, c-format\nmsgid \"Version %s\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:1097\n#, fuzzy\nmsgid \"Starting ...\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:1105\nmsgid \"Display this splash screen during startup\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:1174\nmsgid \"Select Font\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:1232\nmsgid \"Font not found.\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:1233\n#, fuzzy, c-format\nmsgid \"Font \\\"%s\\\" not found on system.\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:1313\nmsgid \"Pick a font\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:1318\nmsgid \"Set Font\"\nmsgstr \"Malkovich\"\n\n#: src/boxes.c:1364\nmsgid \"Click to select font\"\nmsgstr \"Malkovich\"\n\n#: src/spin.c:223\nmsgid \"Expand or collapse row\"\nmsgstr \"Malkovich\"\n\n#: src/filemodel.c:256\nmsgid \"model_save_filename: xmlNewDoc() failed\"\nmsgstr \"Malkovich\"\n\n#: src/filemodel.c:271\nmsgid \"model_save_filename: xmlNewDocNode() failed\"\nmsgstr \"Malkovich\"\n\n#: src/filemodel.c:287\nmsgid \"Save failed.\"\nmsgstr \"Malkovich\"\n\n#: src/filemodel.c:288\n#, fuzzy, c-format\nmsgid \"\"\n\"Save of %s \\\"%s\\\" to file \\\"%s\\\" failed.\\n\"\n\"%s\"\nmsgstr \"Malkovich\"\n\n#: src/filemodel.c:343\nmsgid \"filemodel_real_save_all: no save method\"\nmsgstr \"Malkovich\"\n\n#: src/filemodel.c:453\n#, fuzzy, c-format\nmsgid \"Can't load XML file \\\"%s\\\", it's not a %s save file.\"\nmsgstr \"Malkovich\"\n\n#: src/filemodel.c:462\n#, fuzzy, c-format\nmsgid \"\"\n\"Can't load XML file \\\"%s\\\", unable to extract version information from \"\n\"namespace.\"\nmsgstr \"Malkovich\"\n\n#: src/filemodel.c:475\n#, fuzzy, c-format\nmsgid \"Can't load XML file \\\"%s\\\", the file does not contain a %s.\"\nmsgstr \"Malkovich\"\n\n#. Expands to (eg.) \"Save Column A2\".\n#.\n#: src/filemodel.c:660\n#, fuzzy, c-format\nmsgid \"Save %s %s\"\nmsgstr \"Malkovich\"\n\n#: src/filemodel.c:736 src/filemodel.c:748\nmsgid \"Object has been modified.\"\nmsgstr \"Malkovich\"\n\n#: src/filemodel.c:737\n#, fuzzy, c-format\nmsgid \"\"\n\"%s \\\"%s\\\" has been modified since you loaded it from file \\\"%s\\\".\\n\"\n\"\\n\"\n\"Do you want to save your changes?\"\nmsgstr \"Malkovich\"\n\n#: src/filemodel.c:749\n#, fuzzy, c-format\nmsgid \"%s \\\"%s\\\" has been modified. Do you want to save your changes?\"\nmsgstr \"Malkovich\"\n\n#: src/workspacegroup.c:146\n#, fuzzy, c-format\nmsgid \"\"\n\"Can't create workspacegroup \\\"%s\\\". A symbol with that name already exists.\"\nmsgstr \"Malkovich\"\n\n#: src/workspacegroup.c:213\nmsgid \"Set workspace name here\"\nmsgstr \"Malkovich\"\n\n#: src/workspacegroup.c:215\nmsgid \"Set workspace caption here\"\nmsgstr \"Malkovich\"\n\n#: src/workspacegroup.c:217\nmsgid \"New Workspace\"\nmsgstr \"Malkovich\"\n\n#: src/workspacegroup.c:221\nmsgid \"Create Workspace\"\nmsgstr \"Malkovich\"\n\n#: src/matrix.c:148\nmsgid \"Sliders\"\nmsgstr \"Malkovich\"\n\n#: src/matrix.c:149\nmsgid \"Toggle buttons\"\nmsgstr \"Malkovich\"\n\n#: src/matrix.c:150\nmsgid \"Text, plus scale and offset\"\nmsgstr \"Malkovich\"\n\n#: src/matrix.c:161\nmsgid \"Display as\"\nmsgstr \"Malkovich\"\n\n#: src/matrix.c:192\n#, fuzzy, c-format\nmsgid \"Edit Matrix \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/matrix.c:197\nmsgid \"Set Matrix\"\nmsgstr \"Malkovich\"\n\n#: src/matrix.c:272\nmsgid \"Display\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:133\n#, fuzzy, c-format\nmsgid \"Save Column \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:181 src/columnview.c:243\nmsgid \"Toolkit\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:241\nmsgid \"Set menu item text here\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:243\nmsgid \"Add to this toolkit\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:245\nmsgid \"Store column in this file\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:248\n#, fuzzy, c-format\nmsgid \"New Menu Item from Column \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:253\nmsgid \"Menuize\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:648\nmsgid \"Edit caption, press enter to accept changes, press escape to cancel\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:701\nmsgid \"Enter expressions here\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:755\nmsgid \"doubleclick to set title\"\nmsgstr \"\"\n\n#: src/columnview.c:764\nmsgid \"Fold the column away\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:769\nmsgid \"Open the column\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:893\nmsgid \"Column menu\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:894\nmsgid \"_Edit Caption\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:903\nmsgid \"Make Column Into _Menu Item\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:940\nmsgid \"Left-drag to move, left-double-click to set title, right-click for menu\"\nmsgstr \"Malkovich\"\n\n#: src/columnview.c:973\nmsgid \"Delete the column\"\nmsgstr \"Malkovich\"\n\n#. used as in \"fred refers to undefined symbol jim\"\n#.\n#: src/tool.c:77\nmsgid \"refers to undefined symbol\"\nmsgstr \"Malkovich\"\n\n#: src/tool.c:870\n#, fuzzy, c-format\nmsgid \"\"\n\"Can't create dialog with name \\\"%s\\\", an object with that name already \"\n\"exists in kit \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: src/compile.c:1449\nmsgid \"Too many shared nodes in graph.\"\nmsgstr \"Malkovich\"\n\n#: src/compile.c:1451\nmsgid \"Raise MAX_RELOC\"\nmsgstr \"Malkovich\"\n\n#: src/compile.c:1768\n#, fuzzy, c-format\nmsgid \"Member \\\"%s\\\" of class \\\"%s\\\" should have no arguments.\"\nmsgstr \"Malkovich\"\n\n#: src/compile.c:2645\n#, fuzzy\nmsgid \"pattern match failed\"\nmsgstr \"Malkovich\"\n\n#: src/idialog.c:432\nmsgid \"Pin up\"\nmsgstr \"Malkovich\"\n\n#: src/idialog.c:434\nmsgid \"Check this to pin the dialog up\"\nmsgstr \"Malkovich\"\n\n#: src/link.c:578\nmsgid \"Circular dependency.\"\nmsgstr \"Malkovich\"\n\n#: src/link.c:579\n#, fuzzy, c-format\nmsgid \"Circular dependency detected near symbol \\\"%s\\\".\"\nmsgstr \"Malkovich\"\n\n#: src/colourdisplay.c:259\nmsgid \"Double-click to edit this color, or drag-and-drop between colors\"\nmsgstr \"Malkovich\"\n\n#: src/toolkitgroup.c:139\n#, fuzzy, c-format\nmsgid \"Toolkits for %s\"\nmsgstr \"Malkovich\"\n\n#: src/dump.c:187\nmsgid \"parameter\"\nmsgstr \"Malkovich\"\n\n#: src/dump.c:188\nmsgid \"zombie\"\nmsgstr \"Malkovich\"\n\n#: src/dump.c:190\nmsgid \"workspace group\"\nmsgstr \"Malkovich\"\n\n#: src/dump.c:191\nmsgid \"root symbol\"\nmsgstr \"Malkovich\"\n\n#: src/dump.c:192\nmsgid \"external symbol\"\nmsgstr \"Malkovich\"\n\n#: src/dump.c:193\nmsgid \"built-in symbol\"\nmsgstr \"Malkovich\"\n\n#: src/column.c:327\n#, fuzzy, c-format\nmsgid \"Can't create column \\\"%s\\\". A column with that name already exists.\"\nmsgstr \"Malkovich\"\n\n#: src/column.c:364\nmsgid \"Empty column.\"\nmsgstr \"Malkovich\"\n\n#: src/column.c:365\nmsgid \"There are no objects in the current column.\"\nmsgstr \"Malkovich\"\n\n#: src/column.c:384\nmsgid \"Too few items.\"\nmsgstr \"Malkovich\"\n\n#: src/column.c:385\n#, fuzzy, c-format\nmsgid \"This column only has %d items, but %s needs %d items.\"\nmsgstr \"Malkovich\"\n\n#: src/class.c:50\n#, fuzzy, c-format\nmsgid \"Object %s is not a class.\"\nmsgstr \"Malkovich\"\n\n#: src/class.c:333\nmsgid \"No such secret.\"\nmsgstr \"Malkovich\"\n\n#: src/class.c:334\nmsgid \"\"\n\"Editing local classes which reference non-local objects is a bit broken at \"\n\"the moment :-(\"\nmsgstr \"Malkovich\"\n\n#: src/class.c:658\n#, fuzzy, c-format\nmsgid \"You can't have more than %d arguments to a superclass constructor.\"\nmsgstr \"Malkovich\"\n\n#: src/class.c:787 src/class.c:846\nmsgid \"Bad superclass.\"\nmsgstr \"Malkovich\"\n\n#: src/class.c:788\n#, fuzzy, c-format\nmsgid \"Superclass constructor \\\"%s\\\" should have no secret arguments.\"\nmsgstr \"Malkovich\"\n\n#: src/class.c:796\n#, fuzzy, c-format\nmsgid \"Superclass constructor \\\"%s\\\" expects %d arguments, not %d.\"\nmsgstr \"Malkovich\"\n\n#: src/class.c:850\n#, fuzzy, c-format\nmsgid \"First element in superclass of \\\"%s\\\" must be class or constructor.\"\nmsgstr \"Malkovich\"\n\n#: src/class.c:882 src/class.c:979\n#, fuzzy, c-format\nmsgid \"\"\n\"Too many arguments to class constructor \\\"%s\\\". No more than %d arguments \"\n\"are supported.\"\nmsgstr \"Malkovich\"\n\n#: src/class.c:972\nmsgid \"Class not found.\"\nmsgstr \"Malkovich\"\n\n#: src/class.c:973\n#, fuzzy, c-format\nmsgid \"Class \\\"%s\\\" not found.\"\nmsgstr \"Malkovich\"\n\n#: src/class.c:1010\n#, fuzzy, c-format\nmsgid \"Member \\\"%s\\\" of class \\\"%s\\\" should be of type \\\"%s\\\", instead it's:\"\nmsgstr \"Malkovich\"\n\n#: src/plot.c:80\nmsgid \"YYYY\"\nmsgstr \"\"\n\n#: src/plot.c:81\nmsgid \"XYYY\"\nmsgstr \"\"\n\n#: src/plot.c:82\nmsgid \"XYXY\"\nmsgstr \"\"\n\n#: src/plot.c:93\n#, fuzzy\nmsgid \"Point\"\nmsgstr \"Malkovich\"\n\n#: src/plot.c:95\n#, fuzzy\nmsgid \"Spline\"\nmsgstr \"Malkovich\"\n\n#: src/plot.c:96\nmsgid \"Bar\"\nmsgstr \"\"\n\n#: src/plot.c:141\nmsgid \"More than one column needed or XY plots\"\nmsgstr \"\"\n\n#: src/plot.c:151\nmsgid \"Even number of columns only for XY format plots\"\nmsgstr \"\"\n\n#: src/plot.c:316\n#, fuzzy\nmsgid \"Format\"\nmsgstr \"Malkovich\"\n\n#: src/plot.c:319\n#, fuzzy\nmsgid \"Style\"\nmsgstr \"Malkovich\"\n\n#: src/plot.c:322\nmsgid \"Xmin\"\nmsgstr \"\"\n\n#: src/plot.c:325\nmsgid \"Xmax\"\nmsgstr \"\"\n\n#: src/plot.c:328\nmsgid \"Ymin\"\nmsgstr \"\"\n\n#: src/plot.c:331\nmsgid \"Ymax\"\nmsgstr \"\"\n\n#: src/plot.c:337\nmsgid \"Options\"\nmsgstr \"Malkovich\"\n\n#: src/plot.c:361\nmsgid \"1xn or nx1 images only for Plot\"\nmsgstr \"\"\n\n#: src/plot.c:380\n#, fuzzy\nmsgid \"Unable to prepare image.\"\nmsgstr \"Malkovich\"\n\n#: src/plot.c:393\nmsgid \"1xn or nx1 images only\"\nmsgstr \"\"\n\n#: src/rowview.c:304\nmsgid \"You can only duplicate top level rows.\"\nmsgstr \"Malkovich\"\n\n#: src/rowview.c:457\nmsgid \"Drag between columns not yet implemented.\"\nmsgstr \"Malkovich\"\n\n#. Other init.\n#.\n#: src/rowview.c:585\nmsgid \"Row menu\"\nmsgstr \"Malkovich\"\n\n#: src/rowview.c:598\nmsgid \"Re_set\"\nmsgstr \"Malkovich\"\n\n#: src/rowview.c:664\nmsgid \"Click to open or close class\"\nmsgstr \"Malkovich\"\n\n#: src/iregion.c:166\n#, fuzzy, c-format\nmsgid \"at (%d, %d), size (%d, %d)\"\nmsgstr \"Malkovich\"\n\n#: src/iregion.c:181 src/iregion.c:223\nmsgid \"Left\"\nmsgstr \"Malkovich\"\n\n#: src/iregion.c:182 src/iregion.c:226\nmsgid \"Top\"\nmsgstr \"Malkovich\"\n\n#: src/iregion.c:183 src/iregion.c:229\nmsgid \"Width\"\nmsgstr \"Malkovich\"\n\n#: src/iregion.c:184 src/iregion.c:232\nmsgid \"Height\"\nmsgstr \"Malkovich\"\n\n#: src/iregion.c:223\nmsgid \"Left edge of region\"\nmsgstr \"Malkovich\"\n\n#: src/iregion.c:226\nmsgid \"Top edge of region\"\nmsgstr \"Malkovich\"\n\n#: src/iregion.c:229\nmsgid \"Width of region\"\nmsgstr \"Malkovich\"\n\n#: src/iregion.c:232\nmsgid \"Height of region\"\nmsgstr \"Malkovich\"\n\n#: src/iregion.c:237\n#, fuzzy, c-format\nmsgid \"Edit \\\"%s\\\"\"\nmsgstr \"Malkovich\"\n\n#: src/iregion.c:241\nmsgid \"Set Region\"\nmsgstr \"Malkovich\"\n\n#~ msgid \"No match found.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Thumbnails\"\n#~ msgstr \"Malkovich\"\n\n#, fuzzy\n#~ msgid \"Image files found in: \\\"%s\\\"\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Searching ...\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Search incomplete!\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Show thumbnails\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Show thumbnails for files in this directory\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Stack overflow.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Spine stack overflow, runaway recursion?\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Frame stack overflow, expression too complex.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Stack underflow.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Frame stack underflow, you've found a bug!\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Spine stack underflow, you've found a bug!\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"No options.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"You need at least one option in your option list\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Set option caption here\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Set option default value here\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Edit Option\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Set Option\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Orderlist menu\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Delete _Selected\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Delete _All\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Current options - right button for menu\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Enter new option fields here\"\n#~ msgstr \"Malkovich\"\n\n#, fuzzy\n#~ msgid \"Zoom to fit plot to window\"\n#~ msgstr \"Malkovich\"\n\n#, fuzzy\n#~ msgid \"Bad regular expression \\\"%s\\\".\"\n#~ msgstr \"Malkovich\"\n\n#, fuzzy\n#~ msgid \"Loading toolkit \\\"%s\\\"\"\n#~ msgstr \"Malkovich\"\n\n#, fuzzy\n#~ msgid \"Loading workspace \\\"%s\\\"\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Loading plugins\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"First recalculation ...\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Final recalculation ...\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Building main window\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Initialising toolkit\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"GObject is not a VipsObject.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"VIPS8 error.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"VIPS8 not linked.\"\n#~ msgstr \"Malkovich\"\n\n#, fuzzy\n#~ msgid \"static string \\\"%s\\\"\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Re_cover After Crash\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"VIPS image files (*.v)\"\n#~ msgstr \"Malkovich\"\n\n#, fuzzy\n#~ msgid \"Unable to open \\\"%s\\\" for write.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Right hand side of '.' is not tag.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Unable to open location.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"\"\n#~ \"Opened window for URL:\\n\"\n#~ \"  %s\\n\"\n#~ \"This may take a few seconds.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Computing image.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"\"\n#~ \"Calculating all the pixels in an image. Press the Cancel button to stop \"\n#~ \"computation early.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"TIFF image files (*.tif, *.tiff)\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"JPEG image files (*.jpg, *.jpeg, *.jpe)\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"PNG image files (*.png)\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"PPM image files (*.ppm, *.pgm, *.pbm)\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"OpenEXR image files (*.exr)\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Analyze image files (*.img, *.hdr)\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"CSV files (*.csv)\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"from\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"No group\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"%s version: %s\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Calculating ...\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"\"\n#~ \"Unable to load from file \\\"%s\\\". Error loading as image, workspace or \"\n#~ \"matrix.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Edit _Toolkits\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"\"\n#~ \"unable to compile \\\"%s\\\"\\n\"\n#~ \"%s\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Program\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Link report.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Error report.\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"_Link\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Show a link report\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"defined in toolkit \\\"%s\\\"\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"line %d\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"tool \\\"%s\\\"\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"toolkit \\\"%s\\\"\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"TIFF image\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"JPEG image\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"PNG image\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"PPM/PGM/PBM image\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"OpenEXR image\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"Analyze image\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"libMagick-supported image\"\n#~ msgstr \"Malkovich\"\n\n#~ msgid \"VIPS image\"\n#~ msgstr \"Malkovich\"\n"
  },
  {
    "path": "proj/README",
    "content": "sample config and makefiles for building with the MSC toolchain\n\nexperts only, no support!\n"
  },
  {
    "path": "proj/src/makefile.msc",
    "content": "# autogenerated from automake.am with automake.py\r\nTOP = ..\\..\r\nPRJ_TOP = ..\r\nPACKAGE = nip\r\nPKG_VER = 7.8.6\r\n!INCLUDE $(TOP)\\glib\\build\\win32\\make.msc\r\n\r\n!IFDEF DEBUG\r\nLDFLAGS = $(LDFLAGS) /NODEFAULTLIB:msvcrt \r\n!ENDIF\r\n\r\ntop_srcdir = $(PRJ_TOP)\r\ntop_builddir = $(PRJ_TOP)\r\nincludedir = $(PRJ_TOP)\r\nLT_RELEASE = $(PKG_VER)\r\nSUBDIRS = # BITMAPS\r\n\r\nsub-all: \r\n\tfor %d in ($(SUBDIRS)) do nmake -nologo -f makefile.msc sub-one THIS=%d\r\n\r\nsub-one:\r\n\tcd $(THIS)\r\n\tnmake -nologo -f makefile.msc\r\n\tcd ..\r\n\r\nYACC = \\\r\n\t@YACC@ -d\r\n\r\nOBJECTS = \\\r\n\taction.obj \\\r\n\tasynch.obj \\\r\n\tboxes.obj \\\r\n\tbrowse.obj \\\r\n\tbuiltin.obj \\\r\n\tclass.obj \\\r\n\tcolourdisplay.obj \\\r\n\tcolumn.obj \\\r\n\tcolumnview.obj \\\r\n\tcommand.obj \\\r\n\tcompile.obj \\\r\n\tconversion.obj \\\r\n\tconversionview.obj \\\r\n\tdoubleclick.obj \\\r\n\tdump.obj \\\r\n\texpr.obj \\\r\n\tfilemodel.obj \\\r\n\tfilename.obj \\\r\n\tfilenameview.obj \\\r\n\tfilesel.obj \\\r\n\tgraph.obj \\\r\n\tgtkfilesel2.obj \\\r\n\tgtkmenubar2.obj \\\r\n\tgtkutil.obj \\\r\n\theap.obj \\\r\n\theapmodel.obj \\\r\n\tclassmodel.obj \\\r\n\tidialog.obj \\\r\n\tiimage.obj \\\r\n\tiimageview.obj \\\r\n\tiregionview.obj \\\r\n\tiregiongroup.obj \\\r\n\tiregiongroupview.obj \\\r\n\tregionview.obj \\\r\n\tiregion.obj \\\r\n\tiarrow.obj \\\r\n\tiarrowview.obj \\\r\n\timageinfo.obj \\\r\n\timagedisplay.obj \\\r\n\timagepresent.obj \\\r\n\timageview.obj \\\r\n\tiwindow.obj \\\r\n\tled.obj \\\r\n\tlink.obj \\\r\n\tmain.obj \\\r\n\tmainw.obj \\\r\n\tmatrix.obj \\\r\n\tmatrixview.obj \\\r\n\tmodel.obj \\\r\n\torderitem.obj \\\r\n\torderlist.obj \\\r\n\tpaintboxview.obj \\\r\n\tpath.obj \\\r\n\tpredicate.obj \\\r\n\twatch.obj \\\r\n\treduce.obj \\\r\n\trhs.obj \\\r\n\trhsview.obj \\\r\n\trow.obj \\\r\n\trowview.obj \\\r\n\tsecret.obj \\\r\n\tslider.obj \\\r\n\tcolour.obj \\\r\n\treal.obj \\\r\n\trealview.obj \\\r\n\toption.obj \\\r\n\ttslider.obj \\\r\n\toptionview.obj \\\r\n\tsliderview.obj \\\r\n\tcolourview.obj \\\r\n\tspin.obj \\\r\n\tstatusview.obj \\\r\n\tsubcolumn.obj \\\r\n\tsubcolumnview.obj \\\r\n\tsymbol.obj \\\r\n\ttable.obj \\\r\n\titext.obj \\\r\n\titextview.obj \\\r\n\ttoggle.obj \\\r\n\ttoggleview.obj \\\r\n\ttool.obj \\\r\n\ttoolkit.obj \\\r\n\ttoolkitgroup.obj \\\r\n\ttoolkitgroupview.obj \\\r\n\ttoolkitview.obj \\\r\n\ttoolview.obj \\\r\n\ttrace.obj \\\r\n\tprogram.obj \\\r\n\ttree.obj \\\r\n\tutil.obj \\\r\n\tview.obj \\\r\n\tvips_call.obj \\\r\n\twild.obj \\\r\n\tworkspace.obj \\\r\n\tworkspacegroup.obj \\\r\n\tworkspacegroupview.obj \\\r\n\tworkspaceview.obj \\\r\n\t\\\r\n\tlex.obj \\\r\n\tparse.obj \\\r\n\r\nADDONS = \\\r\n\t\\\r\n\tregex.obj \\\r\n\tfnmatch.obj\r\n\r\nregex.obj : regex.c regex.h\r\n\t$(CC) $(CFLAGS) -GD -c -DREGEX_MALLOC -DHAVE_STRING_H $(PKG_CFLAGS) regex.c\r\n\r\n$(PACKAGE).res : $(PACKAGE).rc $(PACKAGE).ico\r\n\trc -r -fo $(PACKAGE).res $(PACKAGE).rc\r\n\r\nRESOURCE = $(PACKAGE).res\r\n\r\nEXTRA_DIST = \\\r\n\tdoc\r\n\r\nLDADD = \\\r\n\t@IP_CFLAGS@ @IP_LIBS@\r\n\r\nCLEANFILES = \\\r\n\tparse.c \\\r\n\tparse.h \\\r\n\tlex.c \\\r\n\ttags\r\n\r\nINCLUDES = \\\r\n\t-FI msvc_recommended_pragmas.h \\\r\n\t-DIM_NO_VIPS7_COMPAT \\\r\n\t-I $(PRJ_TOP) -DHAVE_CONFIG_H -I. \\\r\n\t$(VIPS_CFLAGS) \\\r\n\t$(GTK_CFLAGS) -DGTK_ENABLE_BROKEN \\\r\n\t$(LIBXML2_CFLAGS) \\\r\n\t$(DIRENT_CFLAGS)\r\n\r\nPKG_LINK = \\\r\n\t$(VIPS_LIBS) \\\r\n\t$(GLIB_LIBS) $(GTK_LIBS) \\\r\n\t$(DIRENT_LIBS) \\\r\n\t$(LIBXML2_LIBS)\r\n\r\nall : \\\r\n\t$(PRJ_TOP)\\config.h \\\r\n\tsub-all \\\r\n\t$(PACKAGE).exe\r\n\r\n# bison --defines --output=parse d:\\devel\\my-gtk\\nip-7.8.6\\src\\parse.y\r\n\r\nlex.c : lex.l\r\n\tflex -olex.c lex.l\r\n\r\n$(PRJ_TOP)\\config.h: $(PRJ_TOP)\\config.h.win32\r\n\tcopy $(PRJ_TOP)\\config.h.win32 $(PRJ_TOP)\\config.h\r\n\r\nRESOURCE = $(PACKAGE).res\r\n\r\n$(PACKAGE).lib : $(OBJECTS)\r\n\tlib /out:$(PACKAGE).lib $(OBJECTS)\r\n\r\n$(PACKAGE)-$(PKG_VER).dll : $(OBJECTS) $(PACKAGE).def\r\n\t$(CC) $(CFLAGS) -LD -Fe$(PACKAGE)-$(PKG_VER).dll $(OBJECTS) $(PKG_LINK) user32.lib advapi32.lib wsock32.lib $(LDFLAGS) /def:$(PACKAGE).def\r\n\r\n$(PACKAGE).exe : $(OBJECTS) $(PACKAGE).res\r\n\t$(CC) $(CFLAGS) -Fe$(PACKAGE).exe $(PACKAGE).res $(OBJECTS) $(PKG_LINK) \\\r\n\tuser32.lib advapi32.lib shell32.lib wsock32.lib winspool.lib \\\r\n\t$(LDFLAGS)\r\n\r\n.c.obj :\r\n\t$(CC) $(CFLAGS) -GD -c $(PKG_CFLAGS) $<\r\n"
  },
  {
    "path": "proj/src/nip.rc",
    "content": "nip\tICON\t\"nip.ico\"\r\n"
  },
  {
    "path": "share/Makefile.am",
    "content": "SUBDIRS = nip2 \n"
  },
  {
    "path": "share/nip2/Makefile.am",
    "content": "SUBDIRS = rc data start compat\n"
  },
  {
    "path": "share/nip2/compat/7.10/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t_L = default_value?0;\n\t\t\t_a = default_value?1;\n\t\t\t_b = default_value?2;\n\n\t\t\tlightness = Slider 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size lightness.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [lightness.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Convert To\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum spaces (_ \"Convert to\") (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum spaces (_ \"Tag as\") (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Colour Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum Whitepoints (_ \"Old whitepoint\") \"D65\";\n\t\t\tnew_white = Option_enum Whitepoints (_ \"New whitepoint\") \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= monitor_profile, has_bands image && get_bands image == 3\n\t\t= print_profile;\n\trender_intents = Option_enum Render_intent.names (_ \"Render intent\") \n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgreen_red = Slider (-20) 20 0;\n\t\t\tblue_yellow = Slider (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, green_red.value, blue_yellow.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thue = Slider 0 360 0;\n\t\t\tsaturation = Slider 0.01 5 1;\n\t\t\tbrightness = Slider 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [bv, sv, 1] + Vector [0, 0, hv];\n\t\t\t\t\tbv = brightness.value;\n\t\t\t\t\tsv = saturation.value;\n\t\t\t\t\thv = hue.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tdE_threshold = Slider 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < dE_threshold\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_image_to_colour_item = class\n\tMenuaction (_ \"Im_age to Colour\") (_ \"convert image to colour\") {\n\taction x \n\t\t= map_unary test x\n\t{\n\t\ttest x\n\t\t\t= to_colour x, is_Image x\n\t\t\t= to_colour (Image pixel), is_Mark x\n\t\t\t= error (_ \"Colour_from_image: arg not Image or Mark: \" ++ \n\t\t\t\tprint x)\n\t\t{\n\t\t\tpixel = extract_area x.left x.top 1 1 x;\n\t\t}\n\t}\n}\n\nColour_colour_to_image_item = class\n\tMenuaction (_ \"C_olour to _Image\") (_ \"convert colour to image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression (_ \"Width of image to make\") 64;\n\t\theight = Expression (_ \"Height of image to make\") 64;\n\n\t\t_result\n\t\t\t= map_unary (Image @ build) x\n\t\t{\n\t\t\tbuild in\n\t\t\t\t= image_new (to_real width) (to_real height) 3 \n\t\t\t\t\tImage_format.FLOAT \n\t\t\t\t\tImage_coding.NOCODING (get_type in) in 0 0;\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure 0 0 in.width in.height \n\t\t\t\t\t(to_real pacross) (to_real pdown) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make S_ynthetic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.10/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tsmooth_threshold = Slider 0 5 1.5;\n\t\t\tbrighten_max = Slider 1 50 10;\n\t\t\tdarken_max = Slider 1 50 50;\n\t\t\tflat_sharp = Slider (-2) 5 1;\n\t\t\tjaggy_sharp = Slider (-2) 5 2;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size smooth_threshold \n\t\t\t\t\t\tbrighten_max darken_max \n\t\t\t\t\t\tflat_sharp jaggy_sharp in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur\" \"blur with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Slider 1 50 1;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= convsep mask in\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur radius.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur radius.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_convf, !separable && type == 1\n\t\t\t\t\t\t= im_convsepf, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 5) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) ((guess_size + 1) / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twidth = Expression \"Window width\" 3;\n\t\t\theight = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real width * to_real height + 1) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank width height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tthreshold \n\t\t\t\t= Slider 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more threshold.value) x;\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tDilate8_item = class\n\t\tMenuaction \"Dilate _8-connected\" \"dilate with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8) x;\n\t}\n\n\tDilate4_item = class\n\t\tMenuaction \"Dilate _4-connected\" \"dilate with a 4-connected mask\" {\n\t\taction x = map_unary (dilate mask4) x;\n\t}\n\n\tErode8_item = class\n\t\tMenuaction \"_Erode 8-connected\" \"erode with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8) x;\n\t}\n\n\tErode4_item = class\n\t\tMenuaction \"E_rode 4-connected\" \"erode with a 4-connected mask\" {\n\t\taction x = map_unary (erode mask4) x;\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value frequency_cutoff.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tring_width = Slider 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) frequency_cutoff.value \n\t\t\t\t\tring_width.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\t\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\t\t\tradius = Slider 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) \n\t\t\t\t\t\tfrequency_cutoff_x.value frequency_cutoff_y.value\n\t\t\t\t\t\tradius.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) frequency_cutoff.value \n\t\t\t\t\tamplitude_cutoff.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tring_width = Slider 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) frequency_cutoff.value \n\t\t\t\t\tring_width.value amplitude_cutoff.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\t\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\t\t\tradius = Slider 0.01 0.99 0.5;\n\t\t\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) \n\t\t\t\t\tfrequency_cutoff_x.value frequency_cutoff_y.value \n\t\t\t\t\tradius.value amplitude_cutoff.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\torder = Slider 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2)\n\t\t\t\t\t\torder.value\n\t\t\t\t\t\tfrequency_cutoff.value amplitude_cutoff.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tring_width = Slider 0.01 0.99 0.5;\n\t\t\t\torder = Slider 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8)\n\t\t\t\t\t\torder.value frequency_cutoff.value ring_width.value \n\t\t\t\t\t\tamplitude_cutoff.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\t\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\t\t\tradius = Slider 0.01 0.99 0.5;\n\t\t\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\torder = Slider 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) order.value\n\t\t\t\t\t\tfrequency_cutoff_x.value frequency_cutoff_y.value\n\t\t\t\t\t\tradius.value amplitude_cutoff.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\toffset = Slider (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + offset;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Slider 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Slider 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twidth = Expression \"Window width\" 20;\n\t\t\t\theight = Expression \"Window height\" 20;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local width.expr height.expr in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Slider (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Slider (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Slider (-1) 1 0;\n\t\t\tshift = Slider (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Slider (-1) 1 0;\n\t\t\tshift = Slider (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Slider (-1) 1 0;\n\t\t\thshift = Slider (-1) 1 0;\n\t\t\tvshift = Slider (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tSlider_blend_item = class\n\t\tMenuaction \"_Slider Blend\" \"blend two objects together with a slider\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tblend = Slider 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - blend) + im2 * blend;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image Blend\" \"use an image to blend two objects\" {\n\t\taction a b c \n\t\t\t\t= map_trinary process a b c\n\t\t{\n\t\t\tprocess a b c \n\t\t\t\t= blend condition in1 in2\n\t\t\t{\n\t\t\t\tcompare a b\n\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t= false, \n\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t= false, \n\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t= false,\n\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t= true;\n\t\t\t\targs' = sortc compare [a, b, c];\n\t\t\t\tcondition = args'?0;\n\t\t\t\tin1 = args'?1;\n\t\t\t\tin2 = args'?2;\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Slider 0 1 0.5;\n\t\t\tblend_width = Slider 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t\"Green over Red\",\n\t\t\t\"Blue over Red\",\n\t\t\t\"Red over Green\",\n\t\t\t\"Red over Blue\",\n\t\t\t\"Blue over Green\",\n\t\t\t\"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Slider 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\targs = sortc (const (is_colour_type @ get_type)) [a, b];\n\t\t\t\tmono = args?0;\n\t\t\t\tcolour = args?1;\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Slider 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t\t\"Grey\",\n\t\t\t\t\"Green over Red\",\n\t\t\t\t\"Blue over Red\",\n\t\t\t\t\"Red over Green\",\n\t\t\t\t\"Red over Blue\",\n\t\t\t\t\"Blue over Green\",\n\t\t\t\t\"Green over Blue\"\n\t\t\t] 0;\n\t\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider f t v = class \n\t\t\t\t\tscope.Slider f t ((int) v) {\n\t\t\t\t\tSlider = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Slider 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tradius = Slider 0 50 5;\n\t\thighlights = Slider 0 100 95;\n\t\tglow = Slider 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur \n\t\t\t\t\tradius.value) mask;\n\t\t\t\tcolour' = colour_transform_to \n\t\t\t\t\timage.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        shadow_x = Slider (-50) 50 5;\n        shadow_y = Slider (-50) 50 5;\n        shadow_softness = Slider 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = shadow_softness.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect shadow_x.value shadow_y.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.10/Format.def",
    "content": "Format_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nFormat_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = Group x;\n}\n\nFormat_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = x.value;\n}\n\n#separator\n\nFormat_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nFormat_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list (or group) of objects into a single object\" {\n\taction x\n\t\t= ass x.value, is_Group x\n\t\t= ass x\n\t{\n\t\tass x\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= map_unary ass x, is_list x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.10/Histogram.def",
    "content": "Hist_new_item = class\n\tMenuaction \"_New Histogram\" \"make a new histogram\" {\n\taction = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tdepth = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\tblack = Slider 0 100 0;\n\t\twhite = Slider 0 100 100;\n\n\t\tshadow_point = Slider 0.1 0.3 0.2;\n\t\tmid_point = Slider 0.4 0.6 0.5;\n\t\thighlight_point = Slider 0.7 0.9 0.8;\n\n\t\tshadow_adjust = Slider (-15) 15 0;\n\t\tmid_adjust = Slider (-30) 30 0;\n\t\thighlight_adjust = Slider (-15) 15 0;\n\n\t\t_result = tone_build fmt\n\t\t\t\tblack white\n\t\t\t\tshadow_point mid_point highlight_point\n\t\t\t\tshadow_adjust mid_adjust highlight_adjust\n\t\t{\n\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?depth;\n\t\t}\n\t}\n}\n\nHist_find_item = class \n\tMenupullright \"_Find Histogram\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map Histogram\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\targs = sortc (const is_hist) [a, b];\n\t\t\tim = args?0;\n\t\t\thist = args?1;\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Cumulativise Histogram\" \n\t\t\"form cumulative histogram from frequency histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise Histogram\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch Histogram\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (image_set_type Image_type.HISTOGRAM @ Image) [\n\t\t\t\t\tim_profile image.value 0,\n\t\t\t\t\tim_profile image.value 1,\n\t\t\t\t\tim_profile (fliptb image.value) 0,\n\t\t\t\t\tim_profile (fliplr image.value) 1\n\t\t\t\t]?edge;\n\t\t}\n\t}\n}\n\nHist_graph_item = class \n\tMenuaction \"_Slice Image\" \"slice an image along a guide\" {\n\taction x\n\t\t= map_unary process x\n\t{\n\t\tprocess guide\n\t\t\t= image_set_type Image_type.HISTOGRAM slice\n\t\t{\n\t\t\tslice\n\t\t\t\t= extract_area \n\t\t\t\t\t0 guide.top guide.width 1 guide.image,\n\t\t\t\t\tis_HGuide guide\n\t\t\t\t= extract_area\n\t\t\t\t\tguide.left 0 1 guide.height guide.image;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.10/Image.def",
    "content": "Image_new_item = class \n\tMenuaction \"New _Image\" \"make a new image\" {\n\tformat_names = [\n\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t];\n\n\taction = class \n\t\tImage _result {\n\t\t_vislevel = 3;\n\n\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\tnbands = Expression \"Image bands\" 1;\n\t\tformat_option = Option \"Image format\" format_names 0;\n\t\ttype_option = Option_enum \n\t\t\tImage_type.type_names \"Image type\" \"B_W\";\n\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t_result\n\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t}\n}\n\nImage_new_from_image_item = class\n\tMenuaction \"New _From Image\" \"make a new image based on image x\" {\n\taction x = class\n\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t}\n} \n\nImage_region_item = class \n\tMenupullright \"New _Region on Image\" \"make a new region on an image\" {\n\tRegion_item = class \n\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t}\n\n\tMark_item = class \n\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t}\n\n\tArrow_item = class \n\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t}\n\n\tHGuide_item = class \n\t\tMenuaction \"_Horizontal Guide\" \"make a horizontal guide on an image\" {\n\t\taction image = scope.HGuide image 0.5;\n\t}\n\n\tVGuide_item = class \n\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\taction image = scope.VGuide image 0.5;\n\t}\n}\n\n#separator\n\nImage_number_format_item = class\n\tMenupullright \"_Number Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find the image geometry ... don't bother trying to look\n\t\t// inside groups though\n\t\t_geo\n\t\t\t= x.rect, is_Image x\n\t\t\t= Rect 0 0 100 100;\n\n\t\tl = Expression \"Crop left\" ((int) (_geo.left + _geo.width / 4));\n\t\tt = Expression \"Crop top\" ((int) (_geo.top + _geo.height / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (_geo.width / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (_geo.height / 2)));\n\n\t\t_result \n\t\t\t= map_unary extract x\n\t\t{\n\t\t\textract im\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands, \n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t_sorted = sortc _pred [a, b];\n\t\t\t_a' = _sorted?0;\n\t\t\t_b' = _sorted?1;\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join images together left/right or up/down\" {\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Slider 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Slider 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Slider (-100) (100) 0;\n\t\t\tvshim = Slider (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list x);\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 10;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 10;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Slider 0.001 3 1;\n\t\t\toffset = Slider (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Slider 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tshadow_adjust = Slider (-15) 15 0;\n\t\t\tmid_adjust = Slider (-30) 30 0;\n\t\t\thighlight_adjust = Slider (-15) 15 0;\n\n\t\t\tshadow_point = Slider 0.1 0.3 0.2;\n\t\t\tmid_point = Slider 0.4 0.6 0.5;\n\t\t\thighlight_point = Slider 0.7 0.9 0.8;\n\t\t\tblack = Slider 0 100 0;\n\t\t\twhite = Slider 0 100 100;\n\n\t\t\tcurve = tone_build x.format \n\t\t\t\t\tblack white\n\t\t\t\t\tshadow_point mid_point highlight_point\n\t\t\t\t\tshadow_adjust mid_adjust highlight_adjust;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in = [\n\t\t\t\t\t\tin, \n\t\t\t\t\t\trot90 in,\n\t\t\t\t\t\trot180 in,\n\t\t\t\t\t\trot270 in\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Slider (-180) 180 0;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x \n\t\t\t\t= map_unary straighten x\n\t\t\t{\n\t\t\t\tstraighten arrow\n\t\t\t\t\t= rotate angle'' arrow.image\n\t\t\t\t{\n\t\t\t\t\tx = arrow.width;\n\t\t\t\t\ty = arrow.height;\n\t\n\t\t\t\t\tangle = im (polar (x, y));\n\t\n\t\t\t\t\tangle'\n\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t= angle;\n\t\n\t\t\t\t\tangle''\n\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\t_interp = Option_enum Interpolate.names \"Interpolation\" \"Bilinear\";\n\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tinterp = _interp;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize xfactor yfactor interp.value_thing image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\tinterp = _interp;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize fac fac interp.value_thing image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor = max_pair xfac yfac;\n\t\t\t\t\t\tmin_factor = min_pair xfac yfac;\n\t\t\t\t\t\tfac = [max_factor, min_factor, xfac, yfac]?which;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\"\n\t\t\t(map (extract 0) Interpolate.names.value) Interpolate.BILINEAR;\n\t\trubber_order = Option \"order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\tscale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_transform {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t_result = transform_search max_err max_iter order interp wrap\n\t\t\t\t\t\tsample reference;\n\n\t\t\t\ttransformed_image = Image _result?0;\n\t\t\t\t_transform = Transform _result?1 \n\t\t\t\t\treference.width reference.height;\n\t\t\t\tfinal_error = _result?2;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\targs = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\ti = args?0;\n\t\t\t\t\t\tt = args?1;\n\t\t\t\t\t\tt' = t.scale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n\n    sep2 = Menuseparator;\n\n\tResize_canvas_item = class\n\t\tMenuaction \"Resize _Canvas\" \"change size of surrounding image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to guess a sensible size for the new image \n\t\t\t_guess_size\n\t\t\t\t= x.rect, is_Image x\n\t\t\t\t= Rect 0 0 100 100;\n\n\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\tbgcolour = Expression \"Background colour\" 0;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image \n\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t{\n\t\t\t\t\twidth = image.width;\n\t\t\t\t\theight = image.height;\n\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\tbands \n\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t= image.bands;\n\t\t\t\t\tformat \n\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t= image.format;\n\t\t\t\t\ttype = image.type;\n\n\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\txp \n\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\typ \n\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t= yposv?((int) (position / 3));\n\n\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_edit_header_item = class\n\tMenuaction \"Change _Header\" \"change advisory header fields of image\" {\n\ttype_names = Image_type.type_names;\n\tall_names = sort (map (extract 0) type_names.value);\n\n\tget_prop has get def x\n\t\t= get x, has x\n\t\t= def;\n\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\ttype_option \n\t\t\t= Option_enum Image_type.type_names \"Image type\"\n\t\t\t\t(Image_type.type_names.get_name type)\n\t\t{\n\t\t\ttype \n\t\t\t\t= x.type, is_Image x\n\t\t\t\t= Image_type.MULTIBAND;\n\t\t}\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= ramp, orientation == 0\n\t\t\t\t= rot90 ramp\n\t\t\t{\n\t\t\t\tfn \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tramp = Image (fn (to_real nwidth) (to_real nheight));\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tGaussian_item = class \n\t\tMenuaction \"Gaussian _Noise\" \"make an image of gaussian noise\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tmean = Slider 0 255 128;\n\t\t\tdeviation = Slider 0 128 50;\n\n\t\t\t_result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) \n\t\t\t\tmean.value deviation.value);\n\t\t}\n\t}\n\n\tFractal_item = class \n\t\tMenuaction \"_Fractal\" \"make a fractal image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tdimension = Slider 2.001 2.999 2.001;\n\n\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t}\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Slider 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value frequency_cutoff.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tring_width = Slider 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) frequency_cutoff.value \n\t\t\t\t\t\t\t\tring_width.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\t\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\t\t\tradius = Slider 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12)\n\t\t\t\t\t\t\tfrequency_cutoff_x.value frequency_cutoff_y.value\n\t\t\t\t\t\t\tradius.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4)\n\t\t\t\t\t\t\tfrequency_cutoff.value amplitude_cutoff.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tring_width = Slider 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10)\n\t\t\t\t\t\t\tfrequency_cutoff.value ring_width.value \n\t\t\t\t\t\t\tamplitude_cutoff.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\t\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\t\t\tradius = Slider 0.01 0.99 0.5;\n\t\t\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16)\n\t\t\t\t\t\t\tfrequency_cutoff_x.value frequency_cutoff_y.value\n\t\t\t\t\t\t\tradius.value amplitude_cutoff.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\torder = Slider 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2)\n\t\t\t\t\t\t\t\torder.value frequency_cutoff.value \n\t\t\t\t\t\t\t\tamplitude_cutoff.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\tring_width = Slider 0.01 0.99 0.5;\n\t\t\t\torder = Slider 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8)\n\t\t\t\t\t\t\torder.value frequency_cutoff.value \n\t\t\t\t\t\t\tring_width.value amplitude_cutoff.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\t\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\t\t\tradius = Slider 0.01 0.99 0.5;\n\t\t\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\t\t\torder = Slider 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14)\n\t\t\t\t\t\t\torder.value frequency_cutoff_x.value\n\t\t\t\t\t\t\tfrequency_cutoff_y.value radius.value \n\t\t\t\t\t\t\tamplitude_cutoff.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Slider 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Slider 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n    Colour_atlas_item = class\n        Menuaction \"_Colour Atlas\"\n            \"make a grid of patches grouped around a colour\" {\n        action = class \n            _result {   \n            _vislevel = 3;\n       \n            start = Colour_picker \"Lab\" [50,0,0];\n            nstep = Expression \"Number of steps\" 2;\n            ssize = Expression \"Step size\" 2; \n\n            _result\n                = Image (colour_transform_to (get_type start) im)\n            {\n                base = colour_transform_to Image_type.LAB start;\n                step = to_real ssize;\n                offset = to_real nstep * step;\n                range c = [c - offset, c - offset + step ... c + offset]; \n                                \n                mk_patch b a = image_new 150 150 3\n                    Image_format.FLOAT Image_coding.NOCODING \n                    Image_type.LAB (Vector [base?0, a, b]) 0 0;\n\n                mk_strip b = map (mk_patch b) (range base?1);\n                mk_grid = map mk_strip (range base?2);\n                im = imagearray_assemble 15 15 mk_grid;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.10/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/7.10\n\nstart_DATA = \\\n\tColour.def \\\n\t_convert.def \\\n\tFilter.def \\\n\tFormat.def \\\n\t_generate.def \\\n\tHistogram.def \\\n\tImage.def \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_list.def \\\n\tMath.def \\\n\tMatrix.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\tTasks.def \\\n\t_types.def \\\n\tWidgets.def\n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/7.10/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_And\" \"bitwise and of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_Or\" \"bitwise or of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"E_xclusive Or\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_Not\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c = map_trinary if_then_else a b c;\n\t}\n\n\tBand_or_item = class \n\t\tMenuaction \"Band O_r\" \"or the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_or @ bandsplit) im;\n\t}\n\n\tBand_and_item = class \n\t\tMenuaction \"Band A_nd\" \"and the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_and @ bandsplit) im;\n\t}\n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = n ? x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = a ++ b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = a : x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"_Many Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"Position of M_aximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"Position of M_inimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.10/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsigma = Slider 0.001 10 1;\n\t\t\tmin_amplitude = Slider 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn sigma.value min_amplitude.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsigma = Slider 0.001 10 1.5;\n\t\t\tmin_amplitude = Slider 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn sigma.value min_amplitude.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\textract n f = take (to_real n) @ drop (to_real f);\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (extract number first mat.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map (extract number first) mat.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 (extract 1) [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 (extract 1) \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// insert a thing in a list at position first\n\tinsert first x l\n\t\t= take first l ++ x ++ drop first l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (insert (to_real first) rows mat.value)\n\t\t\t\t{\n\t\t\t\t\trow = replicate mat.width (to_real item);\n\t\t\t\t\trows = replicate (to_real number) row;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"remove columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base \n\t\t\t\t\t\t(map (insert (to_real first) cells) mat.value)\n\t\t\t\t{\n\t\t\t\t\tcells = replicate (to_real number) (to_real item);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (delete first number mat.value);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map (delete first number) mat.value);\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_convert_to_image_item = class\n\tMenuaction \"Matrix to I_mage\" \"convert matrix to image\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tconversion = Option \"Convert to\" [\n\t\t\t\"Monochrome image, same size as matrix\",\n\t\t\t\"Multiband image, each row becomes a pixel\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess mat\n\t\t\t\t= Image im, conversion == 0\n\t\t\t\t= Image joinup\n\t\t\t{\n\t\t\t\tim = im_mask2vips mat;\n\n\t\t\t\tjoinup = bandjoin \n\t\t\t\t\t(map extract_column \n\t\t\t\t\t\t[0 .. mat.width - 1]);\n\n\t\t\t\textract_column n\n\t\t\t\t\t= extract_area n 0 1 mat.height im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_from_image_item = class\n\tMenuaction \"Image to M_atrix\" \"convert image to matrix\" {\n\taction x = map_unary to_matrix x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix_width 2]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tgwidth = Expression \"Graph size across (pixels)\" 512;\n\t\tgheight = Expression \"Graph size down (pixels)\" 512;\n\t\tplot_colour = Colour_picker \"Lab\" [80, -80, 80];\n\t\txmin = Expression \"X range minimum\" \n\t\t\t(foldr1 min_pair (map (extract 0) x.value));\n\t\txmax = Expression \"X range maximum\"\n\t\t\t(foldr1 max_pair (map (extract 0) x.value));\n\t\tymin = Expression \"Y range minimum\"\n\t\t\t(foldr1 min_pair (map (extract 1) x.value));\n\t\tymax = Expression \"Y range maximum\"\n\t\t\t(foldr1 max_pair (map (extract 1) x.value));\n\t\taxies = Toggle \"Draw axies\" true;\n\n\t\tmark \n\t\t\t= Mark this p?0 p?1\n\t\t{\n\t\t\tp = _to_image x.value?0;\n\t\t}\n\t\tmark_hint = \"Mark is at position:\";\n\t\tmark_position = _from_image [mark.left, mark.top];\n\n\t\t// geometry\n\t\t_xrange = to_real xmax - to_real xmin;\n\t\t_yrange = to_real ymax - to_real ymin;\n\t\t_xscale = to_real gwidth / _xrange;\n\t\t_yscale = to_real gheight / _yrange;\n\n\t\t// map an [x,y] point into the image coordinates\n\t\t_to_image p = [(p?0 - to_real xmin) * _xscale, \n\t\t\tto_real gheight - (p?1 - to_real ymin) * _yscale];\n\n\t\t// map an [x,y] point from image cods back to real cods\n\t\t_from_image p = [p?0 / _xscale + to_real xmin, \n\t\t\t(to_real gheight - p?1) / _yscale + to_real ymin];\n\n\t\t_result\n\t\t\t= Image (foldr plot background' x.value)\n\t\t{\n\t\t\t// colourspace we are drawing in\n\t\t\tspace = Image_type.colour_spaces.lookup \n\t\t\t\t0 1 plot_colour.colour_space;\n\n\t\t\tplot_image_new width height pixel\n\t\t\t\t= image_new width height 3 Image_format.FLOAT \n\t\t\t\t\tImage_coding.NOCODING space pixel 0 0;\n\n\t\t\t// background\n\t\t\tbackground = plot_image_new (to_real gwidth) (to_real gheight) 0;\n\n\t\t\t// mark we plot\n\t\t\tmark_width = max_pair 1 (to_real gwidth / 100);\n\t\t\tmark_height = max_pair 1 (to_real gheight / 100);\n\t\t\tmark = plot_image_new mark_width mark_height plot_colour;\n\n\t\t\t// draw axies on background \n\t\t\tbackground' \n\t\t\t\t= drawxy, axies\n\t\t\t\t= background\n\t\t\t{\n\t\t\t\t// colour we draw axies in\n\t\t\t\tax_col = colour_transform_to space (Colour \"Lab\" [100, 0, 0]);\n\n\t\t\t\t// axies\n\t\t\t\txaxis = plot_image_new (to_real gwidth) 1 ax_col; \n\t\t\t\tyaxis = plot_image_new 1 (to_real gheight) ax_col;\n\t\t\t\torigin = _to_image [0, 0];\n\n\t\t\t\tdrawx = insert_noexpand 0 origin?1 xaxis background;\n\t\t\t\tdrawxy = insert_noexpand origin?0 0 yaxis drawx;\n\t\t\t}\n\n\t\t\t// plot a single point on an image\n\t\t\tplot p im \n\t\t\t\t= insert_noexpand \n\t\t\t\t\t(x - mark_width / 2) (y - mark_height / 2) mark im\n\t\t\t{\n\t\t\t\tp' = _to_image p;\n\t\t\t\tx = p'?0;\n\t\t\t\ty = p'?1;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.10/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tbrightness = Slider 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcolour = Slider 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcontrast = Slider 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Slider 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes_hint = \"Average this many frames:\";\n\t\t\tframes = Slider 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tbrightness.value colour.value contrast.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Slider 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\targs = sortc larger [a, b];\n\t\t\t\t\timage = args?0;\n\t\t\t\t\tpatch = args?1;\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = im_measure image.value 0 0 image.width image.height 6 4;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb = Matrix (map2 cons _true_grey_Y' _camera_grey');\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\tlinearising_lut = Image _linear_lut;\n\n\t\t\t// map the original image through the lineariser to \n\t\t\t// get linear 0-1 RGB image\n\t\t\t_image' = hist_map linearising_lut.value image.value;\n\n\t\t\t// remeasure and solve for RGB -> XYZ\n\t\t\t_camera' = im_measure _image' 0 0 image.width image.height 6 4;\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\tM = transpose (_pinv * transpose _camera' * _true_XYZ);\n\n\t\t\t// convert linear RGB camera to Lab \n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tcast_float @\n\t\t\t\trecomb M) _image';\n\n\t\t\t// measure again and compute dE76\n\t\t\t_camera'' = im_measure _result.value 0 0 \n\t\t\t\timage.width image.height 6 4;\n\n\t\t\t_dEs = map abs_vec (map Vector (_camera'' - _true_Lab).value);\n\t\t\tfinal_dE76 = mean (Vector _dEs);\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch = _macbeth_names ? _worst ++ \" (patch \" ++ \n\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\tprint _max_dE ++ \" dE)\";\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b \n\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t{\n\t\t\t// the name of the calib object we need\n\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t// get the Calibrate_chart arg first\n\t\t\targs = sortc (const (is_instanceof calib_name)) [a, b];\n\t\t\tcalib = args?1;\n\t\t\timage = args?0;\n\n\t\t\t// map the original image through the lineariser to get \n\t\t\t// linear 0-1 RGB image\n\t\t\timage' = hist_map calib.linearising_lut image;\n\n\t\t\t// convert linear RGB camera to Lab \n\t\t\tresult = colour_transform Image_type.XYZ Image_type.LAB \n\t\t\t\t((float) (recomb calib.M image'));\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"building image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\tlen images != 2 \n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = land (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\t\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\t\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Slider 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tblend_width = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 blend_width.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) blend_width.value\n\t\t\t{\n\t\t\t\tsorted = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t\ta' = sorted?0;\n\t\t\t\tb' = sorted?1;\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tblend_width = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 blend_width.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) blend_width.value\n\t\t\t{\n\t\t\t\tsorted = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t\ta' = sorted?0;\n\t\t\t\tb' = sorted?1;\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Slider 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tblend_width = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 blend_width.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tblend_width.value\n\t\t\t\t{\n\t\t\t\t\tsorted = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t\ta' = sorted?0;\n\t\t\t\t\tb' = sorted?1;\n\t\t\t\t\tc' = sorted?2;\n\t\t\t\t\td' = sorted?3;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tblend_width = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 blend_width.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tblend_width.value\n\t\t\t\t{\n\t\t\t\t\tsorted = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t\ta' = sorted?0;\n\t\t\t\t\tb' = sorted?1;\n\t\t\t\t\tc' = sorted?2;\n\t\t\t\t\td' = sorted?3;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if_then_else m_control im_in 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_instanceof \"Group\"  m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Slider 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_instanceof \"Group\"  m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize xfactor yfactor 1 scale_im;\n\t\t\t_offset_im = resize xfactor yfactor 1 offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.scale_cutoff, r1 >=\nOptions.scale_cutoff]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            scale_cutoff = Slider 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = class \n\t\tMenuaction \"_Adjust Tone Curve\" \"adjust tone curve on L*\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tauto = Option \"Set black and white point\" [\n\t\t\t\t\"Manually\",\n\t\t\t\t\"Automatically from image histogram\"\n\t\t\t] 0;\n\t\t\tblack = Slider 0 100 0;\n\t\t\twhite = Slider 0 100 100;\n\n\t\t\tshadow_point = Slider 0.1 0.3 0.2;\n\t\t\tmid_point = Slider 0.4 0.6 0.5;\n\t\t\thighlight_point = Slider 0.7 0.9 0.8;\n\n\t\t\tshadow_adjust = Slider (-15) 15 0;\n\t\t\tmid_adjust = Slider (-30) 30 0;\n\t\t\thighlight_adjust = Slider (-15) 15 0;\n\n\t\t\tpreview_curve = Image (im_tone_build black.value white.value\n\t\t\t\tshadow_point.value mid_point.value highlight_point.value\n\t\t\t\tshadow_adjust.value mid_adjust.value highlight_adjust.value);\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= tone_map curve lab \n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t\tcurve \n\t\t\t\t\t\t= preview_curve, auto == 0\n\t\t\t\t\t\t= tone_analyse \n\t\t\t\t\t\t\tshadow_point mid_point highlight_point\n\t\t\t\t\t\t\tshadow_adjust mid_adjust highlight_adjust\n\t\t\t\t\t\t\tlab;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\t// strange order forced on us by need to keep numbering backwards\n\t\t\t// compatible though 7.10\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\",\n\t\t\t\t\"400 dpi\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.10/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Slider\" \"make a new slider widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Slider 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.10/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x, is_real x || is_image x \n\t= error (_ \"bad arguments to \" ++ \"to_matrix\")\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, \n\t\t\tis_image i && get_bands i == 1\n\t\t= (im_vips2mask ((double) i'')).value, \n\t\t\tis_image i && get_bands i == 3 && get_width i == 1\n\t\t= error (_ \"not 1 band image, or 3 band 1 column image\")\n\t{\n\t\tsplit = bandsplit i;\n\t\ti' = im_insert (split?0) (split?1) 1 0;\n\t\ti'' = im_insert i' (split?2) 2 0;\n\t}\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x, is_real x || is_image x \n\t= error (_ \"bad arguments to \" ++ \"to_image\")\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= Colour (colour_space (get_type x)) (map mean (bandsplit (get_image x))),\n\t\thas_image x && has_type x\n\t= error (_ \"bad arguments to \" ++ \"to_colour\")\n{\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real.\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= to_real x.value, is_class x\n\t= x, is_real x\n\t= abs x, is_complex x\n\t= 1, is_bool x && x\n\t= 0, is_bool x && !x\n\t= error (_ \"bad arguments to \" ++ \"to_real\");\n\n/* Try to make a list ... ungroup, basically. Recurse for subgroups.\n */\nto_list x\n\t= map to_list x.value, is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), len parts != 2\n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, len parts != 4\n\t= (ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", member \".0123456789\",\n\t\tmember \"eE\", member \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n// matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n// measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t[\"D93\", D93_whitepoint],\n\t[\"D75\", D75_whitepoint],\n\t[\"D65\", D65_whitepoint],\n\t[\"D55\", D55_whitepoint],\n\t[\"D50\", D50_whitepoint],\n\t[\"A\", A_whitepoint],\n\t[\"B\", B_whitepoint],\n\t[\"C\", C_whitepoint],\n\t[\"E\", E_whitepoint],\n\t[\"D3250\", D3250_whitepoint]\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* Convert D50 Lab to XYZ.\n */\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (im_header_int \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab in = im_XYZ2Lab (im_sRGB2XYZ in);\n\nim_Lab2sRGB in = im_XYZ2sRGB (im_Lab2XYZ in);\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* Given a list of things, try to make them all the same size. Don't change\n * the format. Don't touch non-image things.\n */\nsize_alike l\n\t= map enlarge l\n{\n\tmax_width = foldr (test_prop has_width get_width) 0 l;\n\tmax_height = foldr (test_prop has_height get_height) 0 l;\n\n\ttest_prop has get x best\n\t\t= best, !has x\n\t\t= max_pair best (get x);\n\n\tenlarge x\n\t\t= embed 0 0 0 max_width max_height x, has_width x\n\t\t= x;\n}\n\n/* Given a list of things, look for 1 band objects and bump them to to n -\n * band objects, where n is the maximum number of bands. Don't change the \n * format. Don't touch non-image things.\n */\nbands_alike l\n\t= map upband l\n{\n\tmax_bands = foldr (test_prop has_bands get_bands) 0 l;\n\n\ttest_prop has get x best\n\t\t= best, !has x\n\t\t= max_pair best (get x);\n\n\tupband x\n\t\t= bandjoin (replicate max_bands x),\n\t\t\thas_bands x && get_bands x == 1\n\t\t= x;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.10/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black (to_real w) (to_real h) (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = Matrix_con mask_g_sum 0 [mask_g_line]\n{\n        mask_g = im_gauss_imask (radius / 3) 0.2;\n        mask_g_line = mask_g.value?(mask_g.height / 2);\n        mask_g_sum = foldr1 add mask_g_line;\n}\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (foldr1 add mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.10/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = class\n\t\t\t\t{\n\t\t\t\tscale_factor = Expression \"scale the size of the frame by\" 1;\n\n\t\t\t\t/* These sliders define the fraction of the frames width or height is extracted\n\t\t \t\t * to produce each of the particular regions.\n\t\t \t\t */\n\t\t\t\tcorner_section = Slider 0.1 1 0.5;\n\t\t\t\tmiddle_section = Slider 0.1 1 0.2;\n\t\t\t\tblend_fraction = Slider 0.1 0.9 0.1;\n\t\t\t\t}\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = class\n\t\t\t\t{\n\t\t\t\tapply = Toggle \"Apply mount options\" false;\n\t\t\t\tls = Expression \"Lower mount section bigger by (cm)\" 0;\n\t\t\t\tmount_colour = Colour _type [0, 0, 0];\n\t\t\t\t_los = ls.expr * ppcm.expr;\n\t\t\t\t}\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize _sf _sf Interpolate.BILINEAR a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\n\t\t\tvariables = class\n\t\t\t\t{\n\t\t\t\tscale_factor = Expression \"scale the size of the frame by\" 1;\n\n\t\t\t\t/* These sliders define the fraction of the frames width or height that\n\t\t\t\t * is extracted to produce each of the particular regions.\n\t\t \t\t */\n\t\t\t\tcorner_section = Slider 0.1 1 0.5;\n\t\t\t\tmiddle_section = Slider 0.1 1 0.3;\n\t\t\t\tblend_fraction = Slider 0.1 0.9 0.1;\n\t\t\t\toption = Toggle \"Use mirror of left-side to make right\" true;\n\t\t\t\t}\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = class\n\t\t\t\t{\n\t\t\t\tapply = Toggle \"Apply mount options\" false;\n\t\t\t\tls = Expression \"Lower mount section bigger by (cm)\" 0;\n\t\t\t\tmount_colour = Colour _type [0, 0, 0];\n\t\t\t\t_los = ls.expr * ppcm.expr;\n\t\t\t\t}\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize _sf _sf Interpolate.BILINEAR a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\n\t\t\tvariables = class\n\t\t\t\t{\n\t\t\t\tscale_factor = Expression \"scale the size of the frame by\" 1;\n\n\t\t\t\t/* These sliders define the fraction of the frames width or height is extracted\n\t\t \t\t * to produce each of the particular regions.\n\t\t \t\t */\n\t\t\t\tcorner_section = Slider 0.1 1 0.4;\n\t\t\t\tedge_section = Slider 0.1 1 0.1;\n\t\t\t\tmiddle_section = Slider 0.1 0.5 0.3;\n\t\t\t\tblend_fraction = Slider 0.1 0.9 0.1;\n\t\t\t\toption = Toggle \"Use mirror of left-side to make right\" true;\n\t\t\t\t}\n\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = class\n\t\t\t\t{\n\t\t\t\tapply = Toggle \"Apply mount color\" false;\n\t\t\t\tls = Expression \"Lower mount section bigger by (cm)\" 0;\n\t\t\t\tcolour = Colour _type [0, 0, 0];\n\t\t\t\t_los = ls.expr * ppcm.expr;\n\t\t\t\t}\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize _sf _sf Interpolate.BILINEAR a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" ] 6;\n\n\n\tcontrol_selection mask im no\n\t\t= (if mask then im * 1.2 else im * 1), no == 0\n\t\t= (if mask then im * 0.8 else im * 1), no == 1\n\t\t= (if mask then 0 else im), no == 2\n\t\t= (if mask then 255 else im), no == 3\n\t\t= (if mask then im else 0), no == 4\n\t\t= (if mask then im else 255), no == 5\n\t\t= mask;\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Slider 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = a.image;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = ((pt_list.value)?0).image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize f1 f2 1 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize f1 1 1 b1\n\t\t\t\t\t{b1 = resize 1 f2 1 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/7.10/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if_then_else mask im 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\t\t\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\t\t\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t}\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\t\t\n\t\t\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = im_header_int \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = im_header_int \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = im_header_int \"Xsize\" (get_image im), dir == 0\n\t    \t = im_header_int \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t}\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = line.image;\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\t\t\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_instanceof \"Group\"  pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = (pt_l?0).image;\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t}\n\n\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t}\n"
  },
  {
    "path": "share/nip2/compat/7.10/_list.def",
    "content": "/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn (tl l), fn (hd l)\n\t= l;\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* foldl fn st l: fold list l up from the left using function fn and start value st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st (hd l)) (tl l);\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn (hd l) (tl l);\n\n/* foldr fn st l: fold up list l, right to left, with function fn and start \n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn (hd l) (foldr fn st (tl l));\n\n/* foldrl fn l: like foldr, but use the 1st element as the start value\n *\n * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= foldr fn (hd l) (tl l);\n\n/* Search a list for an element, returning it's index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn (hd l)\n\t\t= search (tl l) (n + 1);\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= hd l : init (tl l);\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* land l: and all the elements of list l together\n *\n * land (map (==0) list) == true, if every element of list is zero.\n * land :: [bool] -> bool\n */\nland = foldr logical_and true;\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= hd l, tl l == []\n\t= last (tl l);\n\n/* len l: length of list l\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta = l?0;\n\tb = l?1;\n\tx = tl (tl l);\n}\n\n/* lor l: or all the elements of list l together\n *\n * lor (map (equal 0) list) == true, if any element of list is zero.\n * lor :: [bool] -> bool\n */\nlor = foldr logical_or false;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2\n\t= map fn' (zip2 l1 l2)\n{\n\tfn' p = fn p?0 p?1;\n}\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3\n\t= map fn' (zip3 l1 l2 l3)\n{\n\tfn' p = fn p?0 p?1 p?2;\n}\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = lor (map (equal x) l);\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta = hd l;\n\tx = tl l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scan fn st l: apply (fold fn r) to every initial segment of a list\n *\n * scan add 0 [1,2,3] == [1,3,6]\n * scan :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscan fn \n\t= g \n{\n\tg st l\n\t\t= [st], l == []\n\t\t= st : g (fn st (hd l)) (tl l);\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta = hd l1;\n\t\tx = tl l1;\n\t\tb = hd l2;\n\t\ty = tl l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by fn\n *\n * split is_space \"hello world\" == [\"hello\", \"world\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n  \n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together\n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/7.10/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true of character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && land (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, land (map is_obj l)\n\t= true, land (map is_list l) &&\n\t\tland (map (not @ is_obj) l) &&\n\t\tland (map is_rectangular l) &&\n\t\tlen l > 0 &&\n\t\tland (map (equal (hd lengths)) (tl lengths))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n\tlengths = map len l;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n */\nis_matrix l = is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == []\n      = is_matrix l && len l == len (hd l);\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == []\n      = is_matrix l && (len l) % 2 == 1 && (len (l?0)) % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && (len l) % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Slider x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && land (map xy l)\n{\n\txy l = is_real_list l && len l == 2;\n}\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= error (\"get_type: unable to get type from \" ++ print x)\n{\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.B_W, bands == 1\n\t\t= type, bands == 3 && is_colorimetric\n\t\t= Image_type.sRGB, bands == 3 && !is_colorimetric\n\t\t= Image_type.MULTIBAND, bands != 3 && !is_colorimetric\n\t\t= type\n\t{\n\t\ttype = im_header_int \"Type\" im;\n\t\tcoding = im_header_int \"Coding\" im;\n\t\tbands = im_header_int \"Bands\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= im_header_int \"BandFmt\" x, is_image x\n\t= error (\"get_format: unable to get format from \" ++ print x);\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= im_header_int \"Bbits\" x, is_image x\n\t= error (\"get_bits: unable to get bits from \" ++ print x);\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= im_header_int \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= error (\"get_bands: unable to get bands from \" ++ print x);\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= im_header_int \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= error (\"get_coding: unable to get coding from \" ++ print x);\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= im_header_int \"Xres\" x, is_image x\n\t= error (\"get_xres: unable to get xres from \" ++ print x);\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= im_header_int \"Yres\" x, is_image x\n\t= error (\"get_yres: unable to get yres from \" ++ print x);\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= im_header_int \"Xoffset\" x, is_image x\n\t= error (\"get_xoffset: unable to get xoffset from \" ++ print x);\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= im_header_int \"Yoffset\" x, is_image x\n\t= error (\"get_yoffset: unable to get yoffset from \" ++ print x);\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= error (\"get_image: unable to get image from \" ++ print x);\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= error (\"get_number: unable to get number from \" ++ print x);\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= error (\"get_real: unable to get real from \" ++ print x);\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= im_header_int \"Xsize\" x, is_image x\n\t= error (\"get_width: unable to get width from \" ++ print x);\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= im_header_int \"Ysize\" x, is_image x\n\t= error (\"get_height: unable to get height from \" ++ print x);\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= error (\"get_left: unable to get left from \" ++ print x);\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= error (\"get_top: unable to get top from \" ++ print x);\n\n// like has/get member,but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.10/_stdenv.def",
    "content": "/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\njoin a b = a ++ b;\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\nif_then_else a b c = if a then b else c;\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error \"unimplemented vector operation\"\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n/* Macbeth chart patch names.\n */\n_macbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = im_header_int \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined,\n\t\thas_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean_object Operator_type.COMPOUND false;\n\n\tmean_object x\n\t\t= im_avg x, is_image x\n\t\t= mean_list x, is_real_list x || is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"mean\");\n\n\tmean_list l \n\t\t= s / n\n\t{\n\t\ttotals = sum l;\n\t\tn = totals?0;\n\t\ts = totals?1;\n\t}\n\n\t// return [n, sum] for a list of numbers, or a list of list of num\n\t// etc.\n\tsum x\n\t\t= foldr accumulate [0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s], is_real x\n\t\t\t= [n + n', s + s'], is_list x\n\t\t\t= error \"mean_list: not real or [real]\"\n\t\t{\n\t\t\tn = sofar?0;\n\t\t\ts = sofar?1;\n\n\t\t\tsub_acc = sum x;\n\n\t\t\tn' = sub_acc?0;\n\t\t\ts' = sub_acc?1;\n\t\t}\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation_object Operator_type.COMPOUND false;\n\n\tdeviation_object x\n\t\t= im_deviate x, is_image x\n\t\t= deviation_list x, is_real_list x || is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"deviation\");\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\ttotals = sum_sum2_list l;\n\t\tn = totals?0;\n\t\ts = totals?1;\n\t\ts2 = totals?2;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\tn = sofar?0;\n\t\t\ts = sofar?1;\n\t\t\ts2 = sofar?2;\n\n\t\t\tsub_acc = sum_sum2_list x;\n\n\t\t\tn' = sub_acc?0;\n\t\t\ts' = sub_acc?1;\n\t\t\ts2' = sub_acc?2;\n\t\t}\n\t}\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs_object Operator_type.COMPOUND false;\n\n\tabs_object x\n\t\t= im_abs x, is_image x\n\t\t= abs_cmplx x, is_complex x\n\t\t= abs_num x, is_real x\n\t\t= abs_list x, is_real_list x\n\t\t= abs_list (map abs_list x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"abs\");\n\n\tabs_list l = (foldr1 add (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec_object Operator_type.COMPOUND false;\n\n\tabs_vec_object x\n\t\t= abs_vec_image x, is_image x\n\t\t= abs_vec_cmplx x, is_complex x\n\t\t= abs_vec_num x, is_real x\n\t\t= abs_vec_list x, is_real_list x\n\t\t= mean (Vector (map abs_vec_list x)), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"abs_vec\");\n\n\tabs_vec_list l = (foldr1 add (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (foldr1 add (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_matrix x, is_list x && is_list (hd x)\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose_object Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_object x\n\t\t= transpose_matrix x, is_matrix x\n\t\t= transpose_image x, is_image x\n\t\t= error (_ \"bad arguments to \" ++ \"transpose\");\n\n\ttranspose_matrix l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_matrix (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\nrot90 x\n\t= oo_unary_function rot90_op x, is_class x\n\t= im_rot90 x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"rot90\")\n{\n\trot90_op = Operator \"rot90\" \n\t\trot90_object Operator_type.COMPOUND_REWRAP false;\n\n\trot90_object x\n\t\t= rot90_matrix x, is_matrix x\n\t\t= im_rot90 x, is_image x\n\t\t= error (_ \"bad arguments to \" ++ \"rot90\");\n\n\t// slow, but what the heck\n\t// avoid im_rotate_dmask90(), it can only do square odd-sided matricies\n\trot90_matrix l = apply_matrix_as_image im_rot90 l;\n}\n\nrot180 x\n\t= oo_unary_function rot180_op x, is_class x\n\t= im_rot180 x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"rot180\")\n{\n\trot180_op = Operator \"rot180\" \n\t\trot180_object Operator_type.COMPOUND_REWRAP false;\n\n\trot180_object x\n\t\t= rot180_matrix x, is_matrix x\n\t\t= im_rot180 x, is_image x\n\t\t= error (_ \"bad arguments to \" ++ \"rot180\");\n\n\t// slow, but what the heck\n\trot180_matrix l = apply_matrix_as_image im_rot180 l;\n}\n\nrot270 x\n\t= oo_unary_function rot270_op x, is_class x\n\t= im_rot270 x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"rot270\")\n{\n\trot270_op = Operator \"rot270\" \n\t\trot270_object Operator_type.COMPOUND_REWRAP false;\n\n\trot270_object x\n\t\t= rot270_matrix x, is_matrix x\n\t\t= im_rot270 x, is_image x\n\t\t= error (_ \"bad arguments to \" ++ \"rot270\");\n\n\t// slow, but what the heck\n\trot270_matrix l = apply_matrix_as_image im_rot270 l;\n}\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(im_header_double \"Xres\" x) (im_header_double \"Yres\" x)\n\t\t(im_header_int \"Xoffset\" x) (im_header_int \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(im_header_int \"Type\" x) \n\t\t(im_header_double \"Xres\" x) (im_header_double \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nrotquad x\n\t= oo_unary_function rotquad_op x, is_class x\n\t= im_rotquad x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"rotquad\")\n{\n\trotquad_op = Operator \"rotquad\" \n\t\trotquad_object Operator_type.COMPOUND_REWRAP false;\n\n\trotquad_object x\n\t\t= rotquad_matrix x, is_matrix x\n\t\t= im_rotquad x, is_image x\n\t\t= error (_ \"bad arguments to \" ++ \"rotquad\");\n\n\trotquad_matrix l = apply_matrix_as_image im_rotquad l;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_cache x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nfliptb x\n\t= oo_unary_function fliptb_op x, is_class x\n\t= im_flipver x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"fliptb\")\n{\n\tfliptb_op = Operator \"fliptb\" \n\t\tfliptb_object Operator_type.COMPOUND_REWRAP false;\n\n\tfliptb_object x\n\t\t= fliptb_matrix x, is_matrix x\n\t\t= im_flipver x, is_image x\n\t\t= error (_ \"bad arguments to \" ++ \"fliptb\");\n\n\tfliptb_matrix l = reverse l;\n}\n\nfliplr x\n\t= oo_unary_function fliplr_op x, is_class x\n\t= im_fliphor x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"fliplr\")\n{\n\tfliplr_op = Operator \"fliplr\" \n\t\tfliplr_object Operator_type.COMPOUND_REWRAP false;\n\n\tfliplr_object x\n\t\t= fliplr_matrix x, is_matrix x\n\t\t= im_fliphor x, is_image x\n\t\t= error (_ \"bad arguments to \" ++ \"fliplr\");\n\n\tfliplr_matrix l = map reverse l;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_real_list x || is_matrix x\n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_matrix x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_real_list x || is_matrix x\n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_matrix x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\nrecomb matrix image\n\t= colour_unary recomb_op image\n{\n\trecomb_op x\n\t\t= im_recomb x (to_matrix matrix), is_image x\n\t\t= error (_ \"bad arguments to \" ++ \"recomb\");\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (converse cons [] @ converse subscript x') obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = im_header_int \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\")\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\tthen_part = x?0;\n\t\telse_part = x?1;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x\n\t\t\t= x, is_image x\n\t\t\t= x.value, is_Image x\n\t\t\t= black + x\n\t\t{\n\t\t\tblack = im_black target_width target_height target_bands;\n\t\t}\n\n\t\tthen_image = to_image then_part;\n\t\telse_image = to_image else_part;\n\n\t\tthen_image' = clip2fmt target_format then_image;\n\t\telse_image' = clip2fmt target_format else_image;\n\n\t\tresized = size_alike [cond, then_image', else_image'];\n\n\t\tblend_result_image = image_set_type target_type\n\t\t\t(im_blend resized?0 resized?1 resized?2);\n\t}\n}\n\ninsert x y small big\n\t= oo_binary_function insert_op small big, is_class small\n\t= oo_binary'_function insert_op small big, is_class big\n\t= im_insert big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n}\n\nmeasure x y w h u v image\n\t= oo_unary_function measure_op image, is_class image\n\t= im_measure image \n\t\t(to_real x) (to_real y) (to_real w) (to_real h)\n\t\t(to_real u) (to_real v), \n\t\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"measure\")\n{\n\tmeasure_op = Operator \"measure\" \n\t\t(measure x y w h u v) Operator_type.COMPOUND_REWRAP false;\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_similarity image (cos angle) (sin angle) 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\trotate Operator_type.COMPOUND_REWRAP false;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = im_header_int \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\timage = (unsigned char) im_mask2vips (Matrix m2);\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t// work for groups too (convenient)\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\nhist_find image\n\t= oo_unary_function hist_find_op image, is_class image\n\t= im_histgr image (-1), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\thist_find Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\thist_map_op = Operator \"hist_map\" \n\t\thist_map Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= lhisteq image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n\n\t// loop over bands, if necessary\n\tlhisteq im\n\t\t= im_lhisteq im (to_real w) (to_real h), get_bands im == 1\n\t\t= (foldl1 join @ map lhisteq @ bandsplit) im;\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\tsum = foldr1 add;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\nresize xfac yfac interp image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// upscale by any factor, nearest neighbour \n\t\t// can't really do this right ... upscale by integer part, then\n\t\t// bilinear to exact size\n\t\t= scale (break xfac')?1 (break yfac')?1\n\t\t\t(im_zoom im (break xfac')?0 (break yfac')?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// downscale by any factor, nearest neighbour \n\t\t// can't really do this right ... downscale by integer part, \n\t\t// then bilinear to exact size\n\t\t= scale (1 / (break rxfac')?1) (1 / (break ryfac')?1)\n\t\t\t(im_subsample im (break rxfac')?0 (break ryfac')?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// upscale by any factor, bilinear\n\t\t= scale xfac' yfac' im,\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.BILINEAR\n\n\t\t// downscale by any factor, bilinear\n\t\t// block shrink by integer factor, then bilinear resample to \n\t\t// exact\n\t\t= scale (1 / (break rxfac')?1) (1 / (break ryfac')?1)\n\t\t\t(im_shrink im (break rxfac')?0 (break ryfac')?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tinterp == Interpolate.BILINEAR\n\n\t\t= error (\"resize: unimplemented argument combination:\\n\" ++ \n\t\t\t\"  xfac = \" ++ print xfac' ++ \"\\n\" ++\n\t\t\t\"  yfac = \" ++ print yfac' ++ \"\\n\" ++\n\t\t\t\"  interp = \" ++ print interp ++ \" (\" ++\n\t\t\t\tInterpolate.names.lookup 1 0 interp ++ \")\")\n\t{\n\t\t// convert a float scale to integer plus fraction\n\t\t// eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25)\n\t\tbreak f = [floor f, f / floor f];\n\n\t\t// binlinear resize\n\t\tscale xfac yfac im\n\t\t\t= im_affine im \n\t\t\t\txfac 0 0 yfac \n\t\t\t\t0 0 \n\t\t\t\t0 0 \n\t\t\t\t(rint (get_width im * xfac)) \n\t\t\t\t(rint (get_height im * yfac));\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(tone_analyse s m h sa ma ha)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Image @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (converse remainder base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (converse idiv base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\n\t\tidiv a b = (int) (a / b);\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c\n\t= wrap (map3 (map_trinary fn) a' b' c'), \n\t\tis_list a' && is_list b' && is_list c'\n\n\t= wrap (map2 (map_trinary fn a') b' c'), \n\t\tis_list b' && is_list c'\n\t= wrap (map2 (map_trinary (converse31 fn) b') a' c'), \n\t\tis_list a' && is_list c'\n\t= wrap (map2 (map_trinary (converse32 fn) c') a' b'), \n\t\tis_list a' && is_list b'\n\n\t= wrap (map (map_trinary fn a' b') c'), \n\t\tis_list c'\n\t= wrap (map (map_trinary (converse32 fn) a' c') b'), \n\t\tis_list b'\n\t= wrap (map (map_trinary (converse34 fn) b' c') a'), \n\t\tis_list a'\n\n\t= fn a b c\n{\n\tconverse31 fn a b c = fn b a c;\n\tconverse32 fn a b c = fn c a b;\n\tconverse33 fn a b c = fn a c b;\n\tconverse34 fn a b c = fn b c a;\n\n\ta'\n\t\t= a.value, is_Group a\n\t\t= a;\n\tb'\n\t\t= b.value, is_Group b\n\t\t= b;\n\tc'\n\t\t= c.value, is_Group c\n\t\t= c;\n\twrap\n\t\t= Group, is_Group a || is_Group b || is_Group c\n\t\t= id;\n}\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b\n\t= wrap (map2 (map_binary fn) a' b'), is_list a' && is_list b'\n\t= wrap (map (map_binary fn a') b'), is_list b'\n\t= wrap (map (map_binary (converse fn) b') a'), is_list a'\n\t= fn a b\n{\n\ta'\n\t\t= a.value, is_Group a\n\t\t= a;\n\tb'\n\t\t= b.value, is_Group b\n\t\t= b;\n\twrap\n\t\t= Group, is_Group a || is_Group b \n\t\t= id;\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a \n\t= wrap (map (map_unary fn) a'), is_list a'\n\t= fn a\n{\n\ta'\n\t\t= a.value, is_Group a\n\t\t= a;\n\twrap\n\t\t= Group, is_Group a\n\t\t= id;\n}\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. height]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Calculate padding ... pad up to tile_size pixel boundary.\n\t */\n\tsx = tile_width' + (width - width % hstep);\n\tsy = tile_height' + (height - height % vstep);\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. width]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n"
  },
  {
    "path": "share/nip2/compat/7.10/_types.def",
    "content": "\n/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0, 1, 2 or 3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_Matrix_width w \n\t= [is_Matrix_width, _ \"Matrix, \" ++ print w ++ _ \" columns\"]\n{\n\tis_Matrix_width x = is_Matrix x && x.width == w;\n}\ncheck_colour_space = [is_colour_space, \"colour_space\"];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide or VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down a bit.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n \t= check_args x.super, x.super != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// join two strings up with a separator string\n\tjoin_sep j a b = a ++ j ++ b;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad arguments to \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"usage\" ++ \"\\n\" ++ indent ++ usage ++ \"\\n\" ++ _ \"where\" ++ \"\\n\" ++ \n\t\targ_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make usage note\n\tusage = x.name ++ \" \" ++ \n\t\tfoldr (join_sep \" \") [] (map (extract 1) argcheck);\n\n\t// make arg type notes\n\targ_types = foldr (join_sep \"\\n\") [] (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = foldr (join_sep \"\\n\") [] all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n */\noo_binary'_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\top.symmetric && matches2 != []\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0,\n\t\tmatches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x \n\t\t= oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x \n\t\t= oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op \n\t\t= oo_unary_function (oo_unary_lookup op) this;\n\n\t/* Provide a fallback for class == thing ... just use pointer\n\t * equality.\n\t */\n\too_binary_table op x = [\n\t\t[pointer_equal this x,\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[not_pointer_equal this x,\n\t\t\top.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\"]\n\t];\n\too_unary_table op = [];\n}\n\n/* A list of things. Do automatic iteration of unary and binary operators on us.\n */\nGroup value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[this.Group (map2 (apply2 op) value x.value),\n\t\t\tis_Group x],\n\t\t[this.Group (map (apply2 op' x) value),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Group (map apply value),\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[if value then x?0 else x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n    oo_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real ... handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binary op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binary op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binary op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binary op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unary op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unary op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binary op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binary op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binary op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unary op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[len value == 3, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = im_header_int \"Type\" im;\n\t\tbands = im_header_int \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n    oo_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.value_name colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum Image_type.colour_spaces \"Colour space\" default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Compat. slider type.\n */\nSlider = Scale \"\";\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\nOption_enum enum caption value_name = class\n\tOption caption enum.names (index (equal value_name) enum.names) {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing value_name;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum enum caption (enum.names ? value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (map (extract col) value) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (map (extract from) value);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = map (extract 0) value;\n\tthings = map (extract 1) value;\n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tFOURIER = 24;\n\tYXY = 23;\n\tsRGB = 22;\n\tLABS = 21;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tLABQ = 16;\n\tCMYK = 15;\n\tCMC = 14;\n\tLAB = 13;\n\tXYZ = 12;\n\tLUT = 11;\n\tHISTOGRAM = 10;\n\tPOWER_SPECTRUM = 9;\n\tBLUE_ONLY = 8;\n\tGREEN_ONLY = 7;\n\tRED_ONLY = 6;\n\tYUV = 5;\n\tIR = 4;\n\tXRAY = 3;\n\tLUMINACE = 2;\n\tB_W = 1;\n\tMULTIBAND = 0;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t[\"FOURIER\", FOURIER],\n\t\t[\"YXY\", YXY],\n\t\t[\"sRGB\", sRGB],\n\t\t[\"LABS\", LABS],\n\t\t[\"LCH\", LCH],\n\t\t[\"UCS\", UCS],\n\t\t[\"RGB\", RGB],\n\t\t[\"LABQ\", LABQ],\n\t\t[\"CMYK\", CMYK],\n\t\t[\"CMC\", CMC],\n\t\t[\"LAB\", LAB],\n\t\t[\"XYZ\", XYZ],\n\t\t[\"LUT\", LUT],\n\t\t[\"HISTOGRAM\", HISTOGRAM],\n\t\t[\"POWER_SPECTRUM\", POWER_SPECTRUM],\n\t\t[\"BLUE_ONLY\", BLUE_ONLY],\n\t\t[\"GREEN_ONLY\", GREEN_ONLY],\n\t\t[\"RED_ONLY\", RED_ONLY],\n\t\t[\"YUV\", YUV],\n\t\t[\"IR\", IR],\n\t\t[\"XRAY\", XRAY],\n\t\t[\"LUMINACE\", LUMINACE],\n\t\t[\"B_W\", B_W],\n\t\t[\"MULTIBAND\", MULTIBAND]\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options generated from this, so match the order to the order in the\n\t * Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t[\"sRGB\", sRGB],\n\t\t[\"Lab\", LAB],\n\t\t[\"LCh\", LCH],\n\t\t[\"XYZ\", XYZ],\n\t\t[\"Yxy\", YXY],\n\t\t[\"UCS\", UCS]\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t[\"Mono\", B_W],\n\t\t[\"sRGB\", sRGB],\n\t\t[\"Lab\", LAB],\n\t\t[\"LabQ\", LABQ],\n\t\t[\"LabS\", LABS],\n\t\t[\"LCh\", LCH],\n\t\t[\"XYZ\", XYZ],\n\t\t[\"Yxy\", YXY],\n\t\t[\"UCS\", UCS]\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = im_header_double \"Xres\" value;\n\tyres = im_header_double \"Yres\" value;\n\txoffset = im_header_int \"Xoffset\" value;\n\tyoffset = im_header_int \"Yoffset\" value;\n\tfilename = im_header_string \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n        [wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// image ++ image is slightly different ... we want to\n\t\t// sizealike, but we must not bandalike\n        [wrap \n\t\t\t(op.fn (get_image resized?0) (get_image resized?1)),\n\t\t\thas_image x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n        [wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t// arithmetic and reational binops between image resize\n\t\t// and band_alike images to match\n\t\t[wrap \n\t\t\t(op.fn (get_image rebanded?0) (get_image rebanded?1)),\n\t\t\thas_image x &&\n\t\t\t(op.type == Operator_type.ARITHMETIC ||\n\t\t\t\top.type == Operator_type.RELATIONAL)],\n\t\t// other op types don't resize\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t[wrap (op.fn this.value x),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this ... only skip rewrap for COMPOUND\n\t\twrap\n\t\t\t= id, op.type == Operator_type.COMPOUND\n\t\t\t= this.Image;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\tthen_part = x?0;\n\t\telse_part = x?1;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x\n\t\t\t= x, is_image x\n\t\t\t= x.value, is_Image x\n\t\t\t= black + x\n\t\t{\n\t\t\tblack = im_black width height target_bands;\n\t\t}\n\n\t\tthen_image = to_image then_part;\n\t\telse_image = to_image else_part;\n\n\t\tthen_image' = clip2fmt target_format then_image;\n\t\telse_image' = clip2fmt target_format else_image;\n\n\t\tite_resized = size_alike [value, then_image', else_image'];\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if ite_resized?0 then ite_resized?1 else ite_resized?2);\n\n\t\tresized = size_alike [this, x];\n\t\trebanded = bands_alike resized;\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nInterpolate = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tnames = Enum [\n\t\t[_ \"Nearest neighbour\", NEAREST_NEIGHBOUR],\n\t\t[_ \"Bilinear\", BILINEAR],\n\t\t[_ \"Bicubic\", BICUBIC]\n\t];\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t[_ \"Perceptual\", PERCEPTUAL],\n\t\t[_ \"Relative\", RELATIVE],\n\t\t[_ \"Saturation\", SATURATION],\n\t\t[_ \"Absolute\", ABSOLUTE]\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n"
  },
  {
    "path": "share/nip2/compat/7.12/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t_L = default_value?0;\n\t\t\t_a = default_value?1;\n\t\t\t_b = default_value?2;\n\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum spaces (_ \"Convert to\") (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum spaces (_ \"Tag as\") (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Colour Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum Whitepoints (_ \"Old whitepoint\") \"D65\";\n\t\t\tnew_white = Option_enum Whitepoints (_ \"New whitepoint\") \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= monitor_profile, has_bands image && get_bands image == 3\n\t\t= print_profile;\n\trender_intents = Option_enum Render_intent.names (_ \"Render intent\") \n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure 0 0 in.width in.height \n\t\t\t\t\t(to_real pacross) (to_real pdown) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.12/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 1.5;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 50;\n\t\t\tfs = Scale \"Sharpen flat areas by\" (-2) 5 1;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" (-2) 5 2;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_convf, !separable && type == 1\n\t\t\t\t\t\t= im_convsepf, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 5) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height + 1) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width.expr window_height.expr in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale Blend\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image Blend\" \"use an image to blend two objects\" {\n\t\taction a b c \n\t\t\t\t= map_trinary process a b c\n\t\t{\n\t\t\tprocess a b c \n\t\t\t\t= blend condition in1 in2\n\t\t\t{\n\t\t\t\tcompare a b\n\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t= false, \n\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t= false, \n\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t= false,\n\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t= true;\n\t\t\t\targs' = sortc compare [a, b, c];\n\t\t\t\tcondition = args'?0;\n\t\t\t\tin1 = args'?1;\n\t\t\t\tin2 = args'?2;\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"_Alpha Blend\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\t\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t[\"Normal\", NORMAL],\n\t\t\t[\"If Lighter\", IFLIGHTER],\n\t\t\t[\"If Darker\", IFDARKER],\n\t\t\t[\"Multiply\", MULTIPLY],\n\t\t\t[\"Add\", ADD],\n\t\t\t[\"Subtract\", SUBTRACT],\n\t\t\t[\"Screen\", SCREEN],\n\t\t\t[\"Burn\", BURN],\n\t\t\t[\"Soft Light\", SOFTLIGHT],\n\t\t\t[\"Hard Light\", HARDLIGHT],\n\t\t\t[\"Lighten\", LIGHTEN],\n\t\t\t[\"Darken\", DARKEN],\n\t\t\t[\"Dodge\", DODGE],\n\t\t\t[\"Reflect\", REFLECT],\n\t\t\t[\"Freeze\", FREEZE],\n\t\t\t[\"Bitwise OR\", OR],\n\t\t\t[\"Bitwise AND\", AND]\n\t\t];\n\t\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum names \"Blend mode\" \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t\"Green over Red\",\n\t\t\t\"Blue over Red\",\n\t\t\t\"Red over Green\",\n\t\t\t\"Red over Blue\",\n\t\t\t\"Blue over Green\",\n\t\t\t\"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\targs = sortc (const (is_colour_type @ get_type)) [a, b];\n\t\t\t\tmono = args?0;\n\t\t\t\tcolour = args?1;\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t\t\"Grey\",\n\t\t\t\t\"Green over Red\",\n\t\t\t\t\"Blue over Red\",\n\t\t\t\t\"Red over Green\",\n\t\t\t\t\"Red over Blue\",\n\t\t\t\t\"Blue over Green\",\n\t\t\t\t\"Green over Blue\"\n\t\t\t] 0;\n\t\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_draw_line_item = class \n\tMenuaction \"Draw _Line\" \"draw a line using an arrow as a guide\" {\n}\n"
  },
  {
    "path": "share/nip2/compat/7.12/Format.def",
    "content": "Format_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nFormat_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nFormat_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nFormat_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nFormat_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list (or group) of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n\n#separator\n\nFormat_csv_import_item = class\n\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\taction = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpath = Pathname \"File to load\" \"empty\";\n\t\tstart_line = Expression \"Start at line\" 1;\n\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t_result\n\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t= Image (im_csv2vips filename)\n\t\t{\n\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\tescape x \n\t\t\t\t= foldr prefix [] x\n\t\t\t{\n\t\t\t\tprefix x l\n\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t= x : l;\n\t\t\t}\n\n\t\t\tblank = image_new 1 1 1 \n\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t0 0 0;\n\t\t}\n\t}\n}\n\n// interpret Analyze header for layout and calibration\nInterpret_header_item = class\n\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\"examine the Analyze header and set layout and value\" {\n\taction x \n\t\t= x'''\n\t{\n\t\t// read bits of header\n\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\tdim0 = dim 0 x;\n\t\tdim1 = dim 1 x;\n\t\tdim2 = dim 2 x;\n\t\tdim3 = dim 3 x;\n\t\tdim4 = dim 4 x;\n\t\tdim5 = dim 5 x;\n\t\tdim6 = dim 6 x;\n\t\tdim7 = dim 7 x;\n\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\n\t\t// oops, now a nop\n\t\tx' = x;\n\n\t\t// lay out higher dimensions width-ways\n\t\tx'' \n\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\tdim0 == 7\n\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\n\t\t// multiply by scale factor to get kBeq\n\t\tx''' = x'' * (cal_max / glmax);\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.12/Histogram.def",
    "content": "Hist_new_item = class\n\tMenuaction \"_New Histogram\" \"make a new histogram\" {\n\taction = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\tb = Scale \"Black point\"  0 100 0;\n\t\tw = Scale \"White point\"  0 100 100;\n\n\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t_result \n\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t{\n\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t}\n\t}\n}\n\nHist_new_from_matrix = Matrix_buildlut_item; \n\nHist_from_image_item = class\n\tMenuaction \"Ta_g Image As Histogram\" \"set image Type field to Histogram\" {\n\taction x = hist_tag x;\n}\n\n#separator\n\nHist_find_item = class \n\tMenupullright \"_Find Histogram\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map Histogram\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\targs = sortc (const is_hist) [a, b];\n\t\t\tim = args?0;\n\t\t\thist = args?1;\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Cumulativise Histogram\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate Histogram\" \n\t\t\"find point-to-point differences (inverse of Cumulativise)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise Histogram\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch Histogram\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\t// the line as a polar vector\n\t\t\t\tpv = polar (arrow.width, arrow.height);\n\t\t\t\ta = im pv;\n\n\t\t\t\t// smallest rotation that will make the line horizontal\n\t\t\t\ta'\n\t\t\t\t\t= 360 - a, a > 270\n\t\t\t\t\t= 180 - a, a > 90\n\t\t\t\t\t= -a;\n\n\t\t\t\tim' = rotate a' arrow.image;\n\n\t\t\t\t// look at the start and end of the arrow, pick the leftmost\n\t\t\t\tp\n\t\t\t\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t\t\t\t= (arrow.right, arrow.bottom);\n\n\t\t\t\t// transform that point to im' space\n\t\t\t\tp' = rectangular (polar p + (0, a')) + \n\t\t\t\t\t(im'.xoffset, im'.yoffset);\n\n\t\t\t\t// extract that area\n\t\t\t\tarea = extract_area \n\t\t\t\t\t(re p' + displace.value) \n\t\t\t\t\t(im p' - width.value / 2 + vdisplace.value) \n\t\t\t\t\t(re pv) width.value \n\t\t\t\t\tim';\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize 1 (1 / width.value) Interpolate.BILINEAR area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= area\n\t\t\t{\n\t\t\t\t// the line as a polar vector\n\t\t\t\tpv = polar (arrow.width, arrow.height);\n\t\t\t\ta = im pv;\n\n\t\t\t\t// smallest rotation that will make the line horizontal\n\t\t\t\ta'\n\t\t\t\t\t= 360 - a, a > 270\n\t\t\t\t\t= 180 - a, a > 90\n\t\t\t\t\t= -a;\n\n\t\t\t\tim' = rotate a' arrow.image;\n\n\t\t\t\t// look at the start and end of the arrow, pick the leftmost\n\t\t\t\tp\n\t\t\t\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t\t\t\t= (arrow.right, arrow.bottom);\n\n\t\t\t\t// transform that point to im' space\n\t\t\t\tp' = rectangular (polar p + (0, a')) + \n\t\t\t\t\t(im'.xoffset, im'.yoffset);\n\n\t\t\t\t// extract that area\n\t\t\t\tarea = extract_area \n\t\t\t\t\t(re p' + displace.value) \n\t\t\t\t\t(im p' - width.value / 2 + vdisplace.value) \n\t\t\t\t\t(re pv) width.value \n\t\t\t\t\tim';\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tformat = Option_enum Plot_format.names \"Format\" \"YYYY\";\n\t\tstyle = Option_enum Plot_style.names \"Style\" \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [[\"style\", style.value], [\"format\", format.value]] ++ range;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [[\"xmin\", xmin.expr], [\"xmax\", xmax.expr], \n\t\t\t\t\t[\"ymin\", ymin.expr], [\"ymax\", ymax.expr]]; \n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\textract_arrow arrow\n\t\t\t\t= extract_area (re p') (im p') (re pv) 1 im'\n\t\t\t{\n\t\t\t\t// the line as a polar vector\n\t\t\t\tpv = polar (arrow.width, arrow.height);\n\t\t\t\ta = im pv;\n\n\t\t\t\t// smallest rotation that will make the line horizontal\n\t\t\t\ta'\n\t\t\t\t\t= 360 - a, a > 270\n\t\t\t\t\t= 180 - a, a > 90\n\t\t\t\t\t= -a;\n\n\t\t\t\tim' = rotate a' arrow.image;\n\n\t\t\t\t// look at the start and end of the arrow, pick the leftmost\n\t\t\t\tp\n\t\t\t\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t\t\t\t= (arrow.right, arrow.bottom);\n\n\t\t\t\t// transform that point to im' space\n\t\t\t\tp' = rectangular (polar p + (0, a')) + \n\t\t\t\t\t(im'.xoffset, im'.yoffset);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.12/Image.def",
    "content": "Image_new_item = class \n\tMenupullright \"_New\" \"make new things\" {\n\tImage_black_item = class \n\t\tMenuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\t\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \n\t\t\t\tImage_type.type_names \"Image type\" \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\t\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\t\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\targs' = sortc compare [a, b];\n\t\t\t\t\ttarget = args'?0;\n\t\t\t\t\tx = args'?1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\n#separator\n\nImage_header_item = class \nMenupullright \"_Header\" \"do stuff to the image header\" {\n\nImage_get_item = class\nMenupullright \"_Get\" \"get header fields\" {\n\n// the header fields we can get\nfields = class {\n\ttype = 0;\n\twidth = 1;\n\theight = 2;\n\tformat = 3;\n\tbands = 4;\n\txres = 5;\n\tyres = 6;\n\txoffset = 7;\n\tyoffset = 8;\n\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t[\"width\", width],\n\t\t\t\t[\"height\", height],\n\t\t\t\t[\"bands\", bands],\n\t\t\t\t[\"format\", format],\n\t\t\t\t[\"type\", type],\n\t\t\t\t[\"xres\", xres],\n\t\t\t\t[\"yres\", yres],\n\t\t\t\t[\"xoffset\", xoffset],\n\t\t\t\t[\"yoffset\", yoffset],\n\t\t\t\t[\"coding\", coding]\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum field_names (_ \"Field\") name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum Image_type.type_names \"Image type\"\n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_number_format_item = class\n\tMenupullright \"Set _Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in = [\n\t\t\t\t\t\tin, \n\t\t\t\t\t\trot90 in,\n\t\t\t\t\t\trot180 in,\n\t\t\t\t\t\trot270 in\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x \n\t\t\t\t= map_unary straighten x\n\t\t\t{\n\t\t\t\tstraighten arrow\n\t\t\t\t\t= rotate angle'' arrow.image\n\t\t\t\t{\n\t\t\t\t\tx = arrow.width;\n\t\t\t\t\ty = arrow.height;\n\t\n\t\t\t\t\tangle = im (polar (x, y));\n\t\n\t\t\t\t\tangle'\n\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t= angle;\n\t\n\t\t\t\t\tangle''\n\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\t_interp = Option_enum Interpolate.names \"Interpolation\" \"Bilinear\";\n\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tinterp = _interp;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize xfactor yfactor interp.value_thing image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\tinterp = _interp;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize fac fac interp.value_thing image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor = max_pair xfac yfac;\n\t\t\t\t\t\tmin_factor = min_pair xfac yfac;\n\t\t\t\t\t\tfac = [max_factor, min_factor, xfac, yfac]?which;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\"\n\t\t\t(map (extract 0) Interpolate.names.value) Interpolate.BILINEAR;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_transform {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t_result = transform_search max_err max_iter order interp wrap\n\t\t\t\t\t\tsample reference;\n\n\t\t\t\ttransformed_image = Image _result?0;\n\t\t\t\t_transform = Transform _result?1 \n\t\t\t\t\treference.width reference.height;\n\t\t\t\tfinal_error = _result?2;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\targs = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\ti = args?0;\n\t\t\t\t\t\tt = args?1;\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldr1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find the image geometry ... don't bother trying to look\n\t\t// inside groups though\n\t\t_geo\n\t\t\t= x.rect, is_Image x\n\t\t\t= Rect 0 0 100 100;\n\n\t\tl = Expression \"Crop left\" ((int) (_geo.left + _geo.width / 4));\n\t\tt = Expression \"Crop top\" ((int) (_geo.top + _geo.height / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (_geo.width / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (_geo.height / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands, \n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t_sorted = sortc _pred [a, b];\n\t\t\t_a' = _sorted?0;\n\t\t\t_b' = _sorted?1;\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tGaussian_item = class \n\t\tMenuaction \"Gaussian _Noise\" \"make an image of gaussian noise\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t_result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) \n\t\t\t\tmean.value deviation.value);\n\t\t}\n\t}\n\n\tFractal_item = class \n\t\tMenuaction \"_Fractal\" \"make a fractal image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t}\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n    Colour_atlas_item = class\n        Menuaction \"_Colour Atlas\"\n            \"make a grid of patches grouped around a colour\" {\n        action = class \n            _result {   \n            _vislevel = 3;\n       \n            start = Colour_picker \"Lab\" [50,0,0];\n            nstep = Expression \"Number of steps\" 2;\n            ssize = Expression \"Step size\" 2; \n\n            _result\n                = Image (colour_transform_to (get_type start) im)\n            {\n                base = colour_transform_to Image_type.LAB start;\n                step = to_real ssize;\n                offset = to_real nstep * step;\n                range c = [c - offset, c - offset + step ... c + offset]; \n                                \n                mk_patch b a = image_new 150 150 3\n                    Image_format.FLOAT Image_coding.NOCODING \n                    Image_type.LAB (Vector [base?0, a, b]) 0 0;\n\n                mk_strip b = map (mk_patch b) (range base?1);\n                mk_grid = map mk_strip (range base?2);\n                im = imagearray_assemble 15 15 mk_grid;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.12/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/7.12\n\nstart_DATA = \\\n\tMath.def \\\n\tImage.def \\\n\tColour.def \\\n\tTasks.def \\\n\tFormat.def \\\n\tFilter.def \\\n\tMatrix.def \\\n\tWidgets.def \\\n\tHistogram.def \\\n\tPreferences.ws \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_convert.def \\\n\t_generate.def \\\n\t_list.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\t_types.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/7.12/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_And\" \"bitwise and of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_Or\" \"bitwise or of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"E_xclusive Or\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_Not\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBand_or_item = class \n\t\tMenuaction \"Band O_r\" \"or the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_or @ bandsplit) im;\n\t}\n\n\tBand_and_item = class \n\t\tMenuaction \"Band A_nd\" \"and the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_and @ bandsplit) im;\n\t}\n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \"position of centre of gravity\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\t// from s15.2, p 665 NR in C\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = class {\n\t\t\t_vislevel = 3;\n\n\t\t\t/* Hide these by default.\n\t\t\t */\n\t\t\tdetails = class {\n\t\t\t\t\tss = len xes;\n\t\t\t\t\tsx = sum xes;\n\t\t\t\t\tsy = sum yes;\n\t\t\t\t\tsxoss = sx / ss;\n\n\t\t\t\t\tt = map (converse subtract sxoss) xes;\n\t\t\t\t\tst2 = sum (map (converse power 2) t);\n\t\t\t}\n\n\t\t\tslope = sum (map2 multiply details.t yes) / details.st2;\n\t\t\tintercept = (details.sy - details.sx * slope) / details.ss;\n\n\t\t\tchi2 = sum \n\t\t\t\t(map (converse power 2)\n\t\t\t\t\t\t(map2 subtract\n\t\t\t\t\t\t\t\t(map (converse subtract intercept) yes) \n\t\t\t\t\t\t\t\t(map (multiply slope) xes)));\n\n\t\t\tsiga = (chi2 / (details.ss - 2)) ** 0.5 * \n\t\t\t\t((1 + details.sx ** 2 / \n\t\t\t\t(details.ss * details.st2)) / details.ss) ** 0.5;\n\t\t\tsigb = (chi2 / (details.ss - 2)) ** 0.5 * \n\t\t\t\t(1 / details.st2) ** 0.5;\n\n\t\t\tq = 1.0;\n\t\t}\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = class {\n\t\t\t_vislevel = 3;\n\n\t\t\t/* Hide these by default.\n\t\t\t */\n\t\t\tdetails = class {\n\t\t\t\twt = map (converse power (-0.5)) devs;\n\n\t\t\t\tss = sum wt;\n\t\t\t\tsx = sum (map2 multiply xes wt);\n\t\t\t\tsy = sum (map2 multiply yes wt);\n\t\t\t\tsxoss = sx / ss;\n\n\t\t\t\tt = map2 divide (map (converse subtract sxoss) xes) devs;\n\t\t\t\tst2 = sum (map (converse power 2) t);\n\t\t\t}\n\n\t\t\tslope = sum (map2 divide (map2 multiply details.t yes) devs) /\n\t\t\t\tdetails.st2;\n\t\t\tintercept = (details.sy - details.sx * slope) / details.ss;\n\n\t\t\tsiga = ((1 + details.sx * details.sx / \n\t\t\t\t(details.ss * details.st2)) / details.ss) ** 0.5;\n\t\t\tsigb = (1 / details.st2) ** 0.5;\n\n\t\t\tchi2 = sum \n\t\t\t\t(map (converse power 2)\n\t\t\t\t\t(map2 divide\n\t\t\t\t\t\t(map2 subtract\n\t\t\t\t\t\t\t\t(map (converse subtract intercept) yes) \n\t\t\t\t\t\t\t\t(map (multiply slope) xes))\n\t\t\t\t\t\tdevs));\n\t\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.12/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 (converse join_tb) (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 (converse join_lr) (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 (converse join_tb) (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 (converse join_lr) (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [[\"style\", Plot_style.POINT], \n\t\t\t\t\t[\"format\", Plot_format.XYYY]] ++ range;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [[\"xmin\", xmin.expr], [\"xmax\", xmax.expr], \n\t\t\t\t\t[\"ymin\", ymin.expr], [\"ymax\", ymax.expr]]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.12/Preferences.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/7.12.0\">\n  <Workspace filename=\"/home/john/CVS_DEVEL/nip2-7.11/share/nip2/start/Preferences.ws\" view=\"WORKSPACE_MODE_NOEDIT\" scale=\"1\" offset=\"0\" window_width=\"680\" window_height=\"1159\">\n    <Column x=\"0\" y=\"2799\" open=\"false\" selected=\"false\" sform=\"false\" next=\"99\" name=\"B\" caption=\"Interface column -- don't touch this!\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"WINDOW_INFRONT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E27.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CSV_SEPARATOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"O1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PRINT_CARTIESIAN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F10.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_PANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"237\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"788\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"700\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_PANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"-1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RELOAD\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D42.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_STATUSBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR_STYLE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MATRIX_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_RECOMP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"N2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_MAX_UNDO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[-1,0,1,5,10]?N1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_FONT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"N4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_INTERLACE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_LINELENGTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D41.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A6.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE_FILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PPM_MODE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"G1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_LAYOUT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C16.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C18.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_MULTI_RES\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_FORMAT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_PREDICTOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_START\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D25.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_SEARCH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D2.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_TMP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_SLIDER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D28.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_REGION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D29.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_AUTO_WS_SAVE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D30.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_DISPLAY_LED\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLKITBROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_MAX_HEAP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D38.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PIN_FILESEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_STATUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CONVERSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_RULERS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CROSSHAIR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_FADE_STEPS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E21.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_TRACE_FUNCTIONS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"H1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_DEVICE\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CHANNEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_BRIGHTNESS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_COLOUR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CONTRAST\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_HUE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_FRAMES\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J13.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_MONO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J14.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_LEFT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_TOP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_ASPECT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_MAX_BLEND_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_REFINE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_WINDOW_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_OBJECT_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_BALANCE_GAMMA\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"680\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"480\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER_REMOTE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"POPUP_NEW_ROWS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_HISTORY_MAX\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D43.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_CPUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D44.value\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2581\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"I\" caption=\"Mosaic defaults\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Maximum blend width&quot; 0 100 10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Refine tie-points&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search windows this size&quot; 30\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search for objects this size&quot; 10\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Image gamma for mosaic balance&quot; 1 3 1.6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2272\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"J\" caption=\"Video for linux\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"J2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;Device&quot; &quot;/dev/video&quot;\"/>\n            <Pathname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Channel&quot; [&quot;TV&quot;, &quot;Composite 1&quot;, &quot;Composite 2&quot;, &quot;Composite 3&quot;] 1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Brightness&quot; 0 32767 23000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Colour&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Contrast&quot; 0 32767 27000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Hue&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Number of frames to average&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Grab monochrome&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2014\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"K\" caption=\"General video capture\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"K1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Crop video: \" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Crop video&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop left&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop top&quot; 6\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number  &quot;Crop width&quot; 747\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop height&quot; 570\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Aspect ratio (stretch vertically\\nby this much)&quot; 1.202\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1887\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"M\" caption=\"PNG save options\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"M1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Compression&quot; (map print [0..9]) 6\"/>\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Interlace&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1790\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"G\" caption=\"PPM/PGM/PBM save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"PPM mode\" labelsn=\"2\" labels0=\"Binary\" labels1=\"ASCII\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Mode&quot; [&quot;Binary&quot;, &quot;ASCII&quot;] 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1508\" open=\"true\" selected=\"false\" sform=\"false\" next=\"25\" name=\"C\" caption=\"TIFF save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Compression&quot; [&quot;None&quot;, &quot;LZW&quot;, &quot;Zip (deflate)&quot;, &quot;PACKBITS&quot;, &quot;JPEG&quot;, &quot;CCITTFAX4&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;JPEG quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n\t    <iText formula=\"Option &quot;Deflate/LZW predictor&quot; [&quot;None&quot;,&quot;Horizontal difference&quot;,&quot;Floating-point&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Layout&quot; [&quot;Strip&quot;, &quot;Tile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile width&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile height&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Multi-res&quot; [&quot;Single image&quot;, &quot;Image pyramid&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Format&quot; [&quot;No truncation&quot;,&quot;Save 1 band 8 bit images as 1 bit&quot;] 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1226\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"A\" caption=\"JPEG save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;ICC profile&quot; [&quot;Use embedded profile, if available&quot;, &quot;Embed profile from file&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Pathname/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;ICC profile file&quot; &quot;$VIPSHOME/share/nip2/data/sRGB.icm&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1039\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"F\" caption=\"Widgets\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Pin up file requestors&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Main window toolbar&quot; [&quot;Default style&quot;, &quot;Icon only&quot;, &quot;Text only&quot;, &quot;Icon and text&quot;, &quot;Icon and text to right&quot;] 0\"/>\n            <Option caption=\"Main window toolbar\" labelsn=\"5\" labels0=\"Default style\" labels1=\"Icon only\" labels2=\"Text only\" labels3=\"Icon and text\" labels4=\"Icon and text to right\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display LEDs in workspace&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display complex numbers as coordinates&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"943\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"H\" caption=\"Debug options\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Disassemble functions\" value=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;untitled&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"815\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"L\" caption=\"Help browser\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"L2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Command to start browser&quot; &quot;firefox&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Go-to-page argument&quot; &quot;-remote 'openURL(%s)'&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"657\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"N\" caption=\"Paintbox \">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Max undo steps\" labelsn=\"5\" labels0=\"Unlimited\" labels1=\"None\" labels2=\"1\" labels3=\"5\" labels4=\"10\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Max undo steps&quot; [&quot;Unlimited&quot;, &quot;None&quot;, &quot;1&quot;, &quot;5&quot;, &quot;10&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Fontname &quot;Default paintbox font&quot; &quot;Sans 12&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Fontname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update during paint&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"407\" open=\"true\" selected=\"false\" sform=\"false\" next=\"26\" name=\"E\" caption=\"Image display\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"E20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use crosshair cursor in image windows&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Fade tiles in this many steps&quot; 10\"/>\n            <Number caption=\"Fade tiles in this many steps\" value=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Thumbnail size&quot; 64\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window width&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window height&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto image window pop up&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E27\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Keep child windows in front of parents&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"45\" name=\"D\" caption=\"Calculation\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Data path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;data&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;data&quot;], &quot;.&quot;]\"/>\n            <Expression caption=\"Data path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Temporary files&quot; (path_relative [&quot;$SAVEDIR&quot;, &quot;tmp&quot;])\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Start path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;start&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;start&quot;]]\"/>\n            <Expression caption=\"Start path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D28\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update sliders during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update sliders during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D29\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update regions during drag\" value=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update regions during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D30\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto workspace save&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D42\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto-reload on file change&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D41\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Text display length (characters)&quot; 80\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D38\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Heap size (per workspace)&quot; 600000\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D43\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of VIPS functions to memoise&quot; 10000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D44\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of CPUs to use&quot; 1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1384\" open=\"true\" selected=\"true\" sform=\"false\" next=\"4\" name=\"O\" caption=\"CSV save\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"String &quot;Separator character&quot; &quot;\\t&quot;\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/compat/7.12/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\targs = sortc larger [a, b];\n\t\t\t\t\timage = args?0;\n\t\t\t\t\tpatch = args?1;\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = im_measure image.value 0 0 image.width image.height 6 4;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb = Matrix (map2 cons _true_grey_Y' _camera_grey');\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\tlinearising_lut = Image _linear_lut;\n\n\t\t\t// map the original image through the lineariser to \n\t\t\t// get linear 0-1 RGB image\n\t\t\t_image' = hist_map linearising_lut.value image.value;\n\n\t\t\t// remeasure and solve for RGB -> XYZ\n\t\t\t_camera' = im_measure _image' 0 0 image.width image.height 6 4;\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\tM = transpose (_pinv * transpose _camera' * _true_XYZ);\n\n\t\t\t// convert linear RGB camera to Lab \n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tcast_float @\n\t\t\t\trecomb M) _image';\n\n\t\t\t// measure again and compute dE76\n\t\t\t_camera'' = im_measure _result.value 0 0 \n\t\t\t\timage.width image.height 6 4;\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tfinal_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b \n\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t{\n\t\t\t// the name of the calib object we need\n\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t// get the Calibrate_chart arg first\n\t\t\targs = sortc (const (is_instanceof calib_name)) [a, b];\n\t\t\tcalib = args?1;\n\t\t\timage = args?0;\n\n\t\t\t// map the original image through the lineariser to get \n\t\t\t// linear 0-1 RGB image\n\t\t\timage' = hist_map calib.linearising_lut image;\n\n\t\t\t// convert linear RGB camera to Lab \n\t\t\tresult = colour_transform Image_type.XYZ Image_type.LAB \n\t\t\t\t((float) (recomb calib.M image'));\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum Plot_style.names \"Style\" \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [[\"style\", style.value]] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[[\"ymin\", ymin.expr], [\"ymax\", ymax.expr]]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\tlen images != 2 \n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = land (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\tsorted = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t\ta' = sorted?0;\n\t\t\t\tb' = sorted?1;\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\tsorted = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t\ta' = sorted?0;\n\t\t\t\tb' = sorted?1;\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\tsorted = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t\ta' = sorted?0;\n\t\t\t\t\tb' = sorted?1;\n\t\t\t\t\tc' = sorted?2;\n\t\t\t\t\td' = sorted?3;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\tsorted = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t\ta' = sorted?0;\n\t\t\t\t\tb' = sorted?1;\n\t\t\t\t\tc' = sorted?2;\n\t\t\t\t\td' = sorted?3;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize xfactor yfactor 1 scale_im;\n\t\t\t_offset_im = resize xfactor yfactor 1 offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.12/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.12/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && len x == 3\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The innermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x && !contains_Group x\n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), len parts != 2\n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, len parts != 4\n\t= (ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", member \".0123456789\",\n\t\tmember \"eE\", member \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), len parts != 5\n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t[\"D93\", D93_whitepoint],\n\t[\"D75\", D75_whitepoint],\n\t[\"D65\", D65_whitepoint],\n\t[\"D55\", D55_whitepoint],\n\t[\"D50\", D50_whitepoint],\n\t[\"A\", A_whitepoint],\n\t[\"B\", B_whitepoint],\n\t[\"C\", C_whitepoint],\n\t[\"E\", E_whitepoint],\n\t[\"D3250\", D3250_whitepoint]\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, im_8216],\n\t[RGB, GREY16, im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, RGB16, im_8216],\n\t[sRGB, GREY16, im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* Given a list of things, try to make them all the same size. Don't change\n * the format. Don't touch non-image things.\n */\nsize_alike l\n\t= map enlarge l\n{\n\tmax_width = foldr (test_prop has_width get_width) 0 l;\n\tmax_height = foldr (test_prop has_height get_height) 0 l;\n\n\ttest_prop has get x best\n\t\t= best, !has x\n\t\t= max_pair best (get x);\n\n\tenlarge x\n\t\t= embed 0 0 0 max_width max_height x, has_width x\n\t\t= x;\n}\n\n/* Given a list of things, look for 1 band objects and bump them to to n -\n * band objects, where n is the maximum number of bands. Don't change the \n * format. Don't touch non-image things.\n */\nbands_alike l\n\t= map upband l\n{\n\tmax_bands = foldr (test_prop has_bands get_bands) 0 l;\n\n\ttest_prop has get x best\n\t\t= best, !has x\n\t\t= max_pair best (get x);\n\n\tupband x\n\t\t= bandjoin (replicate max_bands x),\n\t\t\thas_bands x && get_bands x == 1\n\t\t= x;\n}\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ path_separator ++ b;\n}\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 == 2 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n"
  },
  {
    "path": "share/nip2/compat/7.12/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black (to_real w) (to_real h) (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = Matrix_con mask_g_sum 0 [mask_g_line]\n{\n        mask_g = im_gauss_imask (radius / 3) 0.2;\n        mask_g_line = mask_g.value?(mask_g.height / 2);\n        mask_g_sum = sum mask_g_line;\n}\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.12/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = class\n\t\t\t\t{\n\t\t\t\tscale_factor = Expression \"scale the size of the frame by\" 1;\n\n\t\t\t\t/* These sliders define the fraction of the frames width or height is extracted\n\t\t \t\t * to produce each of the particular regions.\n\t\t \t\t */\n\t\t\t\tcorner_section = Scale \"Corner section\" 0.1 1 0.5;\n\t\t\t\tmiddle_section = Scale \"Middle section\" 0.1 1 0.2;\n\t\t\t\tblend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n\t\t\t\t}\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = class\n\t\t\t\t{\n\t\t\t\tapply = Toggle \"Apply mount options\" false;\n\t\t\t\tls = Expression \"Lower mount section bigger by (cm)\" 0;\n\t\t\t\tmount_colour = Colour _type [0, 0, 0];\n\t\t\t\t_los = ls.expr * ppcm.expr;\n\t\t\t\t}\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize _sf _sf Interpolate.BILINEAR a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\n\t\t\tvariables = class\n\t\t\t\t{\n\t\t\t\tscale_factor = Expression \"scale the size of the frame by\" 1;\n\n\t\t\t\t/* These sliders define the fraction of the frames width or height that\n\t\t\t\t * is extracted to produce each of the particular regions.\n\t\t \t\t */\n\t\t\t\tcorner_section = Scale \"Corner section\" 0.1 1 0.5;\n\t\t\t\tmiddle_section = Scale \"Middle section\" 0.1 1 0.2;\n\t\t\t\tblend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n\t\t\t\toption = Toggle \"Use mirror of left-side to make right\" true;\n\t\t\t\t}\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = class\n\t\t\t\t{\n\t\t\t\tapply = Toggle \"Apply mount options\" false;\n\t\t\t\tls = Expression \"Lower mount section bigger by (cm)\" 0;\n\t\t\t\tmount_colour = Colour _type [0, 0, 0];\n\t\t\t\t_los = ls.expr * ppcm.expr;\n\t\t\t\t}\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize _sf _sf Interpolate.BILINEAR a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\n\t\t\tvariables = class\n\t\t\t\t{\n\t\t\t\tscale_factor = Expression \"scale the size of the frame by\" 1;\n\n\t\t\t\t/* These sliders define the fraction of the frames width or height is extracted\n\t\t \t\t * to produce each of the particular regions.\n\t\t \t\t */\n\t\t\t\tcorner_section = Scale \"Corner section\" 0.1 1 0.5;\n\t\t\t\tedge_section = Scale \"Edge section\" 0.1 1 0.2;\n\t\t\t\tmiddle_section = Scale \"Middle section\" 0.1 1 0.2;\n\t\t\t\tblend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n\t\t\t\toption = Toggle \"Use mirror of left-side to make right\" true;\n\t\t\t\t}\n\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = class\n\t\t\t\t{\n\t\t\t\tapply = Toggle \"Apply mount color\" false;\n\t\t\t\tls = Expression \"Lower mount section bigger by (cm)\" 0;\n\t\t\t\tcolour = Colour _type [0, 0, 0];\n\t\t\t\t_los = ls.expr * ppcm.expr;\n\t\t\t\t}\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize _sf _sf Interpolate.BILINEAR a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" ] 6;\n\n\n\tcontrol_selection mask im no\n\t\t= (if mask then im * 1.2 else im * 1), no == 0\n\t\t= (if mask then im * 0.8 else im * 1), no == 1\n\t\t= (if mask then 0 else im), no == 2\n\t\t= (if mask then 255 else im), no == 3\n\t\t= (if mask then im else 0), no == 4\n\t\t= (if mask then im else 255), no == 5\n\t\t= mask;\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = a.image;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = ((pt_list.value)?0).image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\t};\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize f1 f2 1 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize f1 1 1 b1\n\t\t\t\t\t{b1 = resize 1 f2 1 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/7.12/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\t\t\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\t\t\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t}\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\t\t\n\t\t\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t}\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = line.image;\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\t\t\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = (pt_l?0).image;\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t}\n\n\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t}\n"
  },
  {
    "path": "share/nip2/compat/7.12/_list.def",
    "content": "/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn (tl l), fn (hd l)\n\t= l;\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st (hd l)) (tl l);\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn (hd l) (tl l);\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn (hd l) (foldr fn st (tl l));\n\n/* foldrl fn l: like foldr, but use the 1st element as the start value\n *\n * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= foldr fn (hd l) (tl l);\n\nsum = foldr1 add;\n\nproduct = foldr1 multiply;\n\n/* Search a list for an element, returning it's index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn (hd l)\n\t\t= search (tl l) (n + 1);\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= hd l : init (tl l);\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* land l: and all the elements of list l together\n *\n * land (map (==0) list) == true, if every element of list is zero.\n * land :: [bool] -> bool\n */\nland = foldr logical_and true;\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= hd l, tl l == []\n\t= last (tl l);\n\n/* len l: length of list l\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta = l?0;\n\tb = l?1;\n\tx = tl (tl l);\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* lor l: or all the elements of list l together\n *\n * lor (map (equal 0) list) == true, if any element of list is zero.\n * lor :: [bool] -> bool\n */\nlor = foldr logical_or false;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = lor (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge b l r\n\t= [], b == [] || l == [] || r == []\n\t= hd l : merge (tl b) (tl l) (tl r), hd b\n\t= hd r : merge (tl b) (tl l) (tl r);\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta = hd l;\n\tx = tl l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scan fn st l: apply (fold fn r) to every initial segment of a list\n *\n * scan add 0 [1,2,3] == [1,3,6]\n * scan :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscan fn \n\t= g \n{\n\tg st l\n\t\t= [st], l == []\n\t\t= st : g (fn st (hd l)) (tl l);\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta = hd l1;\n\t\tx = tl l1;\n\t\tb = hd l2;\n\t\ty = tl l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/7.12/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = lor (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && land (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, land (map is_obj l)\n\t= true, land (map is_list l) &&\n\t\tland (map (not @ is_obj) l) &&\n\t\tland (map is_rectangular l) &&\n\t\tlen l > 0 &&\n\t\tland (map (equal (hd lengths)) (tl lengths))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n\tlengths = map len l;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && len l == len (hd l);\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && land (map xy l)\n{\n\txy l = is_real_list l && len l == 2;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && lor (map is_Group l)\n\t= lor (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= error (\"get_type: unable to get type from \" ++ print x)\n{\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= type, bands == 1 && type == Image_type.GREY16\n\t\t= type, type == Image_type.HISTOGRAM && (width == 1 || height == 1)\n\t\t= Image_type.B_W, bands == 1\n\t\t= type, bands == 3 && is_colorimetric\n\t\t= Image_type.sRGB, bands == 3 && !is_colorimetric\n\t\t= Image_type.MULTIBAND, bands != 3 && !is_colorimetric\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= error (\"get_format: unable to get format from \" ++ print x);\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= error (\"get_bits: unable to get bits from \" ++ print x);\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= error (\"get_bands: unable to get bands from \" ++ print x);\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= error (\"get_coding: unable to get coding from \" ++ print x);\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= error (\"get_xres: unable to get xres from \" ++ print x);\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= error (\"get_yres: unable to get yres from \" ++ print x);\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= error (\"get_xoffset: unable to get xoffset from \" ++ print x);\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= error (\"get_yoffset: unable to get yoffset from \" ++ print x);\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= error (\"get_image: unable to get image from \" ++ print x);\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= error (\"get_number: unable to get number from \" ++ print x);\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= error (\"get_real: unable to get real from \" ++ print x);\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= error (\"get_width: unable to get width from \" ++ print x);\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= error (\"get_height: unable to get height from \" ++ print x);\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= error (\"get_left: unable to get left from \" ++ print x);\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= error (\"get_top: unable to get top from \" ++ print x);\n\n// like has/get member,but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.12/_stdenv.def",
    "content": "/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error \"unimplemented vector operation\"\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined,\n\t\thas_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\ttotals = sum_sum2_list l;\n\t\tn = totals?0;\n\t\ts = totals?1;\n\t\ts2 = totals?2;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\tn = sofar?0;\n\t\t\ts = sofar?1;\n\t\t\ts2 = sofar?2;\n\n\t\t\tsub_acc = sum_sum2_list x;\n\n\t\t\tn' = sub_acc?0;\n\t\t\ts' = sub_acc?1;\n\t\t\ts2' = sub_acc?2;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\ttotals = sum_sum2_list l;\n\t\tn = totals?0;\n\t\ts = totals?1;\n\t\ts2 = totals?2;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\tn = sofar?0;\n\t\t\ts = sofar?1;\n\t\t\ts2 = sofar?2;\n\n\t\t\tsub_acc = sum_sum2_list x;\n\n\t\t\tn' = sub_acc?0;\n\t\t\ts' = sub_acc?1;\n\t\t\ts2' = sub_acc?2;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_cache x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (converse cons [] @ converse subscript x') obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\")\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\tthen_part = x?0;\n\t\telse_part = x?1;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x\n\t\t\t= x, is_image x\n\t\t\t= x.value, is_Image x\n\t\t\t= black + x\n\t\t{\n\t\t\tblack = im_black target_width target_height target_bands;\n\t\t}\n\n\t\tthen_image = to_image then_part;\n\t\telse_image = to_image else_part;\n\n\t\tthen_image' = clip2fmt target_format then_image;\n\t\telse_image' = clip2fmt target_format else_image;\n\n\t\tresized = size_alike [cond, then_image', else_image'];\n\n\t\tblend_result_image = image_set_type target_type\n\t\t\t(im_blend resized?0 resized?1 resized?2);\n\t}\n}\n\ninsert x y small big\n\t= oo_binary_function insert_op small big, is_class small\n\t= oo_binary'_function insert_op small big, is_class big\n\t= im_insert rebanded?1 rebanded?0 (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n\n\trebanded = bands_alike [small, big];\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand rebanded?1 rebanded?0 (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n\n\trebanded = bands_alike [small, big];\n}\n\nmeasure x y w h u v image\n\t= oo_unary_function measure_op image, is_class image\n\t= im_measure image \n\t\t(to_real x) (to_real y) (to_real w) (to_real h)\n\t\t(to_real u) (to_real v), \n\t\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"measure\")\n{\n\tmeasure_op = Operator \"measure\" \n\t\t(measure x y w h u v) Operator_type.COMPOUND_REWRAP false;\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_similarity image (cos angle) (sin angle) 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\trotate Operator_type.COMPOUND_REWRAP false;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join a b\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin Operator_type.COMPOUND_REWRAP false;\n\n\tjoin a b\n\t\t= join_im a b, is_image a && is_image b \n\t\t= matrix_binary join_im a b,\n\t\t\tis_matrix a && is_matrix b \n\t\t= error (_ \"bad arguments to \" ++ \"join_lr\");\n\n\tjoin_im a b\t= insert (get_width b) 0 a b;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join a b\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin Operator_type.COMPOUND_REWRAP false;\n\n\tjoin a b\n\t\t= join_im a b, is_image a && is_image b \n\t\t= matrix_binary join_im a b,\n\t\t\tis_matrix a && is_matrix b \n\t\t= error (_ \"bad arguments to \" ++ \"join_tb\");\n\n\tjoin_im a b\t= insert 0 (get_height b) a b;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\timage = (unsigned char) im_mask2vips (Matrix m2);\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsepf image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h = conv (Matrix [[-1, 1]]) h;\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= lhisteq image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n\n\t// loop over bands, if necessary\n\tlhisteq im\n\t\t= im_lhisteq im (to_real w) (to_real h), get_bands im == 1\n\t\t= (foldl1 join @ map lhisteq @ bandsplit) im;\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nresize xfac yfac interp image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// upscale by any factor, nearest neighbour \n\t\t// can't really do this right ... upscale by integer part, then\n\t\t// bilinear to exact size\n\t\t= scale xg?1 yg?1 (im_zoom im xg?0 yg?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// downscale by any factor, nearest neighbour \n\t\t// can't really do this right ... downscale by integer part, \n\t\t// then bilinear to exact size\n\t\t= scale xs?1 ys?1 (im_subsample im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// upscale by any factor, bilinear\n\t\t= scale xfac' yfac' im,\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.BILINEAR\n\n\t\t// downscale by any factor, bilinear\n\t\t// block shrink by integer factor, then bilinear resample to \n\t\t// exact\n\t\t= scale xs?1 ys?1 (im_shrink im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tinterp == Interpolate.BILINEAR\n\n\t\t= error (\"resize: unimplemented argument combination:\\n\" ++ \n\t\t\t\"  xfac = \" ++ print xfac' ++ \"\\n\" ++\n\t\t\t\"  yfac = \" ++ print yfac' ++ \"\\n\" ++\n\t\t\t\"  interp = \" ++ print interp ++ \" (\" ++\n\t\t\t\tInterpolate.names.lookup 1 0 interp ++ \")\")\n\t{\n\t\t// convert a float scale to integer plus fraction\n\t\t// eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25)\n\t\tbreak f = [floor f, f / floor f];\n\n\t\t// same, but for downsizing ... turn a float scale which is less than\n\t\t// 1 into an int shrink and a float scale\n\n\t\t// complicated: the int shrink may round the size down (eg. imagine\n\t\t// subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide\n\t\t// image, not a 3.666 pixel wide image), so pass in the size of image\n\t\t// we are operating on and adjust for any rounding\n\t\t\n\t\t// so ... x is (eg.) 467, f is (eg. 128/467, about 0.274)\n\t\trbreak x f \n\t\t\t= [int_shrink, float_resample]\n\t\t{\n\t\t\t// the size of image we are aiming for after the combined int and\n\t\t\t// float resample\n\t\t\tx' = x * f;\n\n\t\t\t// int part\n\t\t\tint_shrink = floor (1 / f);\n\n\t\t\t// size after int shrink\n\t\t\tx'' = floor (x / int_shrink);\n\n\t\t\t// therefore what we need for the float part\n\t\t\tfloat_resample = x' / x'';\n\t\t}\n\n\t\twidth = get_width im;\n\t\theight = get_height im;\n\n\t\t// grow and shrink factors\n\t\txg = break xfac';\n\t\tyg = break yfac';\n\t\txs = rbreak width xfac';\n\t\tys = rbreak height yfac';\n\n\t\t// binlinear resize\n\t\tscale xfac yfac im\n\t\t\t= im_affine im \n\t\t\t\txfac 0 0 yfac \n\t\t\t\t0 0 \n\t\t\t\t0 0 \n\t\t\t\t(rint (get_width im * xfac)) \n\t\t\t\t(rint (get_height im * yfac));\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nflood_blob x y v image\n\t= oo_unary_function flood_blob_op image, is_class image\n\t= im_flood_blob_copy image \n\t\t(to_real x) (to_real y) v, \n\t\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"flood_blob\")\n{\n\tflood_blob_op = Operator \"flood_blob\" \n\t\t(flood_blob x y v) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (converse remainder base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (converse idiv base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\n\t\tidiv a b = (int) (a / b);\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= [], lor (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == [];\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Image (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && len x?0 > 1\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n"
  },
  {
    "path": "share/nip2/compat/7.12/_types.def",
    "content": "\n/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0, 1, 2 or 3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \"colour_space\"];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide or VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down a bit.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n \t= check_args x.super, x.super != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// join two strings up with a separator string\n\tjoin_sep j a b = a ++ j ++ b;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad arguments to \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"usage\" ++ \"\\n\" ++ indent ++ usage ++ \"\\n\" ++ _ \"where\" ++ \"\\n\" ++ \n\t\targ_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make usage note\n\tusage = x.name ++ \" \" ++ \n\t\tfoldr (join_sep \" \") [] (map (extract 1) argcheck);\n\n\t// make arg type notes\n\targ_types = foldr (join_sep \"\\n\") [] (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = foldr (join_sep \"\\n\") [] all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n */\noo_binary'_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\top.symmetric && matches2 != []\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0,\n\t\tmatches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x \n\t\t= oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x \n\t\t= oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op \n\t\t= oo_unary_function (oo_unary_lookup op) this;\n\n\t/* Provide a fallback for class == thing ... just use pointer\n\t * equality.\n\t */\n\too_binary_table op x = [\n\t\t[pointer_equal this x,\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[not_pointer_equal this x,\n\t\t\top.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\"]\n\t];\n\too_unary_table op = [];\n}\n\n/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t]\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t]\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary ((converse op.fn) x) this,\n\t\t\ttrue]\n\t]\n\t{\n\t\t// need ite as a true trinary\n\t\tite a b c = if a then b else c;\n\n\t\t// we can't call map_trinary directly, since it uses Group and we\n\t\t// don't support mutually recursive top-level functions :-(\n\t\t// copy-paste it here, keep in sync with the version in _stdenv\n\t\tmap_nary fn args\n\t\t\t= fn args, groups == []\n\t\t\t= Group (map process [0, 1 .. shortest - 1])\n\t\t{\n\t\t\tgroups = filter is_Group args;\n\n\t\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\t\tprocess n\n\t\t\t\t= [], lor (map (is_noval n) args)\n\t\t\t\t= map_nary fn (map (extract n) args)\n\t\t\t{\n\t\t\t\textract n arg\n\t\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t\t= arg;\n\n\t\t\t\tis_noval n arg = is_Group arg && arg.value?n == [];\n\t\t\t}\n\t\t}\n\n\t\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\t\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\t\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\t}\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t]\n\t{\n\t\t// we can't call map_trinary directly, since it uses Group and we\n\t\t// don't support mutually recursive top-level functions :-(\n\t\t// copy-paste it here, keep in sync with the version in _stdenv\n\t\tmap_nary fn args\n\t\t\t= fn args, groups == []\n\t\t\t= Group (map process [0, 1 .. shortest - 1])\n\t\t{\n\t\t\tgroups = filter is_Group args;\n\n\t\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\t\tprocess n\n\t\t\t\t= [], lor (map (is_noval n) args)\n\t\t\t\t= map_nary fn (map (extract n) args)\n\t\t\t{\n\t\t\t\textract n arg\n\t\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t\t= arg;\n\n\t\t\t\tis_noval n arg = is_Group arg && arg.value?n == [];\n\t\t\t}\n\t\t}\n\n\t\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\t}\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t];\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t];\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t];\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t];\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t];\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[len value == 3, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.value_name colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum Image_type.colour_spaces \"Colour space\" default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\nOption_enum enum caption value_name = class\n\tOption caption enum.names (index (equal value_name) enum.names) {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing value_name;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum enum caption (enum.names ? value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (map (extract col) value) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (map (extract from) value);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = map (extract 0) value;\n\tthings = map (extract 1) value;\n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tLUMINANCE = 2;\n\tXRAY = 3;\n\tIR = 4;\n\tYUV = 5;\n\tRED_ONLY = 6;\n\tGREEN_ONLY = 7;\n\tBLUE_ONLY = 8;\n\tPOWER_SPECTRUM = 9;\n\tHISTOGRAM = 10;\n\tLUT = 11;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMC = 14;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t[\"MULTIBAND\", MULTIBAND],\n\t\t[\"B_W\", B_W],\n\t\t[\"LUMINANCE\", LUMINANCE],\n\t\t[\"XRAY\", XRAY],\n\t\t[\"IR\", IR],\n\t\t[\"YUV\", YUV],\n\t\t[\"RED_ONLY\", RED_ONLY],\n\t\t[\"GREEN_ONLY\", GREEN_ONLY],\n\t\t[\"BLUE_ONLY\", BLUE_ONLY],\n\t\t[\"POWER_SPECTRUM\", POWER_SPECTRUM],\n\t\t[\"HISTOGRAM\", HISTOGRAM],\n\t\t[\"LUT\", LUT],\n\t\t[\"XYZ\", XYZ],\n\t\t[\"LAB\", LAB],\n\t\t[\"CMC\", CMC],\n\t\t[\"CMYK\", CMYK],\n\t\t[\"LABQ\", LABQ],\n\t\t[\"RGB\", RGB],\n\t\t[\"UCS\", UCS],\n\t\t[\"LCH\", LCH],\n\t\t[\"LABS\", LABS],\n\t\t[\"sRGB\", sRGB],\n\t\t[\"YXY\", YXY],\n\t\t[\"FOURIER\", FOURIER],\n\t\t[\"RGB16\", RGB16],\n\t\t[\"GREY16\", GREY16]\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options generated from this, so match the order to the order in the\n\t * Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t[\"sRGB\", sRGB],\n\t\t[\"Lab\", LAB],\n\t\t[\"LCh\", LCH],\n\t\t[\"XYZ\", XYZ],\n\t\t[\"Yxy\", YXY],\n\t\t[\"UCS\", UCS]\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t[\"Mono\", B_W],\n\t\t[\"sRGB\", sRGB],\n\t\t[\"RGB16\", RGB16],\n\t\t[\"GREY16\", GREY16],\n\t\t[\"Lab\", LAB],\n\t\t[\"LabQ\", LABQ],\n\t\t[\"LabS\", LABS],\n\t\t[\"LCh\", LCH],\n\t\t[\"XYZ\", XYZ],\n\t\t[\"Yxy\", YXY],\n\t\t[\"UCS\", UCS]\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// image ++ image is slightly different ... we want to\n\t\t// sizealike, but we must not bandalike\n\t\t[wrap \n\t\t\t(op.fn (get_image resized?0) (get_image resized?1)),\n\t\t\thas_image x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t// arithmetic and reational binops between image resize\n\t\t// and band_alike images to match\n\t\t[wrap \n\t\t\t(op.fn (get_image rebanded?0) (get_image rebanded?1)),\n\t\t\thas_image x &&\n\t\t\t(op.type == Operator_type.ARITHMETIC ||\n\t\t\t\top.type == Operator_type.RELATIONAL)],\n\t\t// other op types don't resize\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \"Image v ==\n\t\t// 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\tthen_part = x?0;\n\t\telse_part = x?1;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x\n\t\t\t= x, is_image x\n\t\t\t= x.value, is_Image x\n\t\t\t= black + x\n\t\t{\n\t\t\tblack = im_black width height target_bands;\n\t\t}\n\n\t\tthen_image = to_image then_part;\n\t\telse_image = to_image else_part;\n\n\t\tthen_image' = clip2fmt target_format then_image;\n\t\telse_image' = clip2fmt target_format else_image;\n\n\t\tite_resized = size_alike [value, then_image', else_image'];\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if ite_resized?0 then ite_resized?1 else ite_resized?2);\n\n\t\tresized = size_alike [this, x];\n\t\trebanded = bands_alike resized;\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t]\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nInterpolate = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tnames = Enum [\n\t\t[_ \"Nearest neighbour\", NEAREST_NEIGHBOUR],\n\t\t[_ \"Bilinear\", BILINEAR],\n\t\t[_ \"Bicubic\", BICUBIC]\n\t];\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t[_ \"Perceptual\", PERCEPTUAL],\n\t\t[_ \"Relative\", RELATIVE],\n\t\t[_ \"Saturation\", SATURATION],\n\t\t[_ \"Absolute\", ABSOLUTE]\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t[_ \"Point\", POINT],\n\t\t[_ \"Line\", LINE],\n\t\t[_ \"Spline\", SPLINE],\n\t\t[_ \"Bar\", BAR]\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t[_ \"YYYY\", YYYY],\n\t\t[_ \"XYYY\", XYXY],\n\t\t[_ \"XYXY\", XYXY]\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [[\"format\", Plot_format.XYYY]] value {\n}\n"
  },
  {
    "path": "share/nip2/compat/7.14/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t[_L, _a, _b] = default_value;\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum spaces (_ \"Convert to\") (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum spaces (_ \"Tag as\") (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Colour Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum Whitepoints (_ \"Old whitepoint\") \"D65\";\n\t\t\tnew_white = Option_enum Whitepoints (_ \"New whitepoint\") \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= monitor_profile, has_bands image && get_bands image == 3\n\t\t= print_profile;\n\trender_intents = Option_enum Render_intent.names (_ \"Render intent\") \n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure 0 0 in.width in.height \n\t\t\t\t\t(to_real pacross) (to_real pdown) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.14/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 1.5;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 50;\n\t\t\tfs = Scale \"Sharpen flat areas by\" (-2) 5 1;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" (-2) 5 2;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_convf, !separable && type == 1\n\t\t\t\t\t\t= im_convsepf, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 5) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height + 1) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width.expr window_height.expr in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\nFilter_greyc_item = class \n\tMenupullright \"_GREYCstoration\" \"noise-removing filter\" {\n\tDenoise_item = class \n\t\tMenuaction \"Denoise\" \"Noise-removing filter\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\titerations = Scale \"Iterations\" 1 5 1;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 40;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.9;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.15;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.6;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.1;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) x;\n\t\t}\n\t}\n\n\tEnlarge_item = class\n\t\tMenuaction \"Enlarge\" \"Enlarge image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Enlarge\" 1 10 3;\n\t\t\titerations = Scale \"Iterations\" 1 5 3;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 20;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.2;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.9;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.1;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.5;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) \n\t\t\t\t\t(resize (to_real scale) (to_real scale) \n\t\t\t\t\t\tInterpolate.BILINEAR x);\n\t\t}\n\t}\n\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image\" \"use an image to blend two objects\" {\n\t\taction a b c = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ti = Toggle \"Invert mask\" false;\n\n\t\t\t_result \n\t\t\t\t= map_trinary process a b c\n\t\t\t{\n\t\t\t\tprocess a b c \n\t\t\t\t\t= blend condition in1 in2, !i\n\t\t\t\t\t= blend (invert condition) in1 in2\n\t\t\t\t{\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t\t= false,\n\t\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t\t= true;\n\t\t\t\t\t[condition, in1, in2] = sortc compare [a, b, c];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"_Alpha\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\t\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t[_ \"Normal\", NORMAL],\n\t\t\t[_ \"If Lighter\", IFLIGHTER],\n\t\t\t[_ \"If Darker\", IFDARKER],\n\t\t\t[_ \"Multiply\", MULTIPLY],\n\t\t\t[_ \"Add\", ADD],\n\t\t\t[_ \"Subtract\", SUBTRACT],\n\t\t\t[_ \"Screen\", SCREEN],\n\t\t\t[_ \"Burn\", BURN],\n\t\t\t[_ \"Soft Light\", SOFTLIGHT],\n\t\t\t[_ \"Hard Light\", HARDLIGHT],\n\t\t\t[_ \"Lighten\", LIGHTEN],\n\t\t\t[_ \"Darken\", DARKEN],\n\t\t\t[_ \"Dodge\", DODGE],\n\t\t\t[_ \"Reflect\", REFLECT],\n\t\t\t[_ \"Freeze\", FREEZE],\n\t\t\t[_ \"Bitwise OR\", OR],\n\t\t\t[_ \"Bitwise AND\", AND]\n\t\t];\n\t\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum names \"Blend mode\" \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\t[mono, colour] = \n\t\t\t\t\tsortc (const (is_colour_type @ get_type)) [a, b];\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t\t_ \"Grey\",\n\t\t\t\t_ \"Green over Red\",\n\t\t\t\t_ \"Blue over Red\",\n\t\t\t\t_ \"Red over Green\",\n\t\t\t\t_ \"Red over Blue\",\n\t\t\t\t_ \"Blue over Green\",\n\t\t\t\t_ \"Green over Blue\"\n\t\t\t] 0;\n\t\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t_ \"North-west\",\n\t\t\t\t_ \"North\",\n\t\t\t\t_ \"North-east\",\n\t\t\t\t_ \"West\",\n\t\t\t\t_ \"Centre\",\n\t\t\t\t_ \"East\",\n\t\t\t\t_ \"South-west\",\n\t\t\t\t_ \"South\",\n\t\t\t\t_ \"South-east\",\n\t\t\t\t_ \"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_draw_line_item = class \n\tMenuaction \"Draw _Line\" \"draw a line using an arrow as a guide\" {\n}\n"
  },
  {
    "path": "share/nip2/compat/7.14/Histogram.def",
    "content": "Hist_new_item = class\n\tMenupullright \"_New\" \"new histogram\" {\n\tHist_item = class\n\t\tMenuaction \"Histogram\" \"make an identity histogram\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\t_result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d);\n\t\t}\n\t}\n\n\tHist_new_from_matrix = Matrix_buildlut_item; \n\n\tHist_from_image_item = class\n\t\tMenuaction \"Ta_g Image As Histogram\" \"set image Type field to Histogram\" {\n\t\taction x = hist_tag x;\n\t}\n\n\tTone_item = class \n\t\tMenuaction \"_Tone Curve\" \"make a new tone mapping curve\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\t_result \n\t\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t\t{\n\t\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_find_item = class \n\tMenupullright \"_Find\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map Histogram\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\t[im, hist] = sortc (const is_hist) [a, b];\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Cumulativise Histogram\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate Histogram\" \n\t\t\"find point-to-point differences (inverse of Cumulativise)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise Histogram\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch Histogram\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\t// the line as a polar vector\n\t\t\t\tpv = polar (arrow.width, arrow.height);\n\t\t\t\ta = im pv;\n\n\t\t\t\t// smallest rotation that will make the line horizontal\n\t\t\t\ta'\n\t\t\t\t\t= 360 - a, a > 270\n\t\t\t\t\t= 180 - a, a > 90\n\t\t\t\t\t= -a;\n\n\t\t\t\tim' = rotate a' arrow.image;\n\n\t\t\t\t// look at the start and end of the arrow, pick the leftmost\n\t\t\t\tp\n\t\t\t\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t\t\t\t= (arrow.right, arrow.bottom);\n\n\t\t\t\t// transform that point to im' space\n\t\t\t\tp' = rectangular (polar p + (0, a')) + \n\t\t\t\t\t(im'.xoffset, im'.yoffset);\n\n\t\t\t\t// extract that area\n\t\t\t\tarea = extract_area \n\t\t\t\t\t(re p' + displace.value) \n\t\t\t\t\t(im p' - width.value / 2 + vdisplace.value) \n\t\t\t\t\t(re pv) width.value \n\t\t\t\t\tim';\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize 1 (1 / width.value) Interpolate.BILINEAR area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= area\n\t\t\t{\n\t\t\t\t// the line as a polar vector\n\t\t\t\tpv = polar (arrow.width, arrow.height);\n\t\t\t\ta = im pv;\n\n\t\t\t\t// smallest rotation that will make the line horizontal\n\t\t\t\ta'\n\t\t\t\t\t= 360 - a, a > 270\n\t\t\t\t\t= 180 - a, a > 90\n\t\t\t\t\t= -a;\n\n\t\t\t\tim' = rotate a' arrow.image;\n\n\t\t\t\t// look at the start and end of the arrow, pick the leftmost\n\t\t\t\tp\n\t\t\t\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t\t\t\t= (arrow.right, arrow.bottom);\n\n\t\t\t\t// transform that point to im' space\n\t\t\t\tp' = rectangular (polar p + (0, a')) + \n\t\t\t\t\t(im'.xoffset, im'.yoffset);\n\n\t\t\t\t// extract that area\n\t\t\t\tarea = extract_area \n\t\t\t\t\t(re p' + displace.value) \n\t\t\t\t\t(im p' - width.value / 2 + vdisplace.value) \n\t\t\t\t\t(re pv) width.value \n\t\t\t\t\tim';\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tformat = Option_enum Plot_format.names \"Format\" \"YYYY\";\n\t\tstyle = Option_enum Plot_style.names \"Style\" \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => style.value, $format => format.value] ++ range;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\textract_arrow arrow\n\t\t\t\t= extract_area (re p') (im p') (re pv) 1 im'\n\t\t\t{\n\t\t\t\t// the line as a polar vector\n\t\t\t\tpv = polar (arrow.width, arrow.height);\n\t\t\t\ta = im pv;\n\n\t\t\t\t// smallest rotation that will make the line horizontal\n\t\t\t\ta'\n\t\t\t\t\t= 360 - a, a > 270\n\t\t\t\t\t= 180 - a, a > 90\n\t\t\t\t\t= -a;\n\n\t\t\t\tim' = rotate a' arrow.image;\n\n\t\t\t\t// look at the start and end of the arrow, pick the leftmost\n\t\t\t\tp\n\t\t\t\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t\t\t\t= (arrow.right, arrow.bottom);\n\n\t\t\t\t// transform that point to im' space\n\t\t\t\tp' = rectangular (polar p + (0, a')) + \n\t\t\t\t\t(im'.xoffset, im'.yoffset);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.14/Image.def",
    "content": "Image_new_item = class \n\tMenupullright \"_New\" \"make new things\" {\n\tImage_black_item = class \n\t\tMenuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \n\t\t\t\tImage_type.type_names \"Image type\" \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region on image using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\t[target, x] = sortc compare [a, b];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\nImage_number_format_item = class\n\tMenupullright \"_Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_header_item = class \n\tMenupullright \"_Header\" \"do stuff to the image header\" {\n\n\tImage_get_item = class\n\t\tMenupullright \"_Get\" \"get header fields\" {\n\n\t\t// the header fields we can get\n\t\tfields = class {\n\t\t\ttype = 0;\n\t\t\twidth = 1;\n\t\t\theight = 2;\n\t\t\tformat = 3;\n\t\t\tbands = 4;\n\t\t\txres = 5;\n\t\t\tyres = 6;\n\t\t\txoffset = 7;\n\t\t\tyoffset = 8;\n\t\t\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t$width => width,\n\t\t\t\t$height => height,\n\t\t\t\t$bands => bands,\n\t\t\t\t$format => format,\n\t\t\t\t$type => type,\n\t\t\t\t$xres => xres,\n\t\t\t\t$yres => yres,\n\t\t\t\t$xoffset => xoffset,\n\t\t\t\t$yoffset => yoffset,\n\t\t\t\t$coding => coding\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum field_names (_ \"Field\") name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum Image_type.type_names \"Image type\"\n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in = [\n\t\t\t\t\t\tin, \n\t\t\t\t\t\trot90 in,\n\t\t\t\t\t\trot180 in,\n\t\t\t\t\t\trot270 in\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x \n\t\t\t\t= map_unary straighten x\n\t\t\t{\n\t\t\t\tstraighten arrow\n\t\t\t\t\t= rotate angle'' arrow.image\n\t\t\t\t{\n\t\t\t\t\tx = arrow.width;\n\t\t\t\t\ty = arrow.height;\n\t\n\t\t\t\t\tangle = im (polar (x, y));\n\t\n\t\t\t\t\tangle'\n\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t= angle;\n\t\n\t\t\t\t\tangle''\n\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\t_interp = Option_enum Interpolate.names \"Interpolation\" \"Bilinear\";\n\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tinterp = _interp;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize xfactor yfactor interp.value_thing image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\tinterp = _interp;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize fac fac interp.value_thing image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor = max_pair xfac yfac;\n\t\t\t\t\t\tmin_factor = min_pair xfac yfac;\n\t\t\t\t\t\tfac = [max_factor, min_factor, xfac, yfac]?which;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\"\n\t\t\t(map (extract 0) Interpolate.names.value) Interpolate.BILINEAR;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_trn {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t[sample', trn, err] = transform_search \n\t\t\t\t\tmax_err max_iter order interp wrap\n\t\t\t\t\tsample reference;\n\t\t\t\ttransformed_image = Image sample';\n\t\t\t\t_trn = Transform trn reference.width reference.height;\n\t\t\t\tfinal_error = err;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\t[i, t] = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tBandwise_item = Image_join_item.Bandwise_item;\n\n    sep1 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldr1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find the image geometry ... don't bother trying to look\n\t\t// inside groups though\n\t\t_geo\n\t\t\t= x.rect, is_Image x\n\t\t\t= Rect 0 0 100 100;\n\n\t\tl = Expression \"Crop left\" ((int) (_geo.left + _geo.width / 4));\n\t\tt = Expression \"Crop top\" ((int) (_geo.top + _geo.height / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (_geo.width / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (_geo.height / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands, \n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t[_a', _b'] = sortc _pred [a, b];\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tGaussian_item = class \n\t\tMenuaction \"Gaussian _Noise\" \"make an image of gaussian noise\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t_result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) \n\t\t\t\tmean.value deviation.value);\n\t\t}\n\t}\n\n\tFractal_item = class \n\t\tMenuaction \"_Fractal\" \"make a fractal image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t}\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n    Colour_atlas_item = class\n        Menuaction \"_Colour Atlas\"\n            \"make a grid of patches grouped around a colour\" {\n        action = class \n            _result {   \n            _vislevel = 3;\n       \n            start = Colour_picker \"Lab\" [50,0,0];\n            nstep = Expression \"Number of steps\" 2;\n            ssize = Expression \"Step size\" 2; \n\n            _result\n                = Image (colour_transform_to (get_type start) im)\n            {\n                base = colour_transform_to Image_type.LAB start;\n                step = to_real ssize;\n                offset = to_real nstep * step;\n                range c = [c - offset, c - offset + step ... c + offset]; \n                                \n                mk_patch b a = image_new 150 150 3\n                    Image_format.FLOAT Image_coding.NOCODING \n                    Image_type.LAB (Vector [base?0, a, b]) 0 0;\n\n                mk_strip b = map (mk_patch b) (range base?1);\n                mk_grid = map mk_strip (range base?2);\n                im = imagearray_assemble 15 15 mk_grid;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.14/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/7.14\n\nstart_DATA = \\\n\tMath.def \\\n\tImage.def \\\n\tColour.def \\\n\tTasks.def \\\n\tObject.def \\\n\tFilter.def \\\n\tMatrix.def \\\n\tWidgets.def \\\n\tHistogram.def \\\n\tPreferences.ws \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_convert.def \\\n\t_generate.def \\\n\t_list.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\t_Object.def \\\n\t_types.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/7.14/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_And\" \"bitwise and of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_Or\" \"bitwise or of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"E_xclusive Or\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_Not\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBand_or_item = class \n\t\tMenuaction \"Band O_r\" \"or the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_or @ bandsplit) im;\n\t}\n\n\tBand_and_item = class \n\t\tMenuaction \"Band A_nd\" \"and the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_and @ bandsplit) im;\n\t}\n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \"position of centre of gravity\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = linreg xes yes;\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = linregw xes yes devs;\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.14/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 (converse join_tb) (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 (converse join_lr) (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 (converse join_tb) (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 (converse join_lr) (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ \n\t\t\t\t\trange;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.14/Object.def",
    "content": "Object_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nObject_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nObject_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nObject_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nObject_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list (or group) of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.14/Preferences.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/7.14.0\">\n  <Workspace filename=\"Preferences.ws\" view=\"WORKSPACE_MODE_NOEDIT\" scale=\"1\" offset=\"0\" window_width=\"680\" window_height=\"1159\">\n    <Column x=\"0\" y=\"2799\" open=\"false\" selected=\"false\" sform=\"false\" next=\"99\" name=\"B\" caption=\"Interface column -- don't touch this!\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"CSV_SEPARATOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"O1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PRINT_CARTIESIAN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F10.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_PANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"237\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"788\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"700\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"100\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RELOAD\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D42.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_STATUSBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR_STYLE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MATRIX_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_RECOMP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"N2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_MAX_UNDO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[-1,0,1,5,10]?N1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_FONT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"N4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_INTERLACE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_LINELENGTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D41.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A6.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE_FILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PPM_MODE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"G1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_LAYOUT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C16.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C18.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_MULTI_RES\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_FORMAT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_PREDICTOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_START\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D25.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_SEARCH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D2.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_TMP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_SLIDER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D28.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_REGION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D29.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_AUTO_WS_SAVE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D30.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_DISPLAY_LED\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLKITBROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_MAX_HEAP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D38.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PIN_FILESEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_STATUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CONVERSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_RULERS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CROSSHAIR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_FADE_STEPS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E21.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_TRACE_FUNCTIONS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"H1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_DEVICE\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CHANNEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_BRIGHTNESS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_COLOUR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CONTRAST\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_HUE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_FRAMES\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J13.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_MONO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J14.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_LEFT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_TOP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_ASPECT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_MAX_BLEND_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_REFINE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_WINDOW_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_OBJECT_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_BALANCE_GAMMA\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"680\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"480\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER_REMOTE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"POPUP_NEW_ROWS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_HISTORY_MAX\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D43.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_CPUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D44.value\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2581\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"I\" caption=\"Mosaic defaults\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Maximum blend width&quot; 0 100 10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Refine tie-points&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search windows this size&quot; 30\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search for objects this size&quot; 10\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Image gamma for mosaic balance&quot; 1 3 1.6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2272\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"J\" caption=\"Video for linux\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"J2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;Device&quot; &quot;/dev/video&quot;\"/>\n            <Pathname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Channel&quot; [&quot;TV&quot;, &quot;Composite 1&quot;, &quot;Composite 2&quot;, &quot;Composite 3&quot;] 1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Brightness&quot; 0 32767 23000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Colour&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Contrast&quot; 0 32767 27000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Hue&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Number of frames to average&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Grab monochrome&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2014\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"K\" caption=\"General video capture\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"K1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Crop video: \" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Crop video&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop left&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop top&quot; 6\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number  &quot;Crop width&quot; 747\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop height&quot; 570\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Aspect ratio (stretch vertically\\nby this much)&quot; 1.202\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1887\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"M\" caption=\"PNG save options\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"M1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Compression&quot; (map print [0..9]) 6\"/>\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Interlace&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1790\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"G\" caption=\"PPM/PGM/PBM save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"PPM mode\" labelsn=\"2\" labels0=\"Binary\" labels1=\"ASCII\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Mode&quot; [&quot;Binary&quot;, &quot;ASCII&quot;] 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1508\" open=\"true\" selected=\"false\" sform=\"false\" next=\"25\" name=\"C\" caption=\"TIFF save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Compression&quot; [&quot;None&quot;, &quot;LZW&quot;, &quot;Zip (deflate)&quot;, &quot;PACKBITS&quot;, &quot;JPEG&quot;, &quot;CCITTFAX4&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;JPEG quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n\t    <iText formula=\"Option &quot;Deflate/LZW predictor&quot; [&quot;None&quot;,&quot;Horizontal difference&quot;,&quot;Floating-point&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Layout&quot; [&quot;Strip&quot;, &quot;Tile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile width&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile height&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Multi-res&quot; [&quot;Single image&quot;, &quot;Image pyramid&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Format&quot; [&quot;No truncation&quot;,&quot;Save 1 band 8 bit images as 1 bit&quot;] 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1226\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"A\" caption=\"JPEG save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;ICC profile&quot; [&quot;Use embedded profile, if available&quot;, &quot;Embed profile from file&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Pathname/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;ICC profile file&quot; &quot;$VIPSHOME/share/nip2/data/sRGB.icm&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1039\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"F\" caption=\"Widgets\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Pin up file requestors&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Main window toolbar&quot; [&quot;Default style&quot;, &quot;Icon only&quot;, &quot;Text only&quot;, &quot;Icon and text&quot;, &quot;Icon and text to right&quot;] 0\"/>\n            <Option caption=\"Main window toolbar\" labelsn=\"5\" labels0=\"Default style\" labels1=\"Icon only\" labels2=\"Text only\" labels3=\"Icon and text\" labels4=\"Icon and text to right\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display LEDs in workspace&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display complex numbers as coordinates&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"943\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"H\" caption=\"Debug options\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Disassemble functions\" value=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;untitled&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"815\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"L\" caption=\"Help browser\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"L2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Command to start browser&quot; &quot;firefox&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Go-to-page argument&quot; &quot;-remote 'openURL(%s)'&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"657\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"N\" caption=\"Paintbox \">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Max undo steps\" labelsn=\"5\" labels0=\"Unlimited\" labels1=\"None\" labels2=\"1\" labels3=\"5\" labels4=\"10\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Max undo steps&quot; [&quot;Unlimited&quot;, &quot;None&quot;, &quot;1&quot;, &quot;5&quot;, &quot;10&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Fontname &quot;Default paintbox font&quot; &quot;Sans 12&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Fontname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update during paint&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"407\" open=\"true\" selected=\"false\" sform=\"false\" next=\"26\" name=\"E\" caption=\"Image display\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"E20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use crosshair cursor in image windows&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Fade tiles in this many steps&quot; 10\"/>\n            <Number caption=\"Fade tiles in this many steps\" value=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Thumbnail size&quot; 64\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window width&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window height&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto image window pop up&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"45\" name=\"D\" caption=\"Calculation\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Data path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;data&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;data&quot;], &quot;.&quot;]\"/>\n            <Expression caption=\"Data path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Temporary files&quot; (path_relative [&quot;$SAVEDIR&quot;, &quot;tmp&quot;])\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Start path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;start&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;start&quot;]]\"/>\n            <Expression caption=\"Start path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D28\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update sliders during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update sliders during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D29\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update regions during drag\" value=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update regions during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D30\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto workspace save&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D42\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto-reload on file change&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D41\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Text display length (characters)&quot; 80\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D38\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Heap size (per workspace)&quot; 600000\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D43\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of VIPS functions to memoise&quot; 20000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D44\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of CPUs to use&quot; 1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1384\" open=\"true\" selected=\"true\" sform=\"false\" next=\"4\" name=\"O\" caption=\"CSV save\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"String &quot;Separator character&quot; &quot;\\t&quot;\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/compat/7.14/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\n\tCsv_import_item = class\n\t\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tstart_line = Expression \"Start at line\" 1;\n\t\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_csv2vips filename)\n\t\t\t{\n\t\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\t\tescape x \n\t\t\t\t\t= foldr prefix [] x\n\t\t\t\t{\n\t\t\t\t\tprefix x l\n\t\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t\t= x : l;\n\t\t\t\t}\n\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// interpret Analyze header for layout and calibration\n\tAnalyze7_header_item = class\n\t\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\t\"examine the Analyze header and set layout and value\" {\n\t\taction x \n\t\t\t= x'''\n\t\t{\n\t\t\t// read bits of header\n\t\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\t\tdim0 = dim 0 x;\n\t\t\tdim1 = dim 1 x;\n\t\t\tdim2 = dim 2 x;\n\t\t\tdim3 = dim 3 x;\n\t\t\tdim4 = dim 4 x;\n\t\t\tdim5 = dim 5 x;\n\t\t\tdim6 = dim 6 x;\n\t\t\tdim7 = dim 7 x;\n\t\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\t\n\t\t\t// oops, now a nop\n\t\t\tx' = x;\n\t\n\t\t\t// lay out higher dimensions width-ways\n\t\t\tx'' \n\t\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\t\tdim0 == 7\n\t\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\t\n\t\t\t// multiply by scale factor to get kBeq\n\t\t\tx''' = x'' * (cal_max / glmax);\n\t\t}\n\t}\n\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\t[image, patch] = sortc larger [a, b];\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\tmode = Option \"Input LUT\" [\n\t\t\t\t\"Linear input\",\n\t\t\t\t\"Fit intercept from chart greyscale\",\n\t\t\t\t\"Linearize input from chart greyscale\"\n\t\t\t] 2;\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = measure 0 0 image.width image.height 6 4 image.value;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb \n\t\t\t\t= Matrix [[0, 0], [1, 1]], mode == 0\n\t\t\t\t= Matrix [0: intercepts, replicate (_camera.width + 1) 1], \n\t\t\t\t\tmode == 1\n\t\t\t\t= Matrix (map2 cons _true_grey_Y' _camera_grey')\n\t\t\t{\n\t\t\t\tintercepts = [(linreg _true_grey_Y' cam).intercept :: \n\t\t\t\t\tcam <- transpose _camera_grey'];\n\t\t\t}\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\t// plot from 0 explicitly so we see the effect of mode1 (intercept\n\t\t\t// from greyscale)\n\t\t\tlinearising_lut = Plot [$ymin => 0] _linear_lut;\n\n\t\t\t// map the original image through the lineariser to \n\t\t\t// get linear 0-1 RGB image\n\t\t\t_image' = hist_map linearising_lut.value image.value;\n\n\t\t\t// remeasure and solve for RGB -> XYZ\n\t\t\t_camera' = im_measure _image' 0 0 image.width image.height 6 4;\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\tM = transpose (_pinv * transpose _camera' * _true_XYZ);\n\n\t\t\t// convert linear RGB camera to Lab \n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tcast_float @\n\t\t\t\trecomb M) _image';\n\n\t\t\t// measure again and compute dE76\n\t\t\t_camera'' = im_measure _result.value 0 0 \n\t\t\t\timage.width image.height 6 4;\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tfinal_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0 && i < len macbeth_names\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b = class\n\t\t\t(map_binary process a b) {\n\t\t\tprocess a b\n\t\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t\t{\n\t\t\t\t// the name of the calib object we need\n\t\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t\t// get the Calibrate_chart arg first\n\t\t\t\t[image, calib] = sortc (const (is_instanceof calib_name)) \n\t\t\t\t\t[a, b];\n\n\t\t\t\t// map the original image through the lineariser to get \n\t\t\t\t// linear 0-1 RGB image\n\t\t\t\timage' = hist_map calib.linearising_lut image;\n\n\t\t\t\t// convert linear RGB camera to Lab \n\t\t\t\tresult = colour_transform Image_type.XYZ Image_type.LAB \n\t\t\t\t\t((float) (recomb calib.M image'));\n\t\t\t}\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum Plot_style.names \"Style\" \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [$style => style.value] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\t!is_list_len 2 images\n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = all (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize xfactor yfactor 1 scale_im;\n\t\t\t_offset_im = resize xfactor yfactor 1 offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.14/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.14/_Object.def",
    "content": "/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0, 1, 2 or 3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \"colour_space\"];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide or VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down a bit.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n \t= check_args x.super, x.super != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// join two strings up with a separator string\n\tjoin_sep j a b = a ++ j ++ b;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad arguments to \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"usage\" ++ \"\\n\" ++ indent ++ usage ++ \"\\n\" ++ _ \"where\" ++ \"\\n\" ++ \n\t\targ_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make usage note\n\tusage = x.name ++ \" \" ++ \n\t\tfoldr (join_sep \" \") [] (map (extract 1) argcheck);\n\n\t// make arg type notes\n\targ_types = foldr (join_sep \"\\n\") [] (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = foldr (join_sep \"\\n\") [] all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if those fail as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if that fails as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary'_function op a b\n\t= matches1?0, matches1 != []\n\t= matches2?0, op.symmetric && matches2 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0, matches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x = oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x = oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op = oo_unary_function (oo_unary_lookup op) this;\n\n\too_binary_table op x = [];\n\too_unary_table op = [];\n}\n"
  },
  {
    "path": "share/nip2/compat/7.14/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && is_list_len 3 x\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The innermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x && !contains_Group x\n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), !is_list_len 2 parts \n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, !is_list_len 4 parts \n\t= (ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", member \".0123456789\",\n\t\tmember \"eE\", member \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), !is_list_len 5 parts \n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t$D93 => D93_whitepoint,\n\t$D75 => D75_whitepoint,\n\t$D65 => D65_whitepoint,\n\t$D55 => D55_whitepoint,\n\t$D50 => D50_whitepoint,\n\t$A => A_whitepoint,\n\t$B => B_whitepoint,\n\t$C => C_whitepoint,\n\t$E => E_whitepoint,\n\t$D3250 => D3250_whitepoint\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, im_8216],\n\t[RGB, GREY16, im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, RGB16, im_8216],\n\t[sRGB, GREY16, im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* Given a list of things, try to make them all the same size. Don't change\n * the format. Don't touch non-image things.\n */\nsize_alike l\n\t= map enlarge l\n{\n\tmax_width = foldr (test_prop has_width get_width) 0 l;\n\tmax_height = foldr (test_prop has_height get_height) 0 l;\n\n\ttest_prop has get x best\n\t\t= best, !has x\n\t\t= max_pair best (get x);\n\n\tenlarge x\n\t\t= embed 0 0 0 max_width max_height x, has_width x\n\t\t= x;\n}\n\n/* Given a list of things, look for 1 band objects and bump them to to n -\n * band objects, where n is the maximum number of bands. Don't change the \n * format. Don't touch non-image things.\n */\nbands_alike l\n\t= map upband l\n{\n\tmax_bands = foldr (test_prop has_bands get_bands) 0 l;\n\n\ttest_prop has get x best\n\t\t= best, !has x\n\t\t= max_pair best (get x);\n\n\tupband x\n\t\t= bandjoin (replicate max_bands x),\n\t\t\thas_bands x && get_bands x == 1\n\t\t= x;\n}\n\n/* Given a list of things, try to match the formats. Don't touch non-image\n * objects.\n */\nformats_alike l\n\t= map upformat l\n{\n\tmax_format = foldr (test_prop has_format get_format) Image_format.UCHAR l;\n\n\ttest_prop has get x best\n\t\t= best, !has x\n\t\t= max_pair best (get x);\n\n\tupformat x\n\t\t= clip2fmt max_format x,\n\t\t\thas_format x \n\t\t= x;\n}\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ path_separator ++ b;\n}\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 == 2 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n"
  },
  {
    "path": "share/nip2/compat/7.14/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black (to_real w) (to_real h) (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = Matrix_con mask_g_sum 0 [mask_g_line]\n{\n        mask_g = im_gauss_imask (radius / 3) 0.2;\n        mask_g_line = mask_g.value?(mask_g.height / 2);\n        mask_g_sum = sum mask_g_line;\n}\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.14/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = class\n\t\t\t\t{\n\t\t\t\tscale_factor = Expression \"scale the size of the frame by\" 1;\n\n\t\t\t\t/* These sliders define the fraction of the frames width or height is extracted\n\t\t \t\t * to produce each of the particular regions.\n\t\t \t\t */\n\t\t\t\tcorner_section = Scale \"Corner section\" 0.1 1 0.5;\n\t\t\t\tmiddle_section = Scale \"Middle section\" 0.1 1 0.2;\n\t\t\t\tblend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n\t\t\t\t}\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = class\n\t\t\t\t{\n\t\t\t\tapply = Toggle \"Apply mount options\" false;\n\t\t\t\tls = Expression \"Lower mount section bigger by (cm)\" 0;\n\t\t\t\tmount_colour = Colour _type [0, 0, 0];\n\t\t\t\t_los = ls.expr * ppcm.expr;\n\t\t\t\t}\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize _sf _sf Interpolate.BILINEAR a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\n\t\t\tvariables = class\n\t\t\t\t{\n\t\t\t\tscale_factor = Expression \"scale the size of the frame by\" 1;\n\n\t\t\t\t/* These sliders define the fraction of the frames width or height that\n\t\t\t\t * is extracted to produce each of the particular regions.\n\t\t \t\t */\n\t\t\t\tcorner_section = Scale \"Corner section\" 0.1 1 0.5;\n\t\t\t\tmiddle_section = Scale \"Middle section\" 0.1 1 0.2;\n\t\t\t\tblend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n\t\t\t\toption = Toggle \"Use mirror of left-side to make right\" true;\n\t\t\t\t}\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = class\n\t\t\t\t{\n\t\t\t\tapply = Toggle \"Apply mount options\" false;\n\t\t\t\tls = Expression \"Lower mount section bigger by (cm)\" 0;\n\t\t\t\tmount_colour = Colour _type [0, 0, 0];\n\t\t\t\t_los = ls.expr * ppcm.expr;\n\t\t\t\t}\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize _sf _sf Interpolate.BILINEAR a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\n\t\t\tvariables = class\n\t\t\t\t{\n\t\t\t\tscale_factor = Expression \"scale the size of the frame by\" 1;\n\n\t\t\t\t/* These sliders define the fraction of the frames width or height is extracted\n\t\t \t\t * to produce each of the particular regions.\n\t\t \t\t */\n\t\t\t\tcorner_section = Scale \"Corner section\" 0.1 1 0.5;\n\t\t\t\tedge_section = Scale \"Edge section\" 0.1 1 0.2;\n\t\t\t\tmiddle_section = Scale \"Middle section\" 0.1 1 0.2;\n\t\t\t\tblend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n\t\t\t\toption = Toggle \"Use mirror of left-side to make right\" true;\n\t\t\t\t}\n\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = class\n\t\t\t\t{\n\t\t\t\tapply = Toggle \"Apply mount color\" false;\n\t\t\t\tls = Expression \"Lower mount section bigger by (cm)\" 0;\n\t\t\t\tcolour = Colour _type [0, 0, 0];\n\t\t\t\t_los = ls.expr * ppcm.expr;\n\t\t\t\t}\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize _sf _sf Interpolate.BILINEAR a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" ] 6;\n\n\n\tcontrol_selection mask im no\n\t\t= (if mask then im * 1.2 else im * 1), no == 0\n\t\t= (if mask then im * 0.8 else im * 1), no == 1\n\t\t= (if mask then 0 else im), no == 2\n\t\t= (if mask then 255 else im), no == 3\n\t\t= (if mask then im else 0), no == 4\n\t\t= (if mask then im else 255), no == 5\n\t\t= mask;\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = a.image;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = ((pt_list.value)?0).image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\t};\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize f1 f2 1 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize f1 1 1 b1\n\t\t\t\t\t{b1 = resize 1 f2 1 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/7.14/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\t\t\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\t\t\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t}\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\t\t\n\t\t\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t}\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = line.image;\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\t\t\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = (pt_l?0).image;\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t}\n\n\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t}\n"
  },
  {
    "path": "share/nip2/compat/7.14/_list.def",
    "content": "/* any l: or all the elements of list l together\n *\n * any (map (equal 0) list) == true, if any element of list is zero.\n * any :: [bool] -> bool\n */\nany = foldr logical_or false;\n\n/* all l: and all the elements of list l together\n *\n * all (map (==0) list) == true, if every element of list is zero.\n * all :: [bool] -> bool\n */\nall = foldr logical_and true;\n\n/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn (tl l), fn (hd l)\n\t= l;\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st (hd l)) (tl l);\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn (hd l) (tl l);\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn (hd l) (foldr fn st (tl l));\n\n/* foldrl fn l: like foldr, but use the 1st element as the start value\n *\n * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= foldr fn (hd l) (tl l);\n\nsum = foldr1 add;\n\nproduct = foldr1 multiply;\n\n/* Search a list for an element, returning it's index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn (hd l)\n\t\t= search (tl l) (n + 1);\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= hd l : init (tl l);\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= hd l, tl l == []\n\t= last (tl l);\n\n/* len l: length of list l\n * (see also is_list_len and friends in predicate.def)\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta:b:x = l;\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = any (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge p l r\n\t= [], p == [] || l == [] || r == []\n\t= a : merge z x y, c\n\t= b : merge z x y\n{\n\ta:x = l;\n\tb:y = r;\n\tc:z = p;\n}\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta:x = l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scan fn st l: apply (fold fn r) to every initial segment of a list\n *\n * scan add 0 [1,2,3] == [1,3,6]\n * scan :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscan fn \n\t= g \n{\n\tg st l\n\t\t= [st], l == []\n\t\t= st : g (fn st a) x\n\t{\n\t\ta:x = l;\n\t}\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta:x = l1;\n\t\tb:y = l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/7.14/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = any (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && all (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* Test list length ... quicker than len x == n for large lists.\n */\nis_list_len n x\n\t= true, x == [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len (n - 1) (tl x);\n\nis_list_len_more n x\n\t= true, x != [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len_more (n - 1) (tl x);\n\nis_list_len_more_equal n x\n\t= true, n == 0\n\t= false, x == [] \n\t= is_list_len_more_equal (n - 1) (tl x);\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, all (map is_obj l)\n\t= true, all (map is_list l) &&\n\t\tall (map (not @ is_obj) l) &&\n\t\tall (map is_rectangular l) &&\n\t\tis_list_len_more 0 l &&\n\t\tall (map (is_list_len (len (hd l))) (tl l))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && is_list_len (len (hd l)) l;\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && all (map xy l)\n{\n\txy l = is_real_list l && is_list_len 2 l;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && any (map is_Group l)\n\t= any (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= error (\"get_type: unable to get type from \" ++ print x)\n{\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\t// can have alpha, hence we let bands be one more than you might think\n\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.GREY16, type == Image_type.GREY16 && is_bands 1\n\t\t= Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && \n\t\t\t(width == 1 || height == 1)\n\t\t= Image_type.B_W, is_bands 1 \n\t\t= Image_type.CMYK, type == Image_type.CMYK && is_bands 4\n\t\t= type, is_colorimetric && is_bands 3\n\t\t= Image_type.sRGB, !is_colorimetric && is_bands 3\n\t\t= Image_type.MULTIBAND, !is_colorimetric && !is_bands 3\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\n\t\t// is bands n, with an optional alpha (ie. can be n + 1 too)\n\t\tis_bands n = bands == n || bands == n + 1;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= error (\"get_format: unable to get format from \" ++ print x);\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= error (\"get_bits: unable to get bits from \" ++ print x);\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= error (\"get_bands: unable to get bands from \" ++ print x);\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= error (\"get_coding: unable to get coding from \" ++ print x);\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= error (\"get_xres: unable to get xres from \" ++ print x);\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= error (\"get_yres: unable to get yres from \" ++ print x);\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= error (\"get_xoffset: unable to get xoffset from \" ++ print x);\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= error (\"get_yoffset: unable to get yoffset from \" ++ print x);\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= error (\"get_image: unable to get image from \" ++ print x);\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= error (\"get_number: unable to get number from \" ++ print x);\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= error (\"get_real: unable to get real from \" ++ print x);\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= error (\"get_width: unable to get width from \" ++ print x);\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= error (\"get_height: unable to get height from \" ++ print x);\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= error (\"get_left: unable to get left from \" ++ print x);\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= error (\"get_top: unable to get top from \" ++ print x);\n\n// like has/get member, but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.14/_stdenv.def",
    "content": "/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\nidivide a b = (int) ((int) a / (int) b);\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the function we call for \"a -> v\" expressions\nmksvpair s v\n\t= [s, v], is_string s\n\t= error \"not str on lhs of ->\";\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error \"unimplemented vector operation\"\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n// make a name value pair\nmknvpair n v\n\t= [n, v], is_string n\n\t= error \"not [char] on LHS of =>\";\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined, has_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_cache x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (\\row [row?x']) obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\")\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x\n\t\t\t= x, is_image x\n\t\t\t= x.value, is_Image x\n\t\t\t= black + x\n\t\t{\n\t\t\tblack = im_black target_width target_height target_bands;\n\t\t}\n\n\t\t[then_image, else_image] = \n\t\t\tmap (clip2fmt target_format @ to_image) [then_part, else_part];\n\t\t[c, t, e] = size_alike [cond, then_image, else_image];\n\n\t\tblend_result_image = image_set_type target_type (im_blend c t e);\n\t}\n}\n\ninsert x y small big\n\t= oo_binary_function insert_op small big, is_class small\n\t= oo_binary'_function insert_op small big, is_class big\n\t= im_insert big' small' (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n\t[small', big'] = bands_alike [small, big];\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big' small' (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n\t[small', big'] = bands_alike [small, big];\n}\n\nmeasure x y w h u v image\n\t= oo_unary_function measure_op image, is_class image\n\t= im_measure image \n\t\t(to_real x) (to_real y) (to_real w) (to_real h)\n\t\t(to_real u) (to_real v), \n\t\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"measure\")\n{\n\tmeasure_op = Operator \"measure\" \n\t\t(measure x y w h u v) Operator_type.COMPOUND_REWRAP false;\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ninvert x\n\t= oo_unary_function invert_op x, is_class x\n\t= im_invert x, is_image x\n\t= 255 - x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"invert\")\n{\n\tinvert_op = Operator \"invert\" invert Operator_type.COMPOUND false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_similarity image (cos angle) (sin angle) 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\trotate Operator_type.COMPOUND_REWRAP false;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join a b\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin Operator_type.COMPOUND_REWRAP false;\n\n\tjoin a b\n\t\t= join_im a b, is_image a && is_image b \n\t\t= matrix_binary join_im a b,\n\t\t\tis_matrix a && is_matrix b \n\t\t= error (_ \"bad arguments to \" ++ \"join_lr\");\n\n\tjoin_im a b\t= insert (get_width b) 0 a b;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join a b\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin Operator_type.COMPOUND_REWRAP false;\n\n\tjoin a b\n\t\t= join_im a b, is_image a && is_image b \n\t\t= matrix_binary join_im a b,\n\t\t\tis_matrix a && is_matrix b \n\t\t= error (_ \"bad arguments to \" ++ \"join_tb\");\n\n\tjoin_im a b\t= insert 0 (get_height b) a b;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\timage = (unsigned char) im_mask2vips (Matrix m2);\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsepf image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\ngreyc iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx x\n\t= oo_unary_function greyc_op x, is_class x\n\t= greyc_im x, is_image x\n\t= error (_ \"bad argument\" ++ \" (\" ++ print x ++ \") to \" ++ \"greyc\")\n{\n\tgreyc_op = Operator \"greyc\" (greyc\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im x = im_greyc x\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\ngreyc_mask iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx mask x\n\t= oo_binary_function greyc_mask_op mask x, is_class mask\n\t= oo_binary'_function greyc_mask_op mask x, is_class x\n\t= greyc_im mask x, is_image mask && is_image x\n\t= error (_ \"bad arguments\" ++ \n\t\t\" (\" ++ print mask ++ \", \" ++ print x ++ \") \" ++\n\t\t\"to \" ++ \"greyc\")\n{\n\tgreyc_mask_op = Operator \"greyc_mask\" (greyc_mask\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im mask x = im_greyc_mask x mask\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h \n\t\t= (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h\n\t{\n\t\t// up the format so it can represent the whole range of\n\t\t// possible values from this mask\n\t\tfmt x\n\t\t\t= Image_format.SHORT, \n\t\t\t\tx == Image_format.UCHAR || x == Image_format.CHAR\n\t\t\t= Image_format.INT, \n\t\t\t\tx == Image_format.USHORT || x == Image_format.SHORT ||\n\t\t\t\tx == Image_format.UINT \n\t\t\t= x;\n\t}\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= lhisteq image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n\n\t// loop over bands, if necessary\n\tlhisteq im\n\t\t= im_lhisteq im (to_real w) (to_real h), get_bands im == 1\n\t\t= (foldl1 join @ map lhisteq @ bandsplit) im;\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nresize xfac yfac interp image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// upscale by any factor, nearest neighbour \n\t\t// can't really do this right ... upscale by integer part, then\n\t\t// bilinear to exact size\n\t\t= scale xg?1 yg?1 (im_zoom im xg?0 yg?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// downscale by any factor, nearest neighbour \n\t\t// can't really do this right ... downscale by integer part, \n\t\t// then bilinear to exact size\n\t\t= scale xs?1 ys?1 (im_subsample im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// upscale by any factor, bilinear\n\t\t= scale xfac' yfac' im,\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.BILINEAR\n\n\t\t// downscale by any factor, bilinear\n\t\t// block shrink by integer factor, then bilinear resample to \n\t\t// exact\n\t\t= scale xs?1 ys?1 (im_shrink im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tinterp == Interpolate.BILINEAR\n\n\t\t= error (\"resize: unimplemented argument combination:\\n\" ++ \n\t\t\t\"  xfac = \" ++ print xfac' ++ \"\\n\" ++\n\t\t\t\"  yfac = \" ++ print yfac' ++ \"\\n\" ++\n\t\t\t\"  interp = \" ++ print interp ++ \" (\" ++\n\t\t\t\tInterpolate.names.lookup 1 0 interp ++ \")\")\n\t{\n\t\t// convert a float scale to integer plus fraction\n\t\t// eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25)\n\t\tbreak f = [floor f, f / floor f];\n\n\t\t// same, but for downsizing ... turn a float scale which is less than\n\t\t// 1 into an int shrink and a float scale\n\n\t\t// complicated: the int shrink may round the size down (eg. imagine\n\t\t// subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide\n\t\t// image, not a 3.666 pixel wide image), so pass in the size of image\n\t\t// we are operating on and adjust for any rounding\n\t\t\n\t\t// so ... x is (eg.) 467, f is (eg. 128/467, about 0.274)\n\t\trbreak x f \n\t\t\t= [int_shrink, float_resample]\n\t\t{\n\t\t\t// the size of image we are aiming for after the combined int and\n\t\t\t// float resample\n\t\t\tx' = x * f;\n\n\t\t\t// int part\n\t\t\tint_shrink = floor (1 / f);\n\n\t\t\t// size after int shrink\n\t\t\tx'' = floor (x / int_shrink);\n\n\t\t\t// therefore what we need for the float part\n\t\t\tfloat_resample = x' / x'';\n\t\t}\n\n\t\twidth = get_width im;\n\t\theight = get_height im;\n\n\t\t// grow and shrink factors\n\t\txg = break xfac';\n\t\tyg = break yfac';\n\t\txs = rbreak width xfac';\n\t\tys = rbreak height yfac';\n\n\t\t// binlinear resize\n\t\tscale xfac yfac im\n\t\t\t= im_affine im \n\t\t\t\txfac 0 0 yfac \n\t\t\t\t0 0 \n\t\t\t\t0 0 \n\t\t\t\t(rint (get_width im * xfac)) \n\t\t\t\t(rint (get_height im * yfac));\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nflood_blob x y v image\n\t= oo_unary_function flood_blob_op image, is_class image\n\t= im_flood_blob_copy image (to_real x) (to_real y) v, is_image image\n\t= error (_ \"bad arguments to \" ++ \"flood_blob\")\n{\n\tflood_blob_op = Operator \"flood_blob\" \n\t\t(flood_blob x y v) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (\\x x % base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (\\x idivide x base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= [], any (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == [];\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Image (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n/* Linear regression. Return a class with the stuff we need in.\n * from s15.2, p 665 NR in C\n */\nlinreg xes yes\n    = obj\n{\n    obj = class {\n        // in case we ever get shown in the workspace\n        _vislevel = 2;\n\n        slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2;\n        intercept = (sy - sx * slope) / ss;\n\n        chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes];\n\n        siga = (chi2 / (ss - 2)) ** 0.5 *\n            ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5;\n        sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5;\n\n        // for compat with linregw, see below\n        q = 1.0;\n    }\n\n    ss = len xes;\n    sx = sum xes;\n    sy = sum yes;\n    sxoss = sx / ss;\n\n    tes = [x - sxoss :: x <- xes];\n    st2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Weighted linear regression. Xes, yes and a list of deviations.\n */\nlinregw xes yes devs \n\t= obj\n{\n\tobj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: \n\t\t\t[x, y, sd] <- zip3 xes yes devs];\n\n\t\tsiga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (1 / st2) ** 0.5;\n\n\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\t}\n\n\twt = [sd ** -0.5 :: sd <- devs];\n\n\tss = sum wt;\n\tsx = sum [x * w :: [x, w] <- zip2 xes wt];\n\tsy = sum [y * w :: [y, w] <- zip2 yes wt];\n\tsxoss = sx / ss;\n\n\ttes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n"
  },
  {
    "path": "share/nip2/compat/7.14/_types.def",
    "content": "/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t]\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t]\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary (\\a op.fn a x) this,\n\t\t\ttrue]\n\t]\n\t{\n\t\t// need ite as a true trinary\n\t\tite a b c = if a then b else c;\n\n\t\t// we can't call map_trinary directly, since it uses Group and we\n\t\t// don't support mutually recursive top-level functions :-(\n\t\t// copy-paste it here, keep in sync with the version in _stdenv\n\t\tmap_nary fn args\n\t\t\t= fn args, groups == []\n\t\t\t= Group (map process [0, 1 .. shortest - 1])\n\t\t{\n\t\t\tgroups = filter is_Group args;\n\n\t\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\t\tprocess n\n\t\t\t\t= [], any (map (is_noval n) args)\n\t\t\t\t= map_nary fn (map (extract n) args)\n\t\t\t{\n\t\t\t\textract n arg\n\t\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t\t= arg;\n\n\t\t\t\tis_noval n arg = is_Group arg && arg.value?n == [];\n\t\t\t}\n\t\t}\n\n\t\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\t\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\t\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\t}\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t]\n\t{\n\t\t// we can't call map_trinary directly, since it uses Group and we\n\t\t// don't support mutually recursive top-level functions :-(\n\t\t// copy-paste it here, keep in sync with the version in _stdenv\n\t\tmap_nary fn args\n\t\t\t= fn args, groups == []\n\t\t\t= Group (map process [0, 1 .. shortest - 1])\n\t\t{\n\t\t\tgroups = filter is_Group args;\n\n\t\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\t\tprocess n\n\t\t\t\t= [], any (map (is_noval n) args)\n\t\t\t\t= map_nary fn (map (extract n) args)\n\t\t\t{\n\t\t\t\textract n arg\n\t\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t\t= arg;\n\n\t\t\t\tis_noval n arg = is_Group arg && arg.value?n == [];\n\t\t\t}\n\t\t}\n\n\t\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\t}\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t];\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t];\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t];\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t];\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t];\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[is_list_len 3 value, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.value_name colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum Image_type.colour_spaces \"Colour space\" default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\nOption_enum enum caption value_name = class\n\tOption caption enum.names (index (equal value_name) enum.names) {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing value_name;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum enum caption (enum.names ? value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNONE = 0;\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNONE = 0;\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (map (extract col) value) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (map (extract from) value);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = map (extract 0) value;\n\tthings = map (extract 1) value;\n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tLUMINANCE = 2;\n\tXRAY = 3;\n\tIR = 4;\n\tYUV = 5;\n\tRED_ONLY = 6;\n\tGREEN_ONLY = 7;\n\tBLUE_ONLY = 8;\n\tPOWER_SPECTRUM = 9;\n\tHISTOGRAM = 10;\n\tLUT = 11;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMC = 14;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t$MULTIBAND => MULTIBAND,\n\t\t$B_W => B_W,\n\t\t$LUMINANCE => LUMINANCE,\n\t\t$XRAY => XRAY,\n\t\t$IR => IR,\n\t\t$YUV => YUV,\n\t\t$RED_ONLY => RED_ONLY,\n\t\t$GREEN_ONLY => GREEN_ONLY,\n\t\t$BLUE_ONLY => BLUE_ONLY,\n\t\t$POWER_SPECTRUM => POWER_SPECTRUM,\n\t\t$HISTOGRAM => HISTOGRAM,\n\t\t$LUT => LUT,\n\t\t$XYZ => XYZ,\n\t\t$LAB => LAB,\n\t\t$CMC => CMC,\n\t\t$CMYK => CMYK,\n\t\t$LABQ => LABQ,\n\t\t$RGB => RGB,\n\t\t$UCS => UCS,\n\t\t$LCH => LCH,\n\t\t$LABS => LABS,\n\t\t$sRGB => sRGB,\n\t\t$YXY => YXY,\n\t\t$FOURIER => FOURIER,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options generated from this, so match the order to the order in the\n\t * Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t$sRGB => sRGB,\n\t\t$Lab => LAB,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t$Mono => B_W,\n\t\t$sRGB => sRGB,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$Lab => LAB,\n\t\t$LabQ => LABQ,\n\t\t$LabS => LABS,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// image ++ image is slightly different ... we want to\n\t\t// sizealike, but we must not bandalike\n\t\t[wrap \n\t\t\t(op.fn (get_image resized?0) (get_image resized?1)),\n\t\t\thas_image x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t// arithmetic and reational binops between image resize\n\t\t// and band_alike images to match\n\t\t[wrap \n\t\t\t(op.fn (get_image rebanded?0) (get_image rebanded?1)),\n\t\t\thas_image x &&\n\t\t\t(op.type == Operator_type.ARITHMETIC ||\n\t\t\t\top.type == Operator_type.RELATIONAL)],\n\t\t// other op types don't resize\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \"Image v ==\n\t\t// 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\t// if one of then/else is an image, get the target format from that\n\t\t// otherwise, let the non-image objects set the target\n\t\ttarget_format \n\t\t\t= get_member_list has_format get_format x, \n\t\t\t\thas_member_list has_format x\n\t\t\t= [];\n\n\t\tto_image x\n\t\t\t= x, is_image x\n\t\t\t= x.value, is_Image x\n\t\t\t= clip2fmt target_format im, target_format != []\n\t\t\t= im\n\t\t{\n\t\t\tim = im_black width height target_bands + x;\n\t\t}\n\n\t\t[if_size, then_size, else_size] = \n\t\t\tsize_alike (value : formats_alike (map to_image x));\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if if_size then then_size else else_size);\n\n\t\tresized = size_alike [this, x];\n\t\trebanded = bands_alike resized;\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t]\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nInterpolate = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tnames = Enum [\n\t\t[_ \"Nearest neighbour\", NEAREST_NEIGHBOUR],\n\t\t[_ \"Bilinear\", BILINEAR],\n\t\t[_ \"Bicubic\", BICUBIC]\n\t];\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t[_ \"Perceptual\", PERCEPTUAL],\n\t\t[_ \"Relative\", RELATIVE],\n\t\t[_ \"Saturation\", SATURATION],\n\t\t[_ \"Absolute\", ABSOLUTE]\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t[_ \"Point\", POINT],\n\t\t[_ \"Line\", LINE],\n\t\t[_ \"Spline\", SPLINE],\n\t\t[_ \"Bar\", BAR]\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t[_ \"YYYY\", YYYY],\n\t\t[_ \"XYYY\", XYXY],\n\t\t[_ \"XYXY\", XYXY]\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [$format => Plot_format.XYYY] value {\n}\n"
  },
  {
    "path": "share/nip2/compat/7.16/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t[_L, _a, _b] = default_value;\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum spaces (_ \"Convert to\") (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum spaces (_ \"Tag as\") (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Colour Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum Whitepoints (_ \"Old whitepoint\") \"D65\";\n\t\t\tnew_white = Option_enum Whitepoints (_ \"New whitepoint\") \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= monitor_profile, has_bands image && get_bands image == 3\n\t\t= print_profile;\n\trender_intents = Option_enum Render_intent.names (_ \"Render intent\") \n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure 0 0 in.width in.height \n\t\t\t\t\t(to_real pacross) (to_real pdown) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.16/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 1.5;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 50;\n\t\t\tfs = Scale \"Sharpen flat areas by\" (-2) 5 1;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" (-2) 5 2;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_convf, !separable && type == 1\n\t\t\t\t\t\t= im_convsepf, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 5) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height + 1) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width.expr window_height.expr in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\nFilter_greyc_item = class \n\tMenupullright \"_GREYCstoration\" \"noise-removing filter\" {\n\tDenoise_item = class \n\t\tMenuaction \"Denoise\" \"Noise-removing filter\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\titerations = Scale \"Iterations\" 1 5 1;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 40;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.9;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.15;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.6;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.1;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) x;\n\t\t}\n\t}\n\n\tEnlarge_item = class\n\t\tMenuaction \"Enlarge\" \"Enlarge image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Enlarge\" 1 10 3;\n\t\t\titerations = Scale \"Iterations\" 1 5 3;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 20;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.2;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.9;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.1;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.5;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) \n\t\t\t\t\t(resize (to_real scale) (to_real scale) \n\t\t\t\t\t\tInterpolate.BILINEAR x);\n\t\t}\n\t}\n\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image\" \"use an image to blend two objects\" {\n\t\taction a b c = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ti = Toggle \"Invert mask\" false;\n\n\t\t\t_result \n\t\t\t\t= map_trinary process a b c\n\t\t\t{\n\t\t\t\tprocess a b c \n\t\t\t\t\t= blend condition in1 in2, !i\n\t\t\t\t\t= blend (invert condition) in1 in2\n\t\t\t\t{\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t\t= false,\n\t\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t\t= true;\n\t\t\t\t\t[condition, in1, in2] = sortc compare [a, b, c];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"_Alpha\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\t\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t[_ \"Normal\", NORMAL],\n\t\t\t[_ \"If Lighter\", IFLIGHTER],\n\t\t\t[_ \"If Darker\", IFDARKER],\n\t\t\t[_ \"Multiply\", MULTIPLY],\n\t\t\t[_ \"Add\", ADD],\n\t\t\t[_ \"Subtract\", SUBTRACT],\n\t\t\t[_ \"Screen\", SCREEN],\n\t\t\t[_ \"Burn\", BURN],\n\t\t\t[_ \"Soft Light\", SOFTLIGHT],\n\t\t\t[_ \"Hard Light\", HARDLIGHT],\n\t\t\t[_ \"Lighten\", LIGHTEN],\n\t\t\t[_ \"Darken\", DARKEN],\n\t\t\t[_ \"Dodge\", DODGE],\n\t\t\t[_ \"Reflect\", REFLECT],\n\t\t\t[_ \"Freeze\", FREEZE],\n\t\t\t[_ \"Bitwise OR\", OR],\n\t\t\t[_ \"Bitwise AND\", AND]\n\t\t];\n\t\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum names \"Blend mode\" \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\t[mono, colour] = \n\t\t\t\t\tsortc (const (is_colour_type @ get_type)) [a, b];\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t\t_ \"Grey\",\n\t\t\t\t_ \"Green over Red\",\n\t\t\t\t_ \"Blue over Red\",\n\t\t\t\t_ \"Red over Green\",\n\t\t\t\t_ \"Red over Blue\",\n\t\t\t\t_ \"Blue over Green\",\n\t\t\t\t_ \"Green over Blue\"\n\t\t\t] 0;\n\t\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t] ++ super._check_args;\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t_ \"North-west\",\n\t\t\t\t_ \"North\",\n\t\t\t\t_ \"North-east\",\n\t\t\t\t_ \"West\",\n\t\t\t\t_ \"Centre\",\n\t\t\t\t_ \"East\",\n\t\t\t\t_ \"South-west\",\n\t\t\t\t_ \"South\",\n\t\t\t\t_ \"South-east\",\n\t\t\t\t_ \"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.16/Histogram.def",
    "content": "Hist_new_item = class\n\tMenupullright \"_New\" \"new histogram\" {\n\tHist_item = class\n\t\tMenuaction \"Histogram\" \"make an identity histogram\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\t_result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d);\n\t\t}\n\t}\n\n\tHist_new_from_matrix = Matrix_buildlut_item; \n\n\tHist_from_image_item = class\n\t\tMenuaction \"Ta_g Image As Histogram\" \"set image Type field to Histogram\" {\n\t\taction x = hist_tag x;\n\t}\n\n\tTone_item = class \n\t\tMenuaction \"_Tone Curve\" \"make a new tone mapping curve\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\t_result \n\t\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t\t{\n\t\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_find_item = class \n\tMenupullright \"_Find\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map Histogram\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\t[im, hist] = sortc (const is_hist) [a, b];\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Cumulativise Histogram\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate Histogram\" \n\t\t\"find point-to-point differences (inverse of Cumulativise)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise Histogram\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch Histogram\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\t// the line as a polar vector\n\t\t\t\tpv = polar (arrow.width, arrow.height);\n\t\t\t\ta = im pv;\n\n\t\t\t\t// smallest rotation that will make the line horizontal\n\t\t\t\ta'\n\t\t\t\t\t= 360 - a, a > 270\n\t\t\t\t\t= 180 - a, a > 90\n\t\t\t\t\t= -a;\n\n\t\t\t\tim' = rotate a' arrow.image;\n\n\t\t\t\t// look at the start and end of the arrow, pick the leftmost\n\t\t\t\tp\n\t\t\t\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t\t\t\t= (arrow.right, arrow.bottom);\n\n\t\t\t\t// transform that point to im' space\n\t\t\t\tp' = rectangular (polar p + (0, a')) + \n\t\t\t\t\t(im'.xoffset, im'.yoffset);\n\n\t\t\t\t// extract that area\n\t\t\t\tarea = extract_area \n\t\t\t\t\t(re p' + displace.value) \n\t\t\t\t\t(im p' - width.value / 2 + vdisplace.value) \n\t\t\t\t\t(re pv) width.value \n\t\t\t\t\tim';\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize 1 (1 / width.value) Interpolate.BILINEAR area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= area\n\t\t\t{\n\t\t\t\t// the line as a polar vector\n\t\t\t\tpv = polar (arrow.width, arrow.height);\n\t\t\t\ta = im pv;\n\n\t\t\t\t// smallest rotation that will make the line horizontal\n\t\t\t\ta'\n\t\t\t\t\t= 360 - a, a > 270\n\t\t\t\t\t= 180 - a, a > 90\n\t\t\t\t\t= -a;\n\n\t\t\t\tim' = rotate a' arrow.image;\n\n\t\t\t\t// look at the start and end of the arrow, pick the leftmost\n\t\t\t\tp\n\t\t\t\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t\t\t\t= (arrow.right, arrow.bottom);\n\n\t\t\t\t// transform that point to im' space\n\t\t\t\tp' = rectangular (polar p + (0, a')) + \n\t\t\t\t\t(im'.xoffset, im'.yoffset);\n\n\t\t\t\t// extract that area\n\t\t\t\tarea = extract_area \n\t\t\t\t\t(re p' + displace.value) \n\t\t\t\t\t(im p' - width.value / 2 + vdisplace.value) \n\t\t\t\t\t(re pv) width.value \n\t\t\t\t\tim';\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tformat = Option_enum Plot_format.names \"Format\" \"YYYY\";\n\t\tstyle = Option_enum Plot_style.names \"Style\" \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => style.value, $format => format.value] ++ range;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\textract_arrow arrow\n\t\t\t\t= extract_area (re p') (im p') (re pv) 1 im'\n\t\t\t{\n\t\t\t\t// the line as a polar vector\n\t\t\t\tpv = polar (arrow.width, arrow.height);\n\t\t\t\ta = im pv;\n\n\t\t\t\t// smallest rotation that will make the line horizontal\n\t\t\t\ta'\n\t\t\t\t\t= 360 - a, a > 270\n\t\t\t\t\t= 180 - a, a > 90\n\t\t\t\t\t= -a;\n\n\t\t\t\tim' = rotate a' arrow.image;\n\n\t\t\t\t// look at the start and end of the arrow, pick the leftmost\n\t\t\t\tp\n\t\t\t\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t\t\t\t= (arrow.right, arrow.bottom);\n\n\t\t\t\t// transform that point to im' space\n\t\t\t\tp' = rectangular (polar p + (0, a')) + \n\t\t\t\t\t(im'.xoffset, im'.yoffset);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.16/Image.def",
    "content": "Image_new_item = class \n\tMenupullright \"_New\" \"make new things\" {\n\tImage_black_item = class \n\t\tMenuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \n\t\t\t\tImage_type.type_names \"Image type\" \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region on image using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\t[target, x] = sortc compare [a, b];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\nImage_number_format_item = class\n\tMenupullright \"_Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_header_item = class \n\tMenupullright \"_Header\" \"do stuff to the image header\" {\n\n\tImage_get_item = class\n\t\tMenupullright \"_Get\" \"get header fields\" {\n\n\t\t// the header fields we can get\n\t\tfields = class {\n\t\t\ttype = 0;\n\t\t\twidth = 1;\n\t\t\theight = 2;\n\t\t\tformat = 3;\n\t\t\tbands = 4;\n\t\t\txres = 5;\n\t\t\tyres = 6;\n\t\t\txoffset = 7;\n\t\t\tyoffset = 8;\n\t\t\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t$width => width,\n\t\t\t\t$height => height,\n\t\t\t\t$bands => bands,\n\t\t\t\t$format => format,\n\t\t\t\t$type => type,\n\t\t\t\t$xres => xres,\n\t\t\t\t$yres => yres,\n\t\t\t\t$xoffset => xoffset,\n\t\t\t\t$yoffset => yoffset,\n\t\t\t\t$coding => coding\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum field_names (_ \"Field\") name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tCustom_item = class\n\t\t\tMenuaction \"C_ustom\" \"get any header field\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tfield = String \"Field\" \"Xsize\";\n\t\t\t\tparse = Option \"Parse\" [\n\t\t\t\t\t\"No parsing\",\n\t\t\t\t\t\"Parse string as integer\",\n\t\t\t\t\t\"Parse string as real\",\n\t\t\t\t\t\"Parse string as hh:mm:ss\"\n\t\t\t\t] 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary (wrap @ process @ get_header field.value) x\n\t\t\t\t{\n\t\t\t\t\tparse_str parse str = parse (split is_space str)?0;\n\n\t\t\t\t\tparse_field name cast parse x\n\t\t\t\t\t\t= cast x, is_number x\n\t\t\t\t\t\t= parse_str parse x, is_string x\n\t\t\t\t\t\t= error (\"not \" ++ name);\n\n\t\t\t\t\tget_int = parse_field \"int\" cast_int parse_int;\n\t\t\t\t\tget_float = parse_field \"float\" cast_float parse_float;\n\t\t\t\t\tget_time = parse_field \"hh:mm:ss\" cast_int parse_time;\n\n\t\t\t\t\twrap x\n\t\t\t\t\t\t= Real x, is_real x\n\t\t\t\t\t\t= Vector x, is_real_list x\n\t\t\t\t\t\t= Image x, is_image x\n\t\t\t\t\t\t= Bool x, is_bool x\n\t\t\t\t\t\t= Matrix x, is_matrix x\n\t\t\t\t\t\t= String \"String\" x, is_string x\n\t\t\t\t\t\t= List x, is_list x\n\t\t\t\t\t\t= x;\n\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tget_int, \n\t\t\t\t\t\tget_float,\n\t\t\t\t\t\tget_time\n\t\t\t\t\t]?parse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum Image_type.type_names \"Image type\"\n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_cache_item = class\n\tMenuaction \"C_ache\" \"cache calculated image pixels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttile_width = Number \"Tile width\" 32;\n\t\ttile_height = Number \"Tile height\" 32;\n\t\tmax_tiles = Number \"Maximum number of tiles to cache\" (-1);\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= cache (to_real tile_width) (to_real tile_height) \n\t\t\t\t\t(to_real max_tiles) image;\n\t\t}\n\t}\n}\n\n#separator\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in = [\n\t\t\t\t\t\tin, \n\t\t\t\t\t\trot90 in,\n\t\t\t\t\t\trot180 in,\n\t\t\t\t\t\trot270 in\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x \n\t\t\t\t= map_unary straighten x\n\t\t\t{\n\t\t\t\tstraighten arrow\n\t\t\t\t\t= rotate angle'' arrow.image\n\t\t\t\t{\n\t\t\t\t\tx = arrow.width;\n\t\t\t\t\ty = arrow.height;\n\t\n\t\t\t\t\tangle = im (polar (x, y));\n\t\n\t\t\t\t\tangle'\n\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t= angle;\n\t\n\t\t\t\t\tangle''\n\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\t_interp = Option_enum Interpolate.names \"Interpolation\" \"Bilinear\";\n\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tinterp = _interp;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize xfactor yfactor interp.value_thing image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\tinterp = _interp;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize fac fac interp.value_thing image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor = max_pair xfac yfac;\n\t\t\t\t\t\tmin_factor = min_pair xfac yfac;\n\t\t\t\t\t\tfac = [max_factor, min_factor, xfac, yfac]?which;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_within_item = class\n\t\t\tMenuaction \"Size _Within\" \"size to fit within a rectangle\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\t// the rects we size to fit within\n\t\t\t\t_rects = [\n\t\t\t\t\t[2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], \n\t\t\t\t\t[1280, 1024], [1024, 768], [800, 600], [640, 480] \n\t\t\t\t];\n\n\t\t\t\twithin = Option \"Fit within (pixels)\" (\n\t\t\t\t\t[print w ++ \" x \" ++ print h :: [w, h] <- _rects] ++\n\t\t\t\t\t[\"Custom\"]\n\t\t\t\t) 4;\n\t\t\t\tcustom_width = Expression \"Custom width\" 1000;\n\t\t\t\tcustom_height = Expression \"Custom height\" 1000;\n\t\t\t    size = Option \"Page size\" [\n\t\t\t\t\t\"Full page\", \"Half page\", \"Quarter page\" \n\t\t\t\t] 0;\n\t\t\t\tinterp = _interp;\n\n\t\t\t \t_result\n\t\t\t\t \t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\txdiv = [1, 2, 2]?size;\n\t\t\t\t\tydiv = [1, 1, 2]?size;\n\t\t\t\t\tallrect = _rects ++ [\n\t\t\t\t\t\t[custom_width.expr, custom_height.expr]\n\t\t\t\t\t];\n\t\t\t\t\t[width, height] = allrect?within;\n\n\t\t\t\t\tprocess x\n\t\t\t\t\t\t= resize fac fac interp.value_thing x, fac < 1\n\t\t\t\t\t\t= x\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = (width / xdiv) / x.width;\n\t\t\t\t\t\tyfac = (height / ydiv) / x.height;\n\t\t\t\t\t\tfac = min_pair xfac yfac;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\"\n\t\t\t(map (extract 0) Interpolate.names.value) Interpolate.BILINEAR;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_trn {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t[sample', trn, err] = transform_search \n\t\t\t\t\tmax_err max_iter order interp wrap\n\t\t\t\t\tsample reference;\n\t\t\t\ttransformed_image = Image sample';\n\t\t\t\t_trn = Transform trn reference.width reference.height;\n\t\t\t\tfinal_error = err;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\t[i, t] = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tBandwise_item = Image_join_item.Bandwise_item;\n\n    sep1 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldl1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find the image geometry ... don't bother trying to look\n\t\t// inside groups though\n\t\t_geo\n\t\t\t= x.rect, is_Image x\n\t\t\t= Rect 0 0 100 100;\n\n\t\tl = Expression \"Crop left\" ((int) (_geo.left + _geo.width / 4));\n\t\tt = Expression \"Crop top\" ((int) (_geo.top + _geo.height / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (_geo.width / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (_geo.height / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t] ++ super._check_args;\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t[_a', _b'] = sortc _pred [a, b];\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tGaussian_item = class \n\t\tMenuaction \"Gaussian _Noise\" \"make an image of gaussian noise\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t_result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) \n\t\t\t\tmean.value deviation.value);\n\t\t}\n\t}\n\n\tFractal_item = class \n\t\tMenuaction \"_Fractal\" \"make a fractal image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t}\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n    Colour_atlas_item = class\n        Menuaction \"_Colour Atlas\"\n            \"make a grid of patches grouped around a colour\" {\n        action = class \n            _result {   \n            _vislevel = 3;\n       \n            start = Colour_picker \"Lab\" [50,0,0];\n            nstep = Expression \"Number of steps\" 2;\n            ssize = Expression \"Step size\" 2; \n\n            _result\n                = Image (colour_transform_to (get_type start) im)\n            {\n                base = colour_transform_to Image_type.LAB start;\n                step = to_real ssize;\n                offset = to_real nstep * step;\n                range c = [c - offset, c - offset + step ... c + offset]; \n                                \n                mk_patch b a = image_new 8 8 3\n                    Image_format.FLOAT Image_coding.NOCODING \n                    Image_type.LAB (Vector [base?0, a, b]) 0 0;\n\n                mk_strip b = map (mk_patch b) (range base?1);\n                mk_grid = map mk_strip (range base?2);\n                im = imagearray_assemble 1 1 mk_grid;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.16/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/7.16\n\nstart_DATA = \\\n\tMath.def \\\n\tImage.def \\\n\tColour.def \\\n\tTasks.def \\\n\tObject.def \\\n\tFilter.def \\\n\tMatrix.def \\\n\tWidgets.def \\\n\tHistogram.def \\\n\tPreferences.ws \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_convert.def \\\n\t_generate.def \\\n\t_list.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\t_Object.def \\\n\t_types.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/7.16/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_And\" \"bitwise and of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_Or\" \"bitwise or of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"E_xclusive Or\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_Not\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBand_or_item = class \n\t\tMenuaction \"Band O_r\" \"or the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_or @ bandsplit) im;\n\t}\n\n\tBand_and_item = class \n\t\tMenuaction \"Band A_nd\" \"and the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_and @ bandsplit) im;\n\t}\n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \n\t\t\t\"position of centre of gravity of histogram\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = linreg xes yes;\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = linregw xes yes devs;\n\t}\n\n\tCluster_item = class \n\t\tMenuaction \"_Cluster\" \"cluster a list of numbers\" {\n\t\taction l = class {\n\t\t\t_vislevel = 2;\n\t\n\t\t\tthresh = Expression \"Threshold\" 10;\n\t\n\t\t\t[_r, _w] = cluster thresh.expr l;\n\t\n\t\t\tresult = _r;\n\t\t\tweights = _w;\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.16/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ \n\t\t\t\t\trange;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t] ++ super._check_args;\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.16/Object.def",
    "content": "Object_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nObject_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nObject_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nObject_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nObject_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list (or group) of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.16/Preferences.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/7.14.0\">\n  <Workspace filename=\"Preferences.ws\" view=\"WORKSPACE_MODE_NOEDIT\" scale=\"1\" offset=\"0\" window_width=\"680\" window_height=\"1159\">\n    <Column x=\"0\" y=\"2799\" open=\"false\" selected=\"false\" sform=\"false\" next=\"99\" name=\"B\" caption=\"Interface column -- don't touch this!\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"CSV_SEPARATOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"O1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PRINT_CARTIESIAN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F10.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_PANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"237\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"788\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"700\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"100\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RELOAD\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D42.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_STATUSBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR_STYLE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MATRIX_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_RECOMP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"N2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_MAX_UNDO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[-1,0,1,5,10]?N1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_FONT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"N4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_INTERLACE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_LINELENGTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D41.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A6.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE_FILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PPM_MODE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"G1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_LAYOUT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C16.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C18.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_MULTI_RES\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_FORMAT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_PREDICTOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_START\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D25.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_SEARCH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D2.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_TMP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_SLIDER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D28.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_REGION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D29.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_AUTO_WS_SAVE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D30.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_DISPLAY_LED\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLKITBROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_MAX_HEAP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D38.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PIN_FILESEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_STATUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CONVERSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_RULERS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CROSSHAIR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E21.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_TRACE_FUNCTIONS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"H1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_DEVICE\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CHANNEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_BRIGHTNESS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_COLOUR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CONTRAST\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_HUE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_FRAMES\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J13.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_MONO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J14.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_LEFT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_TOP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_ASPECT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_MAX_BLEND_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_REFINE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_WINDOW_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_OBJECT_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_BALANCE_GAMMA\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"680\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"480\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER_REMOTE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"POPUP_NEW_ROWS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_HISTORY_MAX\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D43.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_CPUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D44.value\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2581\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"I\" caption=\"Mosaic defaults\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Maximum blend width&quot; 0 100 10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Refine tie-points&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search windows this size&quot; 30\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search for objects this size&quot; 10\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Image gamma for mosaic balance&quot; 1 3 1.6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2272\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"J\" caption=\"Video for linux\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"J2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;Device&quot; &quot;/dev/video&quot;\"/>\n            <Pathname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Channel&quot; [&quot;TV&quot;, &quot;Composite 1&quot;, &quot;Composite 2&quot;, &quot;Composite 3&quot;] 1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Brightness&quot; 0 32767 23000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Colour&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Contrast&quot; 0 32767 27000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Hue&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Number of frames to average&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Grab monochrome&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2014\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"K\" caption=\"General video capture\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"K1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Crop video: \" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Crop video&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop left&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop top&quot; 6\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number  &quot;Crop width&quot; 747\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop height&quot; 570\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Aspect ratio (stretch vertically\\nby this much)&quot; 1.202\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1887\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"M\" caption=\"PNG save options\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"M1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Compression&quot; (map print [0..9]) 6\"/>\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Interlace&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1790\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"G\" caption=\"PPM/PGM/PBM save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"PPM mode\" labelsn=\"2\" labels0=\"Binary\" labels1=\"ASCII\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Mode&quot; [&quot;Binary&quot;, &quot;ASCII&quot;] 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1508\" open=\"true\" selected=\"false\" sform=\"false\" next=\"25\" name=\"C\" caption=\"TIFF save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Compression&quot; [&quot;None&quot;, &quot;LZW&quot;, &quot;Zip (deflate)&quot;, &quot;PACKBITS&quot;, &quot;JPEG&quot;, &quot;CCITTFAX4&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;JPEG quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n\t    <iText formula=\"Option &quot;Deflate/LZW predictor&quot; [&quot;None&quot;,&quot;Horizontal difference&quot;,&quot;Floating-point&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Layout&quot; [&quot;Strip&quot;, &quot;Tile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile width&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile height&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Multi-res&quot; [&quot;Single image&quot;, &quot;Image pyramid&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Format&quot; [&quot;No truncation&quot;,&quot;Save 1 band 8 bit images as 1 bit&quot;] 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1226\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"A\" caption=\"JPEG save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;ICC profile&quot; [&quot;Use embedded profile, if available&quot;, &quot;Embed profile from file&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Pathname/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;ICC profile file&quot; &quot;$VIPSHOME/share/nip2/data/sRGB.icm&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1039\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"F\" caption=\"Widgets\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Pin up file requestors&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Main window toolbar&quot; [&quot;Default style&quot;, &quot;Icon only&quot;, &quot;Text only&quot;, &quot;Icon and text&quot;, &quot;Icon and text to right&quot;] 0\"/>\n            <Option caption=\"Main window toolbar\" labelsn=\"5\" labels0=\"Default style\" labels1=\"Icon only\" labels2=\"Text only\" labels3=\"Icon and text\" labels4=\"Icon and text to right\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display LEDs in workspace&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display complex numbers as coordinates&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"943\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"H\" caption=\"Debug options\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Disassemble functions\" value=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;untitled&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"815\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"L\" caption=\"Help browser\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"L2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Command to start browser&quot; &quot;firefox&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Go-to-page argument&quot; &quot;-remote 'openURL(%s)'&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"657\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"N\" caption=\"Paintbox \">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Max undo steps\" labelsn=\"5\" labels0=\"Unlimited\" labels1=\"None\" labels2=\"1\" labels3=\"5\" labels4=\"10\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Max undo steps&quot; [&quot;Unlimited&quot;, &quot;None&quot;, &quot;1&quot;, &quot;5&quot;, &quot;10&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Fontname &quot;Default paintbox font&quot; &quot;Sans 12&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Fontname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update during paint&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"407\" open=\"true\" selected=\"false\" sform=\"false\" next=\"26\" name=\"E\" caption=\"Image display\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"E20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use crosshair cursor in image windows&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Thumbnail size&quot; 64\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window width&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window height&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto image window pop up&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"45\" name=\"D\" caption=\"Calculation\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Data path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;data&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;data&quot;], &quot;.&quot;]\"/>\n            <Expression caption=\"Data path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Temporary files&quot; (path_relative [&quot;$SAVEDIR&quot;, &quot;tmp&quot;])\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Start path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;start&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;start&quot;]]\"/>\n            <Expression caption=\"Start path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D28\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update sliders during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update sliders during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D29\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update regions during drag\" value=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update regions during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D30\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto workspace save&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D42\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto-reload on file change&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D41\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Text display length (characters)&quot; 80\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D38\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Heap size (per workspace)&quot; 600000\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D43\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of VIPS functions to memoise&quot; 20000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D44\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of CPUs to use&quot; 1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1384\" open=\"true\" selected=\"true\" sform=\"false\" next=\"4\" name=\"O\" caption=\"CSV save\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"String &quot;Separator character&quot; &quot;\\t&quot;\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/compat/7.16/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\n\tCsv_import_item = class\n\t\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tstart_line = Expression \"Start at line\" 1;\n\t\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_csv2vips filename)\n\t\t\t{\n\t\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\t\tescape x \n\t\t\t\t\t= foldr prefix [] x\n\t\t\t\t{\n\t\t\t\t\tprefix x l\n\t\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t\t= x : l;\n\t\t\t\t}\n\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// interpret Analyze header for layout and calibration\n\tAnalyze7_header_item = class\n\t\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\t\"examine the Analyze header and set layout and value\" {\n\t\taction x \n\t\t\t= x'''\n\t\t{\n\t\t\t// read bits of header\n\t\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\t\tdim0 = dim 0 x;\n\t\t\tdim1 = dim 1 x;\n\t\t\tdim2 = dim 2 x;\n\t\t\tdim3 = dim 3 x;\n\t\t\tdim4 = dim 4 x;\n\t\t\tdim5 = dim 5 x;\n\t\t\tdim6 = dim 6 x;\n\t\t\tdim7 = dim 7 x;\n\t\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\t\n\t\t\t// oops, now a nop\n\t\t\tx' = x;\n\t\n\t\t\t// lay out higher dimensions width-ways\n\t\t\tx'' \n\t\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\t\tdim0 == 7\n\t\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\t\n\t\t\t// multiply by scale factor to get kBeq\n\t\t\tx''' = x'' * (cal_max / glmax);\n\t\t}\n\t}\n\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\t[image, patch] = sortc larger [a, b];\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t] ++ super._check_args;\n\t\t\t_vislevel = 3;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\tmode = Option \"Input LUT\" [\n\t\t\t\t\"Linear input\",\n\t\t\t\t\"Fit intercept from chart greyscale\",\n\t\t\t\t\"Linearize input from chart greyscale\"\n\t\t\t] 2;\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = measure 0 0 image.width image.height 6 4 image.value;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb \n\t\t\t\t= Matrix [[0, 0], [1, 1]], mode == 0\n\t\t\t\t= Matrix [0: intercepts, replicate (_camera.width + 1) 1], \n\t\t\t\t\tmode == 1\n\t\t\t\t= Matrix (map2 cons _true_grey_Y' _camera_grey')\n\t\t\t{\n\t\t\t\tintercepts = [(linreg _true_grey_Y' cam).intercept :: \n\t\t\t\t\tcam <- transpose _camera_grey'];\n\t\t\t}\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\t// plot from 0 explicitly so we see the effect of mode1 (intercept\n\t\t\t// from greyscale)\n\t\t\tlinearising_lut = Plot [$ymin => 0] _linear_lut;\n\n\t\t\t// map the original image through the lineariser to \n\t\t\t// get linear 0-1 RGB image\n\t\t\t_image' = hist_map linearising_lut.value image.value;\n\n\t\t\t// remeasure and solve for RGB -> XYZ\n\t\t\t_camera' = im_measure _image' 0 0 image.width image.height 6 4;\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\tM = transpose (_pinv * transpose _camera' * _true_XYZ);\n\n\t\t\t// convert linear RGB camera to Lab \n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tcast_float @\n\t\t\t\trecomb M) _image';\n\n\t\t\t// measure again and compute dE76\n\t\t\t_camera'' = im_measure _result.value 0 0 \n\t\t\t\timage.width image.height 6 4;\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tfinal_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0 && i < len macbeth_names\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b = class\n\t\t\t(map_binary process a b) {\n\t\t\tprocess a b\n\t\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t\t{\n\t\t\t\t// the name of the calib object we need\n\t\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t\t// get the Calibrate_chart arg first\n\t\t\t\t[image, calib] = sortc (const (is_instanceof calib_name)) \n\t\t\t\t\t[a, b];\n\n\t\t\t\t// map the original image through the lineariser to get \n\t\t\t\t// linear 0-1 RGB image\n\t\t\t\timage' = hist_map calib.linearising_lut image;\n\n\t\t\t\t// convert linear RGB camera to Lab \n\t\t\t\tresult = colour_transform Image_type.XYZ Image_type.LAB \n\t\t\t\t\t((float) (recomb calib.M image'));\n\t\t\t}\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum Plot_style.names \"Style\" \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [$style => style.value] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\t!is_list_len 2 images\n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = all (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b ++ super._check_args;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b ++ super._check_args;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d ++ super._check_args;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d ++ super._check_args;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize xfactor yfactor 1 scale_im;\n\t\t\t_offset_im = resize xfactor yfactor 1 offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.16/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.16/_Object.def",
    "content": "/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0|1|2|3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \n\tjoin_sep \"|\" Image_type.colour_spaces.names];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide|VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down a bit.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad properties for \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"where\" ++ \"\\n\" ++ arg_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make arg type notes\n\targ_types = join_sep \"\\n\" (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"\\n\" ++ _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = join_sep \"\\n\" all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if those fail as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if that fails as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary'_function op a b\n\t= matches1?0, matches1 != []\n\t= matches2?0, op.symmetric && matches2 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0, matches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t// these should always be defined\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x = oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x = oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op = oo_unary_function (oo_unary_lookup op) this;\n\n\too_binary_table op x = [];\n\too_unary_table op = [];\n}\n"
  },
  {
    "path": "share/nip2/compat/7.16/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && is_list_len 3 x\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The innermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x && !contains_Group x\n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), !is_list_len 2 parts \n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, !is_list_len 4 parts \n\t= (ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", member \".0123456789\",\n\t\tmember \"eE\", member \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), !is_list_len 5 parts \n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t$D93 => D93_whitepoint,\n\t$D75 => D75_whitepoint,\n\t$D65 => D65_whitepoint,\n\t$D55 => D55_whitepoint,\n\t$D50 => D50_whitepoint,\n\t$A => A_whitepoint,\n\t$B => B_whitepoint,\n\t$C => C_whitepoint,\n\t$E => E_whitepoint,\n\t$D3250 => D3250_whitepoint\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, image_set_type GREY16 @ im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* Given a list of things, try to make them all the same size. Don't change\n * the format. Don't touch non-image things.\n */\nsize_alike l\n\t= map enlarge l\n{\n\tmax_width = foldr (test_prop has_width get_width) 0 l;\n\tmax_height = foldr (test_prop has_height get_height) 0 l;\n\n\ttest_prop has get x best\n\t\t= best, !has x\n\t\t= max_pair best (get x);\n\n\tenlarge x\n\t\t= embed 0 0 0 max_width max_height x, has_width x\n\t\t= x;\n}\n\n/* Given a list of things, look for 1 band objects and bump them to to n -\n * band objects, where n is the maximum number of bands. Don't change the \n * format. Don't touch non-image things.\n */\nbands_alike l\n\t= map upband l\n{\n\tmax_bands = foldr (test_prop has_bands get_bands) 0 l;\n\n\ttest_prop has get x best\n\t\t= best, !has x\n\t\t= max_pair best (get x);\n\n\tupband x\n\t\t= bandjoin (replicate max_bands x),\n\t\t\thas_bands x && get_bands x == 1\n\t\t= x;\n}\n\n/* Given a list of things, try to match the formats. Don't touch non-image\n * objects.\n */\nformats_alike l\n\t= map upformat l\n{\n\tmax_format = foldr (test_prop has_format get_format) Image_format.UCHAR l;\n\n\ttest_prop has get x best\n\t\t= best, !has x\n\t\t= max_pair best (get x);\n\n\tupformat x\n\t\t= clip2fmt max_format x,\n\t\t\thas_format x \n\t\t= x;\n}\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l = join_sep path_separator l;\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 == 2 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n"
  },
  {
    "path": "share/nip2/compat/7.16/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black (to_real w) (to_real h) (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = Matrix_con mask_g_sum 0 [mask_g_line]\n{\n        mask_g = im_gauss_imask (radius / 3) 0.2;\n        mask_g_line = mask_g.value?(mask_g.height / 2);\n        mask_g_sum = sum mask_g_line;\n}\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.16/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t] ++ super._check_args;\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t] ++ super._check_all;\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = class\n\t\t\t\t{\n\t\t\t\tscale_factor = Expression \"scale the size of the frame by\" 1;\n\n\t\t\t\t/* These sliders define the fraction of the frames width or height is extracted\n\t\t \t\t * to produce each of the particular regions.\n\t\t \t\t */\n\t\t\t\tcorner_section = Scale \"Corner section\" 0.1 1 0.5;\n\t\t\t\tmiddle_section = Scale \"Middle section\" 0.1 1 0.2;\n\t\t\t\tblend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n\t\t\t\t}\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = class\n\t\t\t\t{\n\t\t\t\tapply = Toggle \"Apply mount options\" false;\n\t\t\t\tls = Expression \"Lower mount section bigger by (cm)\" 0;\n\t\t\t\tmount_colour = Colour _type [0, 0, 0];\n\t\t\t\t_los = ls.expr * ppcm.expr;\n\t\t\t\t}\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize _sf _sf Interpolate.BILINEAR a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t] ++ super._check_args;\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t] ++ super._check_all;\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\n\t\t\tvariables = class\n\t\t\t\t{\n\t\t\t\tscale_factor = Expression \"scale the size of the frame by\" 1;\n\n\t\t\t\t/* These sliders define the fraction of the frames width or height that\n\t\t\t\t * is extracted to produce each of the particular regions.\n\t\t \t\t */\n\t\t\t\tcorner_section = Scale \"Corner section\" 0.1 1 0.5;\n\t\t\t\tmiddle_section = Scale \"Middle section\" 0.1 1 0.2;\n\t\t\t\tblend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n\t\t\t\toption = Toggle \"Use mirror of left-side to make right\" true;\n\t\t\t\t}\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = class\n\t\t\t\t{\n\t\t\t\tapply = Toggle \"Apply mount options\" false;\n\t\t\t\tls = Expression \"Lower mount section bigger by (cm)\" 0;\n\t\t\t\tmount_colour = Colour _type [0, 0, 0];\n\t\t\t\t_los = ls.expr * ppcm.expr;\n\t\t\t\t}\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize _sf _sf Interpolate.BILINEAR a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t] ++ super._check_args;\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t] ++ super._check_all;\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\n\t\t\tvariables = class\n\t\t\t\t{\n\t\t\t\tscale_factor = Expression \"scale the size of the frame by\" 1;\n\n\t\t\t\t/* These sliders define the fraction of the frames width or height is extracted\n\t\t \t\t * to produce each of the particular regions.\n\t\t \t\t */\n\t\t\t\tcorner_section = Scale \"Corner section\" 0.1 1 0.5;\n\t\t\t\tedge_section = Scale \"Edge section\" 0.1 1 0.2;\n\t\t\t\tmiddle_section = Scale \"Middle section\" 0.1 1 0.2;\n\t\t\t\tblend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n\t\t\t\toption = Toggle \"Use mirror of left-side to make right\" true;\n\t\t\t\t}\n\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = class\n\t\t\t\t{\n\t\t\t\tapply = Toggle \"Apply mount color\" false;\n\t\t\t\tls = Expression \"Lower mount section bigger by (cm)\" 0;\n\t\t\t\tcolour = Colour _type [0, 0, 0];\n\t\t\t\t_los = ls.expr * ppcm.expr;\n\t\t\t\t}\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize _sf _sf Interpolate.BILINEAR a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" ] 6;\n\n\n\tcontrol_selection mask im no\n\t\t= (if mask then im * 1.2 else im * 1), no == 0\n\t\t= (if mask then im * 0.8 else im * 1), no == 1\n\t\t= (if mask then 0 else im), no == 2\n\t\t= (if mask then 255 else im), no == 3\n\t\t= (if mask then im else 0), no == 4\n\t\t= (if mask then im else 255), no == 5\n\t\t= mask;\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = a.image;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = ((pt_list.value)?0).image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\t};\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize f1 f2 1 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize f1 1 1 b1\n\t\t\t\t\t{b1 = resize 1 f2 1 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/7.16/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\t\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\t\t\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\t\t\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t}\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\t\t\n\t\t\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t}\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = line.image;\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\t\t\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = (pt_l?0).image;\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t}\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t}\n\n\n\t\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t}\n"
  },
  {
    "path": "share/nip2/compat/7.16/_list.def",
    "content": "/* any l: or all the elements of list l together\n *\n * any (map (equal 0) list) == true, if any element of list is zero.\n * any :: [bool] -> bool\n */\nany = foldr logical_or false;\n\n/* all l: and all the elements of list l together\n *\n * all (map (==0) list) == true, if every element of list is zero.\n * all :: [bool] -> bool\n */\nall = foldr logical_and true;\n\n/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn (tl l), fn (hd l)\n\t= l;\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st (hd l)) (tl l);\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn (hd l) (tl l);\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn (hd l) (foldr fn st (tl l));\n\n/* foldrl fn l: like foldr, but use the 1st element as the start value\n *\n * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= foldr fn (hd l) (tl l);\n\nsum = foldr1 add;\n\nproduct = foldr1 multiply;\n\n/* Search a list for an element, returning it's index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn (hd l)\n\t\t= search (tl l) (n + 1);\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= hd l : init (tl l);\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* join_sep sep l: join a list with a separator\n *\n * join_sep \", \" (map print [1 .. 4]) == \"1, 2, 3, 4\"\n * join_sep :: [*] -> [[*]] -> [*]\n */\njoin_sep sep l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ sep ++ b;\n}\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= hd l, tl l == []\n\t= last (tl l);\n\n/* len l: length of list l\n * (see also is_list_len and friends in predicate.def)\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta:b:x = l;\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = any (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge p l r\n\t= [], p == [] || l == [] || r == []\n\t= a : merge z x y, c\n\t= b : merge z x y\n{\n\ta:x = l;\n\tb:y = r;\n\tc:z = p;\n}\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta:x = l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scan fn st l: apply (fold fn r) to every initial segment of a list\n *\n * scan add 0 [1,2,3] == [1,3,6]\n * scan :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscan fn \n\t= g \n{\n\tg st l\n\t\t= [st], l == []\n\t\t= st : g (fn st a) x\n\t{\n\t\ta:x = l;\n\t}\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta:x = l1;\n\t\tb:y = l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/7.16/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = any (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && all (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* Test list length ... quicker than len x == n for large lists.\n */\nis_list_len n x\n\t= true, x == [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len (n - 1) (tl x);\n\nis_list_len_more n x\n\t= true, x != [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len_more (n - 1) (tl x);\n\nis_list_len_more_equal n x\n\t= true, n == 0\n\t= false, x == [] \n\t= is_list_len_more_equal (n - 1) (tl x);\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, all (map is_obj l)\n\t= true, all (map is_list l) &&\n\t\tall (map (not @ is_obj) l) &&\n\t\tall (map is_rectangular l) &&\n\t\tis_list_len_more 0 l &&\n\t\tall (map (is_list_len (len (hd l))) (tl l))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && is_list_len (len (hd l)) l;\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_NULL x = is_instanceof \"NULL\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && all (map xy l)\n{\n\txy l = is_real_list l && is_list_len 2 l;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && any (map is_Group l)\n\t= any (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= error (\"get_type: unable to get type from \" ++ print x)\n{\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\t// can have alpha, hence we let bands be one more than you might think\n\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.GREY16, type == Image_type.GREY16 && is_bands 1\n\t\t= Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && \n\t\t\t(width == 1 || height == 1)\n\t\t= Image_type.B_W, is_bands 1 \n\t\t= Image_type.CMYK, type == Image_type.CMYK && is_bands 4\n\t\t= type, is_colorimetric && is_bands 3\n\t\t= Image_type.sRGB, !is_colorimetric && is_bands 3\n\t\t= Image_type.MULTIBAND, !is_colorimetric && !is_bands 3\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\n\t\t// is bands n, with an optional alpha (ie. can be n + 1 too)\n\t\tis_bands n = bands == n || bands == n + 1;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= error (\"get_format: unable to get format from \" ++ print x);\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= error (\"get_bits: unable to get bits from \" ++ print x);\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= error (\"get_bands: unable to get bands from \" ++ print x);\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= error (\"get_coding: unable to get coding from \" ++ print x);\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= error (\"get_xres: unable to get xres from \" ++ print x);\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= error (\"get_yres: unable to get yres from \" ++ print x);\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= error (\"get_xoffset: unable to get xoffset from \" ++ print x);\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= error (\"get_yoffset: unable to get yoffset from \" ++ print x);\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= error (\"get_image: unable to get image from \" ++ print x);\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= error (\"get_number: unable to get number from \" ++ print x);\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= error (\"get_real: unable to get real from \" ++ print x);\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= error (\"get_width: unable to get width from \" ++ print x);\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= error (\"get_height: unable to get height from \" ++ print x);\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= error (\"get_left: unable to get left from \" ++ print x);\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= error (\"get_top: unable to get top from \" ++ print x);\n\n// like has/get member, but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.16/_stdenv.def",
    "content": "/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\nidivide a b = (int) ((int) a / (int) b);\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the function we call for \"a -> v\" expressions\nmksvpair s v\n\t= [s, v], is_string s\n\t= error \"not str on lhs of ->\";\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error \"unimplemented vector operation\"\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n// make a name value pair\nmknvpair n v\n\t= [n, v], is_string n\n\t= error \"not [char] on LHS of =>\";\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined, has_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_cache x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (\\row [row?x']) obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\")\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x\n\t\t\t= x, is_image x\n\t\t\t= x.value, is_Image x\n\t\t\t= black + x\n\t\t{\n\t\t\tblack = im_black target_width target_height target_bands;\n\t\t}\n\n\t\t[then_image, else_image] = \n\t\t\tmap (clip2fmt target_format @ to_image) [then_part, else_part];\n\t\t[c, t, e] = size_alike [cond, then_image, else_image];\n\n\t\tblend_result_image = image_set_type target_type (im_blend c t e);\n\t}\n}\n\ninsert x y small big\n\t= oo_binary_function insert_op small big, is_class small\n\t= oo_binary'_function insert_op small big, is_class big\n\t= im_insert big' small' (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n\t[small', big'] = (formats_alike @ bands_alike) [small, big];\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big' small' (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n\t[small', big'] = (formats_alike @ bands_alike) [small, big];\n}\n\nmeasure x y w h u v image\n\t= oo_unary_function measure_op image, is_class image\n\t= im_measure image \n\t\t(to_real x) (to_real y) (to_real w) (to_real h)\n\t\t(to_real u) (to_real v), \n\t\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"measure\")\n{\n\tmeasure_op = Operator \"measure\" \n\t\t(measure x y w h u v) Operator_type.COMPOUND_REWRAP false;\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ninvert x\n\t= oo_unary_function invert_op x, is_class x\n\t= im_invert x, is_image x\n\t= 255 - x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"invert\")\n{\n\tinvert_op = Operator \"invert\" invert Operator_type.COMPOUND false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_similarity image (cos angle) (sin angle) 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\trotate Operator_type.COMPOUND_REWRAP false;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join a b\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin Operator_type.COMPOUND_REWRAP false;\n\n\tjoin a b\n\t\t= join_im a b, is_image a && is_image b \n\t\t= matrix_binary join_im a b,\n\t\t\tis_matrix a && is_matrix b \n\t\t= error (_ \"bad arguments to \" ++ \"join_lr\");\n\n\tjoin_im a b\t= insert (get_width a) 0 b a;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join a b\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin Operator_type.COMPOUND_REWRAP false;\n\n\tjoin a b\n\t\t= join_im a b, is_image a && is_image b \n\t\t= matrix_binary join_im a b,\n\t\t\tis_matrix a && is_matrix b \n\t\t= error (_ \"bad arguments to \" ++ \"join_tb\");\n\n\tjoin_im a b\t= insert 0 (get_height a) b a;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\timage = (unsigned char) im_mask2vips (Matrix m2);\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsepf image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\ngreyc iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx x\n\t= oo_unary_function greyc_op x, is_class x\n\t= greyc_im x, is_image x\n\t= error (_ \"bad argument\" ++ \" (\" ++ print x ++ \") to \" ++ \"greyc\")\n{\n\tgreyc_op = Operator \"greyc\" (greyc\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im x = im_greyc x\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\ngreyc_mask iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx mask x\n\t= oo_binary_function greyc_mask_op mask x, is_class mask\n\t= oo_binary'_function greyc_mask_op mask x, is_class x\n\t= greyc_im mask x, is_image mask && is_image x\n\t= error (_ \"bad arguments\" ++ \n\t\t\" (\" ++ print mask ++ \", \" ++ print x ++ \") \" ++\n\t\t\"to \" ++ \"greyc\")\n{\n\tgreyc_mask_op = Operator \"greyc_mask\" (greyc_mask\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im mask x = im_greyc_mask x mask\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h \n\t\t= (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h\n\t{\n\t\t// up the format so it can represent the whole range of\n\t\t// possible values from this mask\n\t\tfmt x\n\t\t\t= Image_format.SHORT, \n\t\t\t\tx == Image_format.UCHAR || x == Image_format.CHAR\n\t\t\t= Image_format.INT, \n\t\t\t\tx == Image_format.USHORT || x == Image_format.SHORT ||\n\t\t\t\tx == Image_format.UINT \n\t\t\t= x;\n\t}\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= lhisteq image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n\n\t// loop over bands, if necessary\n\tlhisteq im\n\t\t= im_lhisteq im (to_real w) (to_real h), get_bands im == 1\n\t\t= (foldl1 join @ map lhisteq @ bandsplit) im;\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nresize xfac yfac interp image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// upscale by any factor, nearest neighbour \n\t\t// can't really do this right ... upscale by integer part, then\n\t\t// bilinear to exact size\n\t\t= scale xg?1 yg?1 (im_zoom im xg?0 yg?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// downscale by any factor, nearest neighbour \n\t\t// can't really do this right ... downscale by integer part, \n\t\t// then bilinear to exact size\n\t\t= scale xs?1 ys?1 (im_subsample im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tinterp == Interpolate.NEAREST_NEIGHBOUR\n\n\t\t// upscale by any factor, bilinear\n\t\t= scale xfac' yfac' im,\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.BILINEAR\n\n\t\t// downscale by any factor, bilinear\n\t\t// block shrink by integer factor, then bilinear resample to \n\t\t// exact\n\t\t= scale xs?1 ys?1 (im_shrink im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tinterp == Interpolate.BILINEAR\n\n\t\t= error (\"resize: unimplemented argument combination:\\n\" ++ \n\t\t\t\"  xfac = \" ++ print xfac' ++ \"\\n\" ++\n\t\t\t\"  yfac = \" ++ print yfac' ++ \"\\n\" ++\n\t\t\t\"  interp = \" ++ print interp ++ \" (\" ++\n\t\t\t\tInterpolate.names.lookup 1 0 interp ++ \")\")\n\t{\n\t\t// convert a float scale to integer plus fraction\n\t\t// eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25)\n\t\tbreak f = [floor f, f / floor f];\n\n\t\t// same, but for downsizing ... turn a float scale which is less than\n\t\t// 1 into an int shrink and a float scale\n\n\t\t// complicated: the int shrink may round the size down (eg. imagine\n\t\t// subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide\n\t\t// image, not a 3.666 pixel wide image), so pass in the size of image\n\t\t// we are operating on and adjust for any rounding\n\t\t\n\t\t// so ... x is (eg.) 467, f is (eg. 128/467, about 0.274)\n\t\trbreak x f \n\t\t\t= [int_shrink, float_resample]\n\t\t{\n\t\t\t// the size of image we are aiming for after the combined int and\n\t\t\t// float resample\n\t\t\tx' = x * f;\n\n\t\t\t// int part\n\t\t\tint_shrink = floor (1 / f);\n\n\t\t\t// size after int shrink\n\t\t\tx'' = floor (x / int_shrink);\n\n\t\t\t// therefore what we need for the float part\n\t\t\tfloat_resample = x' / x'';\n\t\t}\n\n\t\twidth = get_width im;\n\t\theight = get_height im;\n\n\t\t// grow and shrink factors\n\t\txg = break xfac';\n\t\tyg = break yfac';\n\t\txs = rbreak width xfac';\n\t\tys = rbreak height yfac';\n\n\t\t// binlinear resize\n\t\tscale xfac yfac im\n\t\t\t= im_affine im \n\t\t\t\txfac 0 0 yfac \n\t\t\t\t0 0 \n\t\t\t\t0 0 \n\t\t\t\t(rint (get_width im * xfac)) \n\t\t\t\t(rint (get_height im * yfac));\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nflood_blob x y v image\n\t= oo_unary_function flood_blob_op image, is_class image\n\t= im_flood_blob_copy image (to_real x) (to_real y) v, is_image image\n\t= error (_ \"bad arguments to \" ++ \"flood_blob\")\n{\n\tflood_blob_op = Operator \"flood_blob\" \n\t\t(flood_blob x y v) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (\\x x % base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (\\x idivide x base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= NULL, any (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Image (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n/* Linear regression. Return a class with the stuff we need in.\n * from s15.2, p 665 NR in C\n */\nlinreg xes yes\n    = obj\n{\n    obj = class {\n        // in case we ever get shown in the workspace\n        _vislevel = 2;\n\n        slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2;\n        intercept = (sy - sx * slope) / ss;\n\n        chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes];\n\n        siga = (chi2 / (ss - 2)) ** 0.5 *\n            ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5;\n        sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5;\n\n        // for compat with linregw, see below\n        q = 1.0;\n    }\n\n    ss = len xes;\n    sx = sum xes;\n    sy = sum yes;\n    sxoss = sx / ss;\n\n    tes = [x - sxoss :: x <- xes];\n    st2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Weighted linear regression. Xes, yes and a list of deviations.\n */\nlinregw xes yes devs \n\t= obj\n{\n\tobj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: \n\t\t\t[x, y, sd] <- zip3 xes yes devs];\n\n\t\tsiga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (1 / st2) ** 0.5;\n\n\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\t}\n\n\twt = [sd ** -0.5 :: sd <- devs];\n\n\tss = sum wt;\n\tsx = sum [x * w :: [x, w] <- zip2 xes wt];\n\tsy = sum [y * w :: [y, w] <- zip2 yes wt];\n\tsxoss = sx / ss;\n\n\ttes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Clustering: pass in a list of points, repeatedly merge the\n * closest two points until no two points are closer than the threshold.\n * Return [merged-points, corresponding-weights]. A weight is a list of the\n * indexes we merged to make that point, ie. len weight == how significant\n * this point is.\n *\n * eg. \n *\tcluster 12 [152,154,155,42,159] == \n *\t\t[[155,42],[[1,2,0,4],[3]]]\n */\ncluster thresh points\n\t= oo_unary_function cluster_op points, is_class points\n\t// can't use [0..len points - 1], in case len points == 0\n\t= merge [points, map (converse cons []) (take (len points) [0 ..])],\n\t\tis_list points\n\t= error (_ \"bad arguments to \" ++ \"cluster\")\n{\n\tcluster_op = Operator \"cluster\" \n\t\t(cluster thresh) Operator_type.COMPOUND false;\n\n\tmerge x\n\t\t= x, m < 2 || d > thresh\n\t\t= merge [points', weights']\n\t{\n\t\t[points, weights] = x;\n\t\tm = len points;\n\n\t\t// generate indexes of all possible pairs, avoiding comparing a thing \n\t\t// to itself, and assuming that dist is reflexive\n\t\t// first index is always less than 2nd index\n\t\t// the +1,+2 makes sure we have an increasing generator, otherwise we\n\t\t// can get [3 .. 4] (for example), which will make a decreasing\n\t\t// sequence\n\t\tpairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]];\n\n\t\t// distance function\n\t\t// arg is eg. [3,1], meaning get distance from point 3 to point 1\n\t\tdist x \n\t\t\t= abs (points?i - points?j)\n\t\t{\n\t\t\t[i, j] = x;\n\t\t}\n\n\t\t// smallest distance, then the two points we merge\n\t\tp = minpos (map dist pairs);\n\t\td = dist pairs?p;\n\t\t[i, j] = pairs?p;\n\n\t\t// new point and new weight\n\t\tnw = weights?i ++ weights?j;\n\t\tnp = (points?i * len weights?i + points?j * len weights?j) / len nw;\n\n\t\t// remove element i from a list\n\t\tremove i l = take i l ++ drop (i + 1) l;\n\n\t\t// remove two old points, add the new merged one\n\t\t// i < j (see \"pairs\", above)\n\t\tpoints' = np : remove i (remove j points);\n\t\tweights' = nw : remove i (remove j weights);\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.16/_types.def",
    "content": "/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t] ++ super._check_args;\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t] ++ super._check_args;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary (\\a op.fn a x) this,\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// we can't call map_trinary directly, since it uses Group and we\n\t// don't support mutually recursive top-level functions :-(\n\t// copy-paste it here, keep in sync with the version in _stdenv\n\tmap_nary fn args\n\t\t= fn args, groups == []\n\t\t= Group (map process [0, 1 .. shortest - 1])\n\t{\n\t\tgroups = filter is_Group args;\n\t\n\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\t\n\t\tprocess n\n\t\t\t= NULL, any (map (is_noval n) args)\n\t\t\t= map_nary fn (map (extract n) args)\n\t\t{\n\t\t\textract n arg\n\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t= arg;\n\t\n\t\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t\t}\n\t}\n\n\t// need ite as a true trinary\n\tite a b c = if a then b else c;\n\n\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t] ++ super._check_args;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t] ++ super._check_args;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t] ++ super._check_args;\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t] ++ super._check_args;\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t] ++ super._check_args;\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t] ++ super._check_args;\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t] ++ super._check_args;\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t] ++ super._check_args;\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t] ++ super._check_args;\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t] ++ super._check_args;\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t] ++ super._check_args;\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t] ++ super._check_args;\n\t_check_all = [\n\t\t[is_list_len 3 value, \"len value == 3\"]\n\t] ++ super._check_all;\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.value_name colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum Image_type.colour_spaces \"Colour space\" default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t] ++ super._check_args;\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t] ++ super._check_all;\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t] ++ super._check_args;\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t] ++ super._check_args;\n}\n\nOption_enum enum caption value_name = class\n\tOption caption enum.names (index (equal value_name) enum.names) {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing value_name;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum enum caption (enum.names ? value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t] ++ super._check_args;\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNONE = 0;\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNONE = 0;\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t] ++ super._check_args;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (map (extract col) value) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (map (extract from) value);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t] ++ super._check_args\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = map (extract 0) value;\n\tthings = map (extract 1) value;\n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tLUMINANCE = 2;\n\tXRAY = 3;\n\tIR = 4;\n\tYUV = 5;\n\tRED_ONLY = 6;\n\tGREEN_ONLY = 7;\n\tBLUE_ONLY = 8;\n\tPOWER_SPECTRUM = 9;\n\tHISTOGRAM = 10;\n\tLUT = 11;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMC = 14;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t$MULTIBAND => MULTIBAND,\n\t\t$B_W => B_W,\n\t\t$LUMINANCE => LUMINANCE,\n\t\t$XRAY => XRAY,\n\t\t$IR => IR,\n\t\t$YUV => YUV,\n\t\t$RED_ONLY => RED_ONLY,\n\t\t$GREEN_ONLY => GREEN_ONLY,\n\t\t$BLUE_ONLY => BLUE_ONLY,\n\t\t$POWER_SPECTRUM => POWER_SPECTRUM,\n\t\t$HISTOGRAM => HISTOGRAM,\n\t\t$LUT => LUT,\n\t\t$XYZ => XYZ,\n\t\t$LAB => LAB,\n\t\t$CMC => CMC,\n\t\t$CMYK => CMYK,\n\t\t$LABQ => LABQ,\n\t\t$RGB => RGB,\n\t\t$UCS => UCS,\n\t\t$LCH => LCH,\n\t\t$LABS => LABS,\n\t\t$sRGB => sRGB,\n\t\t$YXY => YXY,\n\t\t$FOURIER => FOURIER,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options generated from this, so match the order to the order in the\n\t * Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t$sRGB => sRGB,\n\t\t$Lab => LAB,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t$Mono => B_W,\n\t\t$sRGB => sRGB,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$Lab => LAB,\n\t\t$LabQ => LABQ,\n\t\t$LabS => LABS,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t] ++ super._check_args;\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// image ++ image is slightly different ... we want to\n\t\t// sizealike, but we must not bandalike\n\t\t[wrap \n\t\t\t(op.fn (get_image resized?0) (get_image resized?1)),\n\t\t\thas_image x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t// arithmetic and reational binops between image resize\n\t\t// and band_alike images to match\n\t\t[wrap \n\t\t\t(op.fn (get_image rebanded?0) (get_image rebanded?1)),\n\t\t\thas_image x &&\n\t\t\t(op.type == Operator_type.ARITHMETIC ||\n\t\t\t\top.type == Operator_type.RELATIONAL)],\n\t\t// other op types don't resize\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \"Image v ==\n\t\t// 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\t// if one of then/else is an image, get the target format from that\n\t\t// otherwise, let the non-image objects set the target\n\t\ttarget_format \n\t\t\t= get_member_list has_format get_format x, \n\t\t\t\thas_member_list has_format x\n\t\t\t= [];\n\n\t\tto_image x\n\t\t\t= x, is_image x\n\t\t\t= x.value, is_Image x\n\t\t\t= clip2fmt target_format im, target_format != []\n\t\t\t= im\n\t\t{\n\t\t\tim = im_black width height target_bands + x;\n\t\t}\n\n\t\t[if_size, then_size, else_size] = \n\t\t\tsize_alike (value : formats_alike (map to_image x));\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if if_size then then_size else else_size);\n\n\t\tresized = size_alike [this, x];\n\t\trebanded = bands_alike resized;\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t] ++ super._check_args;\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t] ++ super._check_args;\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t] ++ super._check_args;\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nInterpolate = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tnames = Enum [\n\t\t[_ \"Nearest neighbour\", NEAREST_NEIGHBOUR],\n\t\t[_ \"Bilinear\", BILINEAR],\n\t\t[_ \"Bicubic\", BICUBIC]\n\t];\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t[_ \"Perceptual\", PERCEPTUAL],\n\t\t[_ \"Relative\", RELATIVE],\n\t\t[_ \"Saturation\", SATURATION],\n\t\t[_ \"Absolute\", ABSOLUTE]\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t[_ \"Point\", POINT],\n\t\t[_ \"Line\", LINE],\n\t\t[_ \"Spline\", SPLINE],\n\t\t[_ \"Bar\", BAR]\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t[_ \"YYYY\", YYYY],\n\t\t[_ \"XYYY\", XYXY],\n\t\t[_ \"XYXY\", XYXY]\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [$format => Plot_format.XYYY] value {\n}\n\n/* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate\n * empty slots, for example.\n */\nNULL = class \n\t_Object {\n\too_binary_table op x = [\n\t\t// the only operation we allow is equality .. use pointer equality,\n\t\t// this lets us test a == NULL and a != NULL\n\t\t[this === x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"equal\"],\n\t\t[this !== x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"not_equal\"]\n\t] ++ super.oo_binary_table op x;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.24/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t[_L, _a, _b] = default_value;\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum spaces (_ \"Convert to\") (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum spaces (_ \"Tag as\") (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Colour Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum Whitepoints (_ \"Old whitepoint\") \"D65\";\n\t\t\tnew_white = Option_enum Whitepoints (_ \"New whitepoint\") \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= monitor_profile, has_bands image && get_bands image == 3\n\t\t= print_profile;\n\trender_intents = Option_enum Render_intent.names (_ \"Render intent\") \n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_rad_item = class\n\tMenupullright (_ \"_Radiance\") (_ \"convert to and from Radiance packed format\") {\n\tUnpack_item = class\n\t\tMenuaction (_ \"Unpack\") \n\t\t\t(_ \"unpack Radiance format to float\") {\n\t\taction x = map_unary rad2float x;\n\t}\n\n\tPack_item = class\n\t\tMenuaction (_ \"Pack\") \n\t\t\t(_ \"pack 3-band float to Radiance format\") {\n\t\taction x = map_unary float2rad x;\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure 0 0 in.width in.height \n\t\t\t\t\t(to_real pacross) (to_real pdown) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.24/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 1.5;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 50;\n\t\t\tfs = Scale \"Sharpen flat areas by\" (-2) 5 1;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" (-2) 5 2;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\t\t\trotate = Option \"Rotate\" [\n\t\t\t\t\"Don't rotate\", \n\t\t\t\t\"4 x 45 degrees\", \n\t\t\t\t\"8 x 45 degrees\", \n\t\t\t\t\"2 x 90 degrees\"] \n\t\t\t0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_lindetect, !separable && type == 0 && rotate == 1\n\t\t\t\t\t\t= im_compass, !separable && type == 0 && rotate == 2\n\t\t\t\t\t\t= im_gradient, !separable && type == 0 && rotate == 3\n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_conv_f, !separable && type == 1\n\t\t\t\t\t\t= im_convsep_f, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 4) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tSegment_item = class\n\t\tMenuaction \"_Segment\" \"break image into disjoint regions\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsegments\n\t\t\t\t= Expression \"Number of disjoint regions\" \n\t\t\t\t\t(map_unary (get_header \"n-segments\") _result);\n\n\t\t\t_result = map_unary segment x;\n\t\t}\n\t}\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width.expr window_height.expr in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\nFilter_greyc_item = class \n\tMenupullright \"_GREYCstoration\" \"noise-removing filter\" {\n\tDenoise_item = class \n\t\tMenuaction \"Denoise\" \"Noise-removing filter\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\titerations = Scale \"Iterations\" 1 5 1;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 40;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.9;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.15;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.6;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.1;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) x;\n\t\t}\n\t}\n\n\tEnlarge_item = class\n\t\tMenuaction \"Enlarge\" \"Enlarge image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Enlarge\" 1 10 3;\n\t\t\titerations = Scale \"Iterations\" 1 5 3;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 20;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.2;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.9;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.1;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.5;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) \n\t\t\t\t\t(resize Interpolate_bilinear\n\t\t\t\t\t\t(to_real scale) (to_real scale) x);\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image\" \"use an image to blend two objects\" {\n\t\taction a b c = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ti = Toggle \"Invert mask\" false;\n\n\t\t\t_result \n\t\t\t\t= map_trinary process a b c\n\t\t\t{\n\t\t\t\tprocess a b c \n\t\t\t\t\t= blend condition in1 in2, !i\n\t\t\t\t\t= blend (invert condition) in1 in2\n\t\t\t\t{\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t\t= false,\n\t\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t\t= true;\n\t\t\t\t\t[condition, in1, in2] = sortc compare [a, b, c];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"_Alpha\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\t\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t[_ \"Normal\", NORMAL],\n\t\t\t[_ \"If Lighter\", IFLIGHTER],\n\t\t\t[_ \"If Darker\", IFDARKER],\n\t\t\t[_ \"Multiply\", MULTIPLY],\n\t\t\t[_ \"Add\", ADD],\n\t\t\t[_ \"Subtract\", SUBTRACT],\n\t\t\t[_ \"Screen\", SCREEN],\n\t\t\t[_ \"Burn\", BURN],\n\t\t\t[_ \"Soft Light\", SOFTLIGHT],\n\t\t\t[_ \"Hard Light\", HARDLIGHT],\n\t\t\t[_ \"Lighten\", LIGHTEN],\n\t\t\t[_ \"Darken\", DARKEN],\n\t\t\t[_ \"Dodge\", DODGE],\n\t\t\t[_ \"Reflect\", REFLECT],\n\t\t\t[_ \"Freeze\", FREEZE],\n\t\t\t[_ \"Bitwise OR\", OR],\n\t\t\t[_ \"Bitwise AND\", AND]\n\t\t];\n\t\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum names \"Blend mode\" \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\t[mono, colour] = \n\t\t\t\t\tsortc (const (is_colour_type @ get_type)) [a, b];\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t\t_ \"Grey\",\n\t\t\t\t_ \"Green over Red\",\n\t\t\t\t_ \"Blue over Red\",\n\t\t\t\t_ \"Red over Green\",\n\t\t\t\t_ \"Red over Blue\",\n\t\t\t\t_ \"Blue over Green\",\n\t\t\t\t_ \"Green over Blue\"\n\t\t\t] 0;\n\t\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t_ \"North-west\",\n\t\t\t\t_ \"North\",\n\t\t\t\t_ \"North-east\",\n\t\t\t\t_ \"West\",\n\t\t\t\t_ \"Centre\",\n\t\t\t\t_ \"East\",\n\t\t\t\t_ \"South-west\",\n\t\t\t\t_ \"South\",\n\t\t\t\t_ \"South-east\",\n\t\t\t\t_ \"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.24/Histogram.def",
    "content": "Hist_new_item = class\n\tMenupullright \"_New\" \"new histogram\" {\n\tHist_item = class\n\t\tMenuaction \"Histogram\" \"make an identity histogram\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\t_result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d);\n\t\t}\n\t}\n\n\tHist_new_from_matrix = Matrix_buildlut_item; \n\n\tHist_from_image_item = class\n\t\tMenuaction \"Ta_g Image As Histogram\" \"set image Type to Histogram\" {\n\t\taction x = hist_tag x;\n\t}\n\n\tTone_item = class \n\t\tMenuaction \"_Tone Curve\" \"make a new tone mapping curve\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\t_result \n\t\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t\t{\n\t\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_find_item = class \n\tMenupullright \"_Find\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n\n\tIndexed_item = class\n\t\tMenuaction \"_Indexed\" \n\t\t\t\"use a 1-band index image to pick bins for an n-band image\" {\n\t\taction x y \n\t\t\t= map_binary map x y\n\t\t{\n\t\t\tmap a b\n\t\t\t\t= hist_find_indexed index im\n\t\t\t{\n\t\t\t\t[im, index] = sortc (const is_index) [a, b];\n\n\t\t\t\tis_index x\n\t\t\t\t\t= has_image x && b == 1 && \n\t\t\t\t\t\t(f == Image_format.UCHAR || f == Image_format.USHORT)\n\t\t\t\t{\n\t\t\t\t\tim = get_image x;\n\t\t\t\t\tb = get_bands x;\n\t\t\t\t\tf = get_format x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\t[im, hist] = sortc (const is_hist) [a, b];\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Cumulativise\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate\" \n\t\t\"find point-to-point differences (inverse of Cumulativise)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\tarea = extract_arrow \n\t\t\t\t\tdisplace.value vdisplace.value width.value arrow;\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize Interpolate_bilinear 1 (1 / width.value) area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary (extract_arrow \n\t\t\t\tdisplace.value vdisplace.value width.value) x;\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tformat = Option_enum Plot_format.names \"Format\" \"YYYY\";\n\t\tstyle = Option_enum Plot_style.names \"Style\" \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => style.value, $format => format.value] ++ range;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow 0 0 1 x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.24/Image.def",
    "content": "Image_new_item = class \n\tMenupullright \"_New\" \"make new things\" {\n\tImage_black_item = class \n\t\tMenuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \n\t\t\t\tImage_type.type_names \"Image type\" \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region on image using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\t[target, x] = sortc compare [a, b];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\nImage_number_format_item = class\n\tMenupullright \"_Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_header_item = class \n\tMenupullright \"_Header\" \"do stuff to the image header\" {\n\n\tImage_get_item = class\n\t\tMenupullright \"_Get\" \"get header fields\" {\n\n\t\t// the header fields we can get\n\t\tfields = class {\n\t\t\ttype = 0;\n\t\t\twidth = 1;\n\t\t\theight = 2;\n\t\t\tformat = 3;\n\t\t\tbands = 4;\n\t\t\txres = 5;\n\t\t\tyres = 6;\n\t\t\txoffset = 7;\n\t\t\tyoffset = 8;\n\t\t\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t$width => width,\n\t\t\t\t$height => height,\n\t\t\t\t$bands => bands,\n\t\t\t\t$format => format,\n\t\t\t\t$type => type,\n\t\t\t\t$xres => xres,\n\t\t\t\t$yres => yres,\n\t\t\t\t$xoffset => xoffset,\n\t\t\t\t$yoffset => yoffset,\n\t\t\t\t$coding => coding\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum field_names (_ \"Field\") name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tCustom_item = class\n\t\t\tMenuaction \"C_ustom\" \"get any header field\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tfield = String \"Field\" \"Xsize\";\n\t\t\t\tparse = Option \"Parse\" [\n\t\t\t\t\t\"No parsing\",\n\t\t\t\t\t\"Parse string as integer\",\n\t\t\t\t\t\"Parse string as real\",\n\t\t\t\t\t\"Parse string as hh:mm:ss\"\n\t\t\t\t] 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary (wrap @ process @ get_header field.value) x\n\t\t\t\t{\n\t\t\t\t\tparse_str parse str = parse (split is_space str)?0;\n\n\t\t\t\t\tparse_field name cast parse x\n\t\t\t\t\t\t= cast x, is_number x\n\t\t\t\t\t\t= parse_str parse x, is_string x\n\t\t\t\t\t\t= error (\"not \" ++ name);\n\n\t\t\t\t\tget_int = parse_field \"int\" \n\t\t\t\t\t\tcast_signed_int parse_int;\n\t\t\t\t\tget_float = parse_field \"float\" \n\t\t\t\t\t\tcast_float parse_float;\n\t\t\t\t\tget_time = parse_field \"hh:mm:ss\" \n\t\t\t\t\t\tcast_signed_int parse_time;\n\n\t\t\t\t\twrap x\n\t\t\t\t\t\t= Real x, is_real x\n\t\t\t\t\t\t= Vector x, is_real_list x\n\t\t\t\t\t\t= Image x, is_image x\n\t\t\t\t\t\t= Bool x, is_bool x\n\t\t\t\t\t\t= Matrix x, is_matrix x\n\t\t\t\t\t\t= String \"String\" x, is_string x\n\t\t\t\t\t\t= List x, is_list x\n\t\t\t\t\t\t= x;\n\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tget_int, \n\t\t\t\t\t\tget_float,\n\t\t\t\t\t\tget_time\n\t\t\t\t\t]?parse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum Image_type.type_names \"Image type\"\n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_cache_item = class\n\tMenuaction \"C_ache\" \"cache calculated image pixels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttile_width = Number \"Tile width\" 128;\n\t\ttile_height = Number \"Tile height\" 128;\n\t\tmax_tiles = Number \"Maximum number of tiles to cache\" (-1);\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= cache (to_real tile_width) (to_real tile_height) \n\t\t\t\t\t(to_real max_tiles) image;\n\t\t}\n\t}\n}\n\n#separator\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in = [\n\t\t\t\t\t\tin, \n\t\t\t\t\t\trot90 in,\n\t\t\t\t\t\trot180 in,\n\t\t\t\t\t\trot270 in\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate interp angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary straighten x\n\t\t\t\t{\n\t\t\t\t\tstraighten arrow\n\t\t\t\t\t\t= rotate interp angle'' arrow.image\n\t\t\t\t\t{\n\t\t\t\t\t\tx = arrow.width;\n\t\t\t\t\t\ty = arrow.height;\n\t\t\n\t\t\t\t\t\tangle = im (polar (x, y));\n\t\t\n\t\t\t\t\t\tangle'\n\t\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t\t= angle;\n\t\t\n\t\t\t\t\t\tangle''\n\t\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize interp xfactor yfactor image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\taspect = Toggle \"Break aspect ratio\" false;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize interp h v image, aspect\n\t\t\t\t\t\t= resize interp fac fac image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac > yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\tmin_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac < yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\t[h, v] = [\n\t\t\t\t\t\t\tmax_factor, \n\t\t\t\t\t\t\tmin_factor, \n\t\t\t\t\t\t\t[xfac, 1], \n\t\t\t\t\t\t\t[1, yfac]]?which;\n\n\t\t\t\t\t\tfac \n\t\t\t\t\t\t\t= h, v == 1\n\t\t\t\t\t\t\t= v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_within_item = class\n\t\t\tMenuaction \"Size _Within\" \"size to fit within a rectangle\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\t// the rects we size to fit within\n\t\t\t\t_rects = [\n\t\t\t\t\t[2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], \n\t\t\t\t\t[1280, 1024], [1024, 768], [800, 600], [640, 480] \n\t\t\t\t];\n\n\t\t\t\twithin = Option \"Fit within (pixels)\" (\n\t\t\t\t\t[print w ++ \" x \" ++ print h :: [w, h] <- _rects] ++\n\t\t\t\t\t[\"Custom\"]\n\t\t\t\t) 4;\n\t\t\t\tcustom_width = Expression \"Custom width\" 1000;\n\t\t\t\tcustom_height = Expression \"Custom height\" 1000;\n\t\t\t    size = Option \"Page size\" [\n\t\t\t\t\t\"Full page\", \"Half page\", \"Quarter page\" \n\t\t\t\t] 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t \t_result\n\t\t\t\t \t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\txdiv = [1, 2, 2]?size;\n\t\t\t\t\tydiv = [1, 1, 2]?size;\n\t\t\t\t\tallrect = _rects ++ [\n\t\t\t\t\t\t[custom_width.expr, custom_height.expr]\n\t\t\t\t\t];\n\t\t\t\t\t[width, height] = allrect?within;\n\n\t\t\t\t\tprocess x\n\t\t\t\t\t\t= resize interp fac fac x, fac < 1\n\t\t\t\t\t\t= x\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = (width / xdiv) / x.width;\n\t\t\t\t\t\tyfac = (height / ydiv) / x.height;\n\t\t\t\t\t\tfac = min_pair xfac yfac;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\" [\"Nearest\", \"Bilinear\"] 1;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_trn {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t[sample', trn, err] = transform_search \n\t\t\t\t\tmax_err max_iter order interp wrap\n\t\t\t\t\tsample reference;\n\t\t\t\ttransformed_image = Image sample';\n\t\t\t\t_trn = Transform trn reference.width reference.height;\n\t\t\t\tfinal_error = err;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\t[i, t] = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tBandwise_item = Image_join_item.Bandwise_item;\n\n    sep1 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldl1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find the image geometry ... don't bother trying to look\n\t\t// inside groups though\n\t\t_geo\n\t\t\t= x.rect, is_Image x\n\t\t\t= Rect 0 0 100 100;\n\n\t\tl = Expression \"Crop left\" ((int) (_geo.left + _geo.width / 4));\n\t\tt = Expression \"Crop top\" ((int) (_geo.top + _geo.height / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (_geo.width / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (_geo.height / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t[_a', _b'] = sortc _pred [a, b];\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t// we can't use map_unary since chop-into-tiles returns a group of\n\t\t\t// groups and we want to be able to reassemble that\n\t\t\t// TODO: chop-into-tiles should return an array class which\n\t\t\t// displays as group but does not have the looping behaviour?\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n\n\tArrayFL_item = class\n\t\tMenuaction \"_Array from List\"\n\t\t\t\"join a list of images into a single image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tncol = Number \"Max. Number of Columns\" 1;\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t_l \n\t\t\t\t= split_lines ncol.value x.value, is_Group x\n\t\t\t\t= split_lines ncol.value x;\n\n\t\t\t_result\n\t\t\t\t= (image_set_origin 0 0 @\n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value\n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list _l));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tGaussian_item = class \n\t\tMenuaction \"Gaussian _Noise\" \"make an image of gaussian noise\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t_result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) \n\t\t\t\tmean.value deviation.value);\n\t\t}\n\t}\n\n\tFractal_item = class \n\t\tMenuaction \"_Fractal\" \"make a fractal image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t}\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n\tColour_atlas_item = class\n\tMenuaction \"_Colour Atlas\"\n\t\t\"make a grid of patches grouped around a colour\" {\n\t\taction = class \n\t\t\t_result {   \n\t\t\t_vislevel = 3;\n       \n\t\t\tstart = Colour_picker \"Lab\" [50,0,0];\n\t\t\tnstep = Expression \"Number of steps\" 9;\n\t\t\tssize = Expression \"Step size\" 10; \n\t\t\tpsize = Expression \"Patch size\" 32;\n\t\t\tsepsize = Expression \"Separator size\" 4;\n\t\n\t\t\t_result\n\t\t\t\t= colour_transform_to (get_type start) blocks'''\n\t\t\t{\n\t\t\t\tsize = (to_real nstep * 2 + 1) * to_real psize - \n\t\t\t\t\tto_real sepsize;\n\t\t\t\txy = make_xy size size; \n\n\t\t\t\txy_grid = (xy % to_real psize) < \n\t\t\t\t\t(to_real psize - to_real sepsize);\n\t\t\t\tgrid = xy_grid?0 & xy_grid?1;\n\n\t\t\t\tblocks = (int) (to_real ssize * ((int) (xy / to_real psize)));\n\t\t\t\tlab_start = colour_transform_to Image_type.LAB start;\n\t\t\t\tblocks' = blocks - to_real nstep * to_real ssize + \n\t\t\t\t\tVector (tl lab_start.value);\n\t\t\t\tblocks'' = hd lab_start.value ++ Image blocks';\n\t\t\t\tblocks''' \n\t\t\t\t\t= image_set_type Image_type.LAB blocks'', Image grid\n\t\t\t\t\t= 0;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.24/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/7.24\n\nstart_DATA = \\\n\tMath.def \\\n\tImage.def \\\n\tColour.def \\\n\tTasks.def \\\n\tObject.def \\\n\tFilter.def \\\n\tMatrix.def \\\n\tWidgets.def \\\n\tHistogram.def \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_convert.def \\\n\t_generate.def \\\n\t_list.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\t_Object.def \\\n\t_types.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/7.24/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_And\" \"bitwise and of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_Or\" \"bitwise or of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"E_xclusive Or\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_Not\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBand_or_item = class \n\t\tMenuaction \"Band O_r\" \"or the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_or @ bandsplit) im;\n\t}\n\n\tBand_and_item = class \n\t\tMenuaction \"Band A_nd\" \"and the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_and @ bandsplit) im;\n\t}\n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tDifference_item = class \n\t\tMenuaction \"_Difference\" \"difference of two lists\" {\n\t\taction a b = map_binary difference a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tValue_item = class \n\t\tMenuaction \"_Value\" \"value of point in object\" {\n\t\taction a = class _result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tposition = Expression \"Coordinate\" (0, 0);\n\t\n\t\t\t_result = map_binary point position.expr a;\n\t\t}\n\t}\n\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \n\t\t\t\"position of centre of gravity of histogram\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = linreg xes yes;\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = linregw xes yes devs;\n\t}\n\n\tCluster_item = class \n\t\tMenuaction \"_Cluster\" \"cluster a list of numbers\" {\n\t\taction l = class {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tthresh = Expression \"Threshold\" 10;\n\t\n\t\t\t[_r, _w] = cluster thresh.expr l;\n\t\n\t\t\tresult = _r;\n\t\t\tweights = _w;\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.24/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ \n\t\t\t\t\trange;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.24/Object.def",
    "content": "Object_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nObject_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nObject_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nObject_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nObject_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list (or group) of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.24/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\n\tCsv_import_item = class\n\t\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tstart_line = Expression \"Start at line\" 1;\n\t\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_csv2vips filename)\n\t\t\t{\n\t\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\t\tescape x \n\t\t\t\t\t= foldr prefix [] x\n\t\t\t\t{\n\t\t\t\t\tprefix x l\n\t\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t\t= x : l;\n\t\t\t\t}\n\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tRaw_import_item = class\n\t\tMenuaction \"_Raw Import\" \"read a file of binary values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tacross = Expression \"Pixels across\" 100;\n\t\t\tdown = Expression \"Pixels down\" 100;\n\t\t\tbytes = Expression \"Bytes per pixel\" 3;\n\t\t\tskip = Expression \"Skip over initial bytes\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_binfile path.value \n\t\t\t\t\tacross.expr down.expr bytes.expr skip.expr)\n\t\t\t{\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// interpret Analyze header for layout and calibration\n\tAnalyze7_header_item = class\n\t\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\t\"examine the Analyze header and set layout and value\" {\n\t\taction x \n\t\t\t= x'''\n\t\t{\n\t\t\t// read bits of header\n\t\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\t\tdim0 = dim 0 x;\n\t\t\tdim1 = dim 1 x;\n\t\t\tdim2 = dim 2 x;\n\t\t\tdim3 = dim 3 x;\n\t\t\tdim4 = dim 4 x;\n\t\t\tdim5 = dim 5 x;\n\t\t\tdim6 = dim 6 x;\n\t\t\tdim7 = dim 7 x;\n\t\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\t\n\t\t\t// oops, now a nop\n\t\t\tx' = x;\n\t\n\t\t\t// lay out higher dimensions width-ways\n\t\t\tx'' \n\t\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\t\tdim0 == 7\n\t\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\t\n\t\t\t// multiply by scale factor to get kBeq\n\t\t\tx''' = x'' * (cal_max / glmax);\n\t\t}\n\t}\n\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\t[image, patch] = sortc larger [a, b];\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\tmode = Option \"Input LUT\" [\n\t\t\t\t\"Linear input\",\n\t\t\t\t\"Fit intercept from chart greyscale\",\n\t\t\t\t\"Linearize input from chart greyscale\"\n\t\t\t] 2;\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = measure 0 0 image.width image.height 6 4 image.value;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb \n\t\t\t\t= Matrix [[0, 0], [1, 1]], mode == 0\n\t\t\t\t= Matrix [0: intercepts, replicate (_camera.width + 1) 1], \n\t\t\t\t\tmode == 1\n\t\t\t\t= Matrix (map2 cons _true_grey_Y' _camera_grey')\n\t\t\t{\n\t\t\t\tintercepts = [(linreg _true_grey_Y' cam).intercept :: \n\t\t\t\t\tcam <- transpose _camera_grey'];\n\t\t\t}\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\t// plot from 0 explicitly so we see the effect of mode1 (intercept\n\t\t\t// from greyscale)\n\t\t\tlinearising_lut = Plot [$ymin => 0] _linear_lut;\n\n\t\t\t// map the original image through the lineariser to \n\t\t\t// get linear 0-1 RGB image\n\t\t\t_image' = hist_map linearising_lut.value image.value;\n\n\t\t\t// remeasure and solve for RGB -> XYZ\n\t\t\t_camera' = im_measure _image' 0 0 image.width image.height 6 4;\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\tM = transpose (_pinv * transpose _camera' * _true_XYZ);\n\n\t\t\t// convert linear RGB camera to Lab \n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tcast_float @\n\t\t\t\trecomb M) _image';\n\n\t\t\t// measure again and compute dE76\n\t\t\t_camera'' = im_measure _result.value 0 0 \n\t\t\t\timage.width image.height 6 4;\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tfinal_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0 && i < len macbeth_names\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b = class\n\t\t\t(map_binary process a b) {\n\t\t\tprocess a b\n\t\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t\t{\n\t\t\t\t// the name of the calib object we need\n\t\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t\t// get the Calibrate_chart arg first\n\t\t\t\t[image, calib] = sortc (const (is_instanceof calib_name)) \n\t\t\t\t\t[a, b];\n\n\t\t\t\t// map the original image through the lineariser to get \n\t\t\t\t// linear 0-1 RGB image\n\t\t\t\timage' = hist_map calib.linearising_lut image;\n\n\t\t\t\t// convert linear RGB camera to Lab \n\t\t\t\tresult = colour_transform Image_type.XYZ Image_type.LAB \n\t\t\t\t\t((float) (recomb calib.M image'));\n\t\t\t}\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum Plot_style.names \"Style\" \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [$style => style.value] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\t!is_list_len 2 images\n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = all (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize Interpolate_bilinear xfactor yfactor scale_im;\n\t\t\t_offset_im = resize Interpolate_bilinear xfactor yfactor offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.24/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.24/_Object.def",
    "content": "/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0|1|2|3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \n\tjoin_sep \"|\" Image_type.colour_spaces.names];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide|VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad properties for \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"where\" ++ \"\\n\" ++ arg_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make arg type notes\n\targ_types = join_sep \"\\n\" (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"\\n\" ++ _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = join_sep \"\\n\" all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if those fail as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if that fails as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary'_function op a b\n\t= matches1?0, matches1 != []\n\t= matches2?0, op.symmetric && matches2 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0, matches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t// these should always be defined\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x = oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x = oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op = oo_unary_function (oo_unary_lookup op) this;\n\n\too_binary_table op x = [];\n\too_unary_table op = [];\n}\n"
  },
  {
    "path": "share/nip2/compat/7.24/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n// like to_image, but we do 1x1 pixel + x, then embed it up\n// always make an unwrapped image for speed ... this gets used by ifthenelse\n// and stuff like that\n// format can be NULL, meaning set format from x\nto_image_size width height bands format x\n\t= x, is_image x\n\t= x.value, is_Image x\n\t= im''\n{\n\t// we want x to set the target format if we don't have one, so we\n\t// can't use image_new\n\tim = im_black 1 1 bands + x;\n\tim'\n\t\t= clip2fmt format im, format != NULL\n\t\t= im;\n\tim'' = embed 1 0 0 width height im';\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && is_list_len 3 x\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The innermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x && !contains_Group x\n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), !is_list_len 2 parts \n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, !is_list_len 4 parts \n\t= (ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", member \".0123456789\",\n\t\tmember \"eE\", member \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), !is_list_len 5 parts \n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t$D93 => D93_whitepoint,\n\t$D75 => D75_whitepoint,\n\t$D65 => D65_whitepoint,\n\t$D55 => D55_whitepoint,\n\t$D50 => D50_whitepoint,\n\t$A => A_whitepoint,\n\t$B => B_whitepoint,\n\t$C => C_whitepoint,\n\t$E => E_whitepoint,\n\t$D3250 => D3250_whitepoint\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, image_set_type GREY16 @ im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* Given a list of things, try to make them all the same size. Don't change\n * the format. Don't touch non-image things.\n */\nsize_alike l\n\t= map enlarge l\n{\n\tmax_width = foldr (test_prop has_width get_width) 0 l;\n\tmax_height = foldr (test_prop has_height get_height) 0 l;\n\n\ttest_prop has get x best\n\t\t= best, !has x\n\t\t= max_pair best (get x);\n\n\tenlarge x\n\t\t= embed 0 0 0 max_width max_height x, has_width x\n\t\t= x;\n}\n\n/* Given a list of things, look for 1 band objects and bump them to to n -\n * band objects, where n is the maximum number of bands. Don't change the \n * format. Don't touch non-image things.\n */\nbands_alike l\n\t= map upband l\n{\n\tmax_bands = foldr (test_prop has_bands get_bands) 0 l;\n\n\ttest_prop has get x best\n\t\t= best, !has x\n\t\t= max_pair best (get x);\n\n\tupband x\n\t\t= bandjoin (replicate max_bands x),\n\t\t\thas_bands x && get_bands x == 1\n\t\t= x;\n}\n\n/* Given a list of things, try to match the formats. Don't touch non-image\n * objects.\n */\nformats_alike l\n\t= map upformat l\n{\n\tmax_format = foldr (test_prop has_format get_format) Image_format.UCHAR l;\n\n\ttest_prop has get x best\n\t\t= best, !has x\n\t\t= max_pair best (get x);\n\n\tupformat x\n\t\t= clip2fmt max_format x,\n\t\t\thas_format x \n\t\t= x;\n}\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l = join_sep path_separator l;\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 == 2 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n"
  },
  {
    "path": "share/nip2/compat/7.24/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= embed 1 0 0 w h im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black 1 1 (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = im_gauss_imask_sep (radius / 3) 0.2;\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.24/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 1;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" ] 4;\n\n\n\tcontrol_selection mask im no\n\t\t= (if mask then im * 1.2 else im * 1), no == 0\n\t\t= (if mask then im * 0.8 else im * 1), no == 1\n\t\t= (if mask then 0 else im), no == 2\n\t\t= (if mask then 255 else im), no == 3\n\t\t= (if mask then im else 0), no == 4\n\t\t= (if mask then im else 255), no == 5\n\t\t= mask;\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = get_image a;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = get_image ((pt_list.value)?0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize Interpolate_bilinear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize Interpolate_bilinear f1 1 b1\n\t\t\t\t\t{b1 = resize Interpolate_bilinear 1 f2 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/7.24/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = Image (get_image line);\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\t\t\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = Image (get_image (pt_l?0));\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t};\n\nMount_options _ctype _ppcm = class \n  {\n  _vislevel = 3;\n  apply = Toggle \"Apply mount options\" false;\n  ls = Expression \"Lower mount section bigger by (cm)\" 0;\n  mount_colour = Colour _ctype [0, 0, 0];\n  _los = ls.expr * _ppcm;\n  };\n\nFrame_variables comp = class\n  {\n  _vislevel = 3;\n\n  scale_factor = Expression \"scale the size of the frame by\" 1;\n\n  /* These sliders define the fraction of the frames width or height is extracted\n   * to produce each of the particular regions.\n   */\n  corner_section = Scale \"Corner section\" 0.1 1 0.5;\n  edge_section = Scale \"Edge section\" 0.1 1 0.2, comp > 0\n\t\t\t\t  = \"Only required for complex frames\";\n  middle_section = Scale \"Middle section\" 0.1 1 0.2;\n  blend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n  option = Toggle \"Use mirror of left-side to make right\" true;\n  };\n\n"
  },
  {
    "path": "share/nip2/compat/7.24/_list.def",
    "content": "/* any l: or all the elements of list l together\n *\n * any (map (equal 0) list) == true, if any element of list is zero.\n * any :: [bool] -> bool\n */\nany = foldr logical_or false;\n\n/* all l: and all the elements of list l together\n *\n * all (map (==0) list) == true, if every element of list is zero.\n * all :: [bool] -> bool\n */\nall = foldr logical_and true;\n\n/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* delete eq x l: delete the first x from l\n *\n * delete equal 'b' \"abcdb\" == \"acdb\"\n * delete :: (* -> bool) -> * -> [*] -> [*]\n */\ndelete eq a l\n\t= [], l == []\n\t= y, eq a b\n\t= b : delete eq a y\n{\n\tb:y = l;\n}\n\n/* difference eq a b: delete b from a\n *\n * difference equal \"asdf\" \"ad\" == \"sf\"\n * difference :: (* -> bool) -> [*] -> [*] -> [*]\n */\ndifference = foldl @ converse @ delete;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn x, fn a\n\t= l\n{\n\ta:x = l;\n}\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st (hd l)) (tl l);\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn (hd l) (tl l);\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn (hd l) (foldr fn st (tl l));\n\n/* foldrl fn l: like foldr, but use the 1st element as the start value\n *\n * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= foldr fn (hd l) (tl l);\n\n/* Search a list for an element, returning its index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn (hd l)\n\t\t= search (tl l) (n + 1);\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= hd l : init (tl l);\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* join_sep sep l: join a list with a separator\n *\n * join_sep \", \" (map print [1 .. 4]) == \"1, 2, 3, 4\"\n * join_sep :: [*] -> [[*]] -> [*]\n */\njoin_sep sep l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ sep ++ b;\n}\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= hd l, tl l == []\n\t= last (tl l);\n\n/* len l: length of list l\n * (see also is_list_len and friends in predicate.def)\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta:b:x = l;\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = any (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge p l r\n\t= [], p == [] || l == [] || r == []\n\t= a : merge z x y, c\n\t= b : merge z x y\n{\n\ta:x = l;\n\tb:y = r;\n\tc:z = p;\n}\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta:x = l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scan fn st l: apply (fold fn r) to every initial segment of a list\n *\n * scan add 0 [1,2,3] == [1,3,6]\n * scan :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscan fn \n\t= g \n{\n\tg st l\n\t\t= [st], l == []\n\t\t= st : g (fn st a) x\n\t{\n\t\ta:x = l;\n\t}\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta:x = l1;\n\t\tb:y = l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/7.24/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = any (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && all (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* Test list length ... quicker than len x == n for large lists.\n */\nis_list_len n x\n\t= true, x == [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len (n - 1) (tl x);\n\nis_list_len_more n x\n\t= true, x != [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len_more (n - 1) (tl x);\n\nis_list_len_more_equal n x\n\t= true, n == 0\n\t= false, x == [] \n\t= is_list_len_more_equal (n - 1) (tl x);\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, all (map is_obj l)\n\t= true, all (map is_list l) &&\n\t\tall (map (not @ is_obj) l) &&\n\t\tall (map is_rectangular l) &&\n\t\tis_list_len_more 0 l &&\n\t\tall (map (is_list_len (len (hd l))) (tl l))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && is_list_len (len (hd l)) l;\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_NULL x = is_instanceof \"NULL\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && all (map xy l)\n{\n\txy l = is_real_list l && is_list_len 2 l;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && any (map is_Group l)\n\t= any (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= error (\"get_type: unable to get type from \" ++ print x)\n{\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\t// can have alpha, hence we let bands be one more than you might think\n\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.GREY16, type == Image_type.GREY16 && is_bands 1\n\t\t= Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && \n\t\t\t(width == 1 || height == 1)\n\t\t= Image_type.B_W, is_bands 1 \n\t\t= Image_type.CMYK, type == Image_type.CMYK && is_bands 4\n\t\t= type, is_colorimetric && is_bands 3\n\t\t= Image_type.sRGB, !is_colorimetric && is_bands 3\n\t\t= Image_type.MULTIBAND, !is_colorimetric && !is_bands 3\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\n\t\t// is bands n, with an optional alpha (ie. can be n + 1 too)\n\t\tis_bands n = bands == n || bands == n + 1;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= error (\"get_format: unable to get format from \" ++ print x);\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= error (\"get_bits: unable to get bits from \" ++ print x);\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= error (\"get_bands: unable to get bands from \" ++ print x);\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= error (\"get_coding: unable to get coding from \" ++ print x);\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= error (\"get_xres: unable to get xres from \" ++ print x);\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= error (\"get_yres: unable to get yres from \" ++ print x);\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= error (\"get_xoffset: unable to get xoffset from \" ++ print x);\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= error (\"get_yoffset: unable to get yoffset from \" ++ print x);\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= error (\"get_image: unable to get image from \" ++ print x);\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= error (\"get_number: unable to get number from \" ++ print x);\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= error (\"get_real: unable to get real from \" ++ print x);\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= error (\"get_width: unable to get width from \" ++ print x);\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= error (\"get_height: unable to get height from \" ++ print x);\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= error (\"get_left: unable to get left from \" ++ print x);\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= error (\"get_top: unable to get top from \" ++ print x);\n\n// like has/get member, but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.24/_stdenv.def",
    "content": "/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\nidivide a b = (int) ((int) a / (int) b);\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\n// 'difference' is defined in _list\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the function we call for \"a -> v\" expressions\nmksvpair s v\n\t= [s, v], is_string s\n\t= error \"not str on lhs of ->\";\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error (\"unimplemented vector operation: \" ++ op_name)\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n// make a name value pair\nmknvpair n v\n\t= [n, v], is_string n\n\t= error \"not [char] on LHS of =>\";\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined, has_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nsum x\n\t= oo_unary_function sum_op x, is_class x\n\t= im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x\n\t= sum_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"sum\")\n{\n\tsum_op = Operator \"sum\" sum Operator_type.COMPOUND false;\n\n\t// add elements in a nested-list thing\n\tsum_list l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nproduct x\n\t= oo_unary_function product_op x, is_class x\n\t= product_list x, is_list x \n\t// (product image) doesn't make much sense :(\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"product\")\n{\n\tproduct_op = Operator \"product\" product Operator_type.COMPOUND false;\n\n\tproduct_list l\n\t\t= foldr prod 1 l\n\t{\n\t\tprod x total\n\t\t\t= total * product x, is_list x\n\t\t\t= total * x;\n\t}\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image_hist x, is_image x && \n\t\t(fmt == Image_format.UCHAR || fmt == Image_format.USHORT)\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tfmt = get_format x;\n\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean, for any image type\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n\n\t// image mean for 8 and 16-bit unsigned images\n\t// we can use a histogram, yay, and save a pass through the image\n\tmeanze_image_hist i\n\t\t= sum / N\n\t{\n\t\t// histogram, knock out zeros\n\t\thist = hist_find i;\n\t\tblack = image_new 1 1 (get_bands hist) \n\t\t\t(get_format hist) (get_coding hist) (get_type hist) 0 0 0;\n\t\thistze = insert 0 0 black hist;\n\n\t\t// matching identity\n\t\tiden\n\t\t\t= im_identity_ushort (get_bands hist) (get_width hist),\n\t\t\t\t(get_width hist) > 256\n\t\t\t= im_identity (get_bands hist);\n\n\t\t// number of non-zero pixels\n\t\tN = mean histze * 256;\n\n\t\t// sum of pixels\n\t\tsum = mean (hist * iden) * 256;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_cache x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (\\row [row?x']) obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\")\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x \n\t\t\t= to_image_size target_width target_height \n\t\t\t\ttarget_bands target_format x;\n\n\t\t[then_image, else_image] = map to_image [then_part, else_part];\n\t\t[c, t, e] = size_alike [cond, then_image, else_image];\n\n\t\tblend_result_image = image_set_type target_type (im_blend c t e);\n\t}\n}\n\ninsert x y small big\n\t= oo_binary_function insert_op small big, is_class small\n\t= oo_binary'_function insert_op small big, is_class big\n\t= im_insert big' small' (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n\t[small', big'] = (formats_alike @ bands_alike) [small, big];\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big' small' (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n\t[small', big'] = (formats_alike @ bands_alike) [small, big];\n}\n\nmeasure x y w h u v image\n\t= oo_unary_function measure_op image, is_class image\n\t= im_measure image \n\t\t(to_real x) (to_real y) (to_real w) (to_real h)\n\t\t(to_real u) (to_real v), \n\t\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"measure\")\n{\n\tmeasure_op = Operator \"measure\" \n\t\t(measure x y w h u v) Operator_type.COMPOUND_REWRAP false;\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ninvert x\n\t= oo_unary_function invert_op x, is_class x\n\t= im_invert x, is_image x\n\t= 255 - x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"invert\")\n{\n\tinvert_op = Operator \"invert\" invert Operator_type.COMPOUND false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate interp angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_affinei_all image interp.value a (-b) b a 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\t(rotate interp) Operator_type.COMPOUND_REWRAP false;\n\ta = cos angle;\n\tb = sin angle;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_lr\")\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin_lr Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert (get_width a) 0 b a;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_tb\")\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin_tb Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert 0 (get_height a) b a;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\t// The [[real]] can contain 128 values ... squeeze them out!\n\timage = im_mask2vips (Matrix m2) == 255;\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\" ++ \": \" ++ \n\t\t\"conv (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvf mask image\n\t= oo_unary_function convf_op image, is_class image\n\t= im_conv_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convf\" ++ \": \" ++ \n\t\t\"convf (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconvf_op = Operator \"convf\" \n\t\t(convf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsep_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\ngreyc iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx x\n\t= oo_unary_function greyc_op x, is_class x\n\t= greyc_im x, is_image x\n\t= error (_ \"bad argument\" ++ \" (\" ++ print x ++ \") to \" ++ \"greyc\")\n{\n\tgreyc_op = Operator \"greyc\" (greyc\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im x = im_greyc x\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\ngreyc_mask iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx mask x\n\t= oo_binary_function greyc_mask_op mask x, is_class mask\n\t= oo_binary'_function greyc_mask_op mask x, is_class x\n\t= greyc_im mask x, is_image mask && is_image x\n\t= error (_ \"bad arguments\" ++ \n\t\t\" (\" ++ print mask ++ \", \" ++ print x ++ \") \" ++\n\t\t\"to \" ++ \"greyc\")\n{\n\tgreyc_mask_op = Operator \"greyc_mask\" (greyc_mask\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im mask x = im_greyc_mask x mask\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_indexed index value\n\t= oo_binary_function hist_find_indexed_op index value, is_class index\n\t= oo_binary'_function hist_find_indexed_op index value, is_class value\n\t= im_hist_indexed index value, is_image index && is_image value\n\t= error (_ \"bad arguments to \" ++ \"hist_find_indexed\")\n{\n\thist_find_indexed_op = Operator \"hist_find_indexed\" \n\t\t(compose (compose Plot_histogram) hist_find_indexed) \n\t\t\tOperator_type.COMPOUND false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h \n\t\t= (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h\n\t{\n\t\t// up the format so it can represent the whole range of\n\t\t// possible values from this mask\n\t\tfmt x\n\t\t\t= Image_format.SHORT, \n\t\t\t\tx == Image_format.UCHAR || x == Image_format.CHAR\n\t\t\t= Image_format.INT, \n\t\t\t\tx == Image_format.USHORT || x == Image_format.SHORT ||\n\t\t\t\tx == Image_format.UINT \n\t\t\t= x;\n\t}\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= lhisteq image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n\n\t// loop over bands, if necessary\n\tlhisteq im\n\t\t= im_lhisteq im (to_real w) (to_real h), get_bands im == 1\n\t\t= (foldl1 join @ map lhisteq @ bandsplit) im;\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nresize interp xfac yfac image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\t// is this interpolation nearest-neighbour?\n\tis_nn x = x.type == Interpolate_type.NEAREST_NEIGHBOUR;\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// upscale by any factor, nearest neighbour \n\t\t// upscale by integer part, then affine to exact size\n\t\t= scale xg?1 yg?1 (im_zoom im xg?0 yg?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// downscale by any factor, nearest neighbour \n\t\t// downscale by integer part, then affine to exact size\n\t\t= scale xs?1 ys?1 (im_subsample im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// upscale by any factor with affine\n\t\t= scale xfac' yfac' im,\n\t\t\txfac' >= 1 && yfac' >= 1 \n\n\t\t// downscale by any factor, bilinear\n\t\t// block shrink by integer factor, then resample to \n\t\t// exact with affine\n\t\t= scale xs?1 ys?1 (im_shrink im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 \n\n\t\t= error (\"resize: unimplemented argument combination:\\n\" ++ \n\t\t\t\"  xfac = \" ++ print xfac' ++ \"\\n\" ++\n\t\t\t\"  yfac = \" ++ print yfac' ++ \"\\n\" ++\n\t\t\t\"  interp = \" ++ print interp ++ \" (\" ++\n\t\t\t\tInterpolate_type.descriptions?interp.type ++ \")\")\n\t{\n\t\t// convert a float scale to integer plus fraction\n\t\t// eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25)\n\t\tbreak f = [floor f, f / floor f];\n\n\t\t// same, but for downsizing ... turn a float scale which is less than\n\t\t// 1 into an int shrink and a float scale\n\n\t\t// complicated: the int shrink may round the size down (eg. imagine\n\t\t// subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide\n\t\t// image, not a 3.666 pixel wide image), so pass in the size of image\n\t\t// we are operating on and adjust for any rounding\n\t\t\n\t\t// so ... x is (eg.) 467, f is (eg. 128/467, about 0.274)\n\t\trbreak x f \n\t\t\t= [int_shrink, float_resample]\n\t\t{\n\t\t\t// the size of image we are aiming for after the combined int and\n\t\t\t// float resample\n\t\t\tx' = x * f;\n\n\t\t\t// int part\n\t\t\tint_shrink = floor (1 / f);\n\n\t\t\t// size after int shrink\n\t\t\tx'' = floor (x / int_shrink);\n\n\t\t\t// therefore what we need for the float part\n\t\t\tfloat_resample = x' / x'';\n\t\t}\n\n\t\twidth = get_width im;\n\t\theight = get_height im;\n\n\t\t// grow and shrink factors\n\t\txg = break xfac';\n\t\tyg = break yfac';\n\t\txs = rbreak width xfac';\n\t\tys = rbreak height yfac';\n\n\t\t// resize\n\t\tscale xfac yfac im\n\t\t\t= im_affinei_all im interp.value xfac 0 0 yfac 0 0;\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nflood_blob x y v image\n\t= oo_unary_function flood_blob_op image, is_class image\n\t= im_flood_blob_copy image (to_real x) (to_real y) v, is_image image\n\t= error (_ \"bad arguments to \" ++ \"flood_blob\")\n{\n\tflood_blob_op = Operator \"flood_blob\" \n\t\t(flood_blob x y v) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (\\x x % base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (\\x idivide x base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= NULL, any (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n/* Linear regression. Return a class with the stuff we need in.\n * from s15.2, p 665 NR in C\n */\nlinreg xes yes\n    = obj\n{\n    obj = class {\n        // in case we ever get shown in the workspace\n        _vislevel = 2;\n\n        slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2;\n        intercept = (sy - sx * slope) / ss;\n\n        chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes];\n\n        siga = (chi2 / (ss - 2)) ** 0.5 *\n            ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5;\n        sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5;\n\n        // for compat with linregw, see below\n        q = 1.0;\n    }\n\n    ss = len xes;\n    sx = sum xes;\n    sy = sum yes;\n    sxoss = sx / ss;\n\n    tes = [x - sxoss :: x <- xes];\n    st2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Weighted linear regression. Xes, yes and a list of deviations.\n */\nlinregw xes yes devs \n\t= obj\n{\n\tobj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: \n\t\t\t[x, y, sd] <- zip3 xes yes devs];\n\n\t\tsiga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (1 / st2) ** 0.5;\n\n\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\t}\n\n\twt = [sd ** -0.5 :: sd <- devs];\n\n\tss = sum wt;\n\tsx = sum [x * w :: [x, w] <- zip2 xes wt];\n\tsy = sum [y * w :: [y, w] <- zip2 yes wt];\n\tsxoss = sx / ss;\n\n\ttes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Clustering: pass in a list of points, repeatedly merge the\n * closest two points until no two points are closer than the threshold.\n * Return [merged-points, corresponding-weights]. A weight is a list of the\n * indexes we merged to make that point, ie. len weight == how significant\n * this point is.\n *\n * eg. \n *\tcluster 12 [152,154,155,42,159] == \n *\t\t[[155,42],[[1,2,0,4],[3]]]\n */\ncluster thresh points\n\t= oo_unary_function cluster_op points, is_class points\n\t// can't use [0..len points - 1], in case len points == 0\n\t= merge [points, map (converse cons []) (take (len points) [0 ..])],\n\t\tis_list points\n\t= error (_ \"bad arguments to \" ++ \"cluster\")\n{\n\tcluster_op = Operator \"cluster\" \n\t\t(cluster thresh) Operator_type.COMPOUND false;\n\n\tmerge x\n\t\t= x, m < 2 || d > thresh\n\t\t= merge [points', weights']\n\t{\n\t\t[points, weights] = x;\n\t\tm = len points;\n\n\t\t// generate indexes of all possible pairs, avoiding comparing a thing \n\t\t// to itself, and assuming that dist is reflexive\n\t\t// first index is always less than 2nd index\n\t\t// the +1,+2 makes sure we have an increasing generator, otherwise we\n\t\t// can get [3 .. 4] (for example), which will make a decreasing\n\t\t// sequence\n\t\tpairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]];\n\n\t\t// distance function\n\t\t// arg is eg. [3,1], meaning get distance from point 3 to point 1\n\t\tdist x \n\t\t\t= abs (points?i - points?j)\n\t\t{\n\t\t\t[i, j] = x;\n\t\t}\n\n\t\t// smallest distance, then the two points we merge\n\t\tp = minpos (map dist pairs);\n\t\td = dist pairs?p;\n\t\t[i, j] = pairs?p;\n\n\t\t// new point and new weight\n\t\tnw = weights?i ++ weights?j;\n\t\tnp = (points?i * len weights?i + points?j * len weights?j) / len nw;\n\n\t\t// remove element i from a list\n\t\tremove i l = take i l ++ drop (i + 1) l;\n\n\t\t// remove two old points, add the new merged one\n\t\t// i < j (see \"pairs\", above)\n\t\tpoints' = np : remove i (remove j points);\n\t\tweights' = nw : remove i (remove j weights);\n\t}\n}\n\n/* Extract the area of an image around an arrow.\n * Transform the image to make the arrow horizontal, then displace by hd and\n * vd pxels, then cut out a bit h pixels high centered on the arrow.\n */\nextract_arrow hd vd h arrow\n\t= extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im'\n{\n\t// the line as a polar vector\n\tpv = polar (arrow.width, arrow.height);\n\ta = im pv;\n\n\t// smallest rotation that will make the line horizontal\n\ta'\n\t\t= 360 - a, a > 270\n\t\t= 180 - a, a > 90\n\t\t= -a;\n\n\tim' = rotate Interpolate_bilinear a' arrow.image;\n\n\t// look at the start and end of the arrow, pick the leftmost\n\tp\n\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t= (arrow.right, arrow.bottom);\n\n\t// transform that point to im' space\n\tp' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset);\n}\n\n/* You'd think these would go in _convert, but they are not really colour ops,\n * so put them here.\n */\nrad2float image\n\t= oo_unary_function rad2float_op image, is_class image\n\t= im_rad2float image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"rad2float\")\n{\n\trad2float_op = Operator \"rad2float\" \n\t\trad2float Operator_type.COMPOUND_REWRAP false;\n}\n\nfloat2rad image\n\t= oo_unary_function float2rad_op image, is_class image\n\t= im_float2rad image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"float2rad\")\n{\n\tfloat2rad_op = Operator \"float2rad\" \n\t\tfloat2rad Operator_type.COMPOUND_REWRAP false;\n}\n\nsegment x\n\t= oo_unary_function segment_op x, is_class x\n\t= image', is_image x \n\t= error (_ \"bad arguments to \" ++ \"segment\")\n{\n\tsegment_op = Operator \"segment\" \n\t\tsegment Operator_type.COMPOUND_REWRAP false;\n\n\t[image, nsegs] = im_segment x;\n\timage' = im_copy_set_meta image \"n-segments\" nsegs;\n}\n\npoint a b\n\t= oo_binary_function point_op a b, is_class a\n\t= oo_binary'_function point_op a b, is_class b\n\t= im_read_point b x y, is_image b\n\t= [b?x?y], is_matrix b\n\t= [b?x], is_real_list b && y == 0\n\t= [b?y], is_real_list b && x == 0\n\t= error (_ \"bad arguments to \" ++ \"point\")\n{\n\tpoint_op = Operator \"point\" \n\t\t(\\a\\b Vector (point a b)) Operator_type.COMPOUND false;\n\n\t(x, y) \n\t\t= a, is_complex a;\n\t\t= (a?0, a?1), is_real_list a && is_list_len 2 a\n\t\t= error \"bad position format\";\n}\n"
  },
  {
    "path": "share/nip2/compat/7.24/_types.def",
    "content": "/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary (\\a op.fn a x) this,\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// we can't call map_trinary directly, since it uses Group and we\n\t// don't support mutually recursive top-level functions :-(\n\t// copy-paste it here, keep in sync with the version in _stdenv\n\tmap_nary fn args\n\t\t= fn args, groups == []\n\t\t= Group (map process [0, 1 .. shortest - 1])\n\t{\n\t\tgroups = filter is_Group args;\n\t\n\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\tprocess n\n\t\t\t= NULL, any (map (is_noval n) args)\n\t\t\t= map_nary fn (map (extract n) args)\n\t\t{\n\t\t\textract n arg\n\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t= arg;\n\t\n\t\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t\t}\n\t}\n\n\t// need ite as a true trinary\n\tite a b c = if a then b else c;\n\n\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t];\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\n\t\t[op.fn this.value x,\n\t\t\top.type == Operator_type.COMPOUND]\n\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[is_list_len 3 value, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.value_name colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum Image_type.colour_spaces \"Colour space\" default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\nOption_enum enum caption value_name = class\n\tOption caption enum.names (index (equal value_name) enum.names) {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing value_name;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum enum caption (enum.names ? value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNONE = 0;\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNONE = 0;\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n\tRAD = 6;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* Extract a column.\n\t */\n\tcolumn n = map (extract n) value;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (column col) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (column from);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = this.column 0; \n\tthings = this.column 1; \n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tLUMINANCE = 2;\n\tXRAY = 3;\n\tIR = 4;\n\tYUV = 5;\n\tRED_ONLY = 6;\n\tGREEN_ONLY = 7;\n\tBLUE_ONLY = 8;\n\tPOWER_SPECTRUM = 9;\n\tHISTOGRAM = 10;\n\tLUT = 11;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMC = 14;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t$MULTIBAND => MULTIBAND,\n\t\t$B_W => B_W,\n\t\t$LUMINANCE => LUMINANCE,\n\t\t$XRAY => XRAY,\n\t\t$IR => IR,\n\t\t$YUV => YUV,\n\t\t$RED_ONLY => RED_ONLY,\n\t\t$GREEN_ONLY => GREEN_ONLY,\n\t\t$BLUE_ONLY => BLUE_ONLY,\n\t\t$POWER_SPECTRUM => POWER_SPECTRUM,\n\t\t$HISTOGRAM => HISTOGRAM,\n\t\t$LUT => LUT,\n\t\t$XYZ => XYZ,\n\t\t$LAB => LAB,\n\t\t$CMC => CMC,\n\t\t$CMYK => CMYK,\n\t\t$LABQ => LABQ,\n\t\t$RGB => RGB,\n\t\t$UCS => UCS,\n\t\t$LCH => LCH,\n\t\t$LABS => LABS,\n\t\t$sRGB => sRGB,\n\t\t$YXY => YXY,\n\t\t$FOURIER => FOURIER,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options generated from this, so match the order to the order in the\n\t * Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t$sRGB => sRGB,\n\t\t$Lab => LAB,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t$Mono => B_W,\n\t\t$sRGB => sRGB,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$Lab => LAB,\n\t\t$LabQ => LABQ,\n\t\t$LabS => LABS,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// image ++ image is slightly different ... we want to\n\t\t// sizealike, but we must not bandalike\n\t\t[wrap \n\t\t\t(op.fn (get_image resized?0) (get_image resized?1)),\n\t\t\thas_image x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t// arithmetic and reational binops between image resize\n\t\t// and band_alike images to match\n\t\t[wrap \n\t\t\t(op.fn (get_image rebanded?0) (get_image rebanded?1)),\n\t\t\thas_image x &&\n\t\t\t(op.type == Operator_type.ARITHMETIC ||\n\t\t\t\top.type == Operator_type.RELATIONAL)],\n\t\t// other op types don't resize\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \n\t\t// \"Image v == 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\t// if one of then/else is an image, get the target format from that\n\t\t// otherwise, let the non-image objects set the target\n\t\ttarget_format \n\t\t\t= get_member_list has_format get_format x, \n\t\t\t\thas_member_list has_format x\n\t\t\t= NULL;\n\n\t\tto_image x = to_image_size width height target_bands target_format x;\n\n\t\t[if_size, then_size, else_size] = \n\t\t\tsize_alike (value : formats_alike (map to_image x));\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if if_size then then_size else else_size);\n\n\t\tresized = size_alike [this, x];\n\t\trebanded = bands_alike resized;\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nInterpolate_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n        LBB = 3;\n\tNOHALO = 4;\n\tVSQBS = 5;\n\n\t// Should introspect to get the list of interpolators :-(\n        // We can \"dir\" on VipsInterpolate to get a list of them, but we\n        // can't get i18n'd descriptions until we have more\n        // introspection stuff in nip2.\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Bilinear\",\n                _ \"Bicubic\",\n\t\t_ \"Upsize: reduced halo bicubic (LBB)\",\n\t\t_ \"Upsharp: reduced halo bicubic with edge sharpening (Nohalo)\",\n\t\t_ \"Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)\"\n\t];\n\n\t/* And to vips type names.\n\t */\n\ttypes = [\n\t\t\"VipsInterpolateNearest\",\n\t\t\"VipsInterpolateBilinear\",\n\t\t\"VipsInterpolateBicubic\",\n\t\t\"VipsInterpolateLbb\",\n\t\t\"VipsInterpolateNohalo\",\n\t\t\"VipsInterpolateVsqbs\"\n\t];\n}\n\nInterpolate type options = class {\n\tvalue = vips_object_new Interpolate_type.types?type [] options;\n}\n\nInterpolate_bilinear = Interpolate Interpolate_type.BILINEAR [];\n\nInterpolate_picker default = class \n\tInterpolate interp.value [] {\n\t_vislevel = 2;\n\n\tinterp = Option \"Interpolation\" Interpolate_type.descriptions default;\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t[_ \"Perceptual\", PERCEPTUAL],\n\t\t[_ \"Relative\", RELATIVE],\n\t\t[_ \"Saturation\", SATURATION],\n\t\t[_ \"Absolute\", ABSOLUTE]\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t[_ \"Point\", POINT],\n\t\t[_ \"Line\", LINE],\n\t\t[_ \"Spline\", SPLINE],\n\t\t[_ \"Bar\", BAR]\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t[_ \"YYYY\", YYYY],\n\t\t[_ \"XYYY\", XYXY],\n\t\t[_ \"XYXY\", XYXY]\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [$format => Plot_format.XYYY] value {\n}\n\n/* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate\n * empty slots, for example.\n */\nNULL = class \n\t_Object {\n\too_binary_table op x = [\n\t\t// the only operation we allow is equality .. use pointer equality,\n\t\t// this lets us test a == NULL and a != NULL\n\t\t[this === x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"equal\"],\n\t\t[this !== x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"not_equal\"]\n\t] ++ super.oo_binary_table op x;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.26/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t[_L, _a, _b] = default_value;\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Convert to\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Tag as\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Colour Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum (_ \"Old whitepoint\") Whitepoints \"D65\";\n\t\t\tnew_white = Option_enum (_ \"New whitepoint\") Whitepoints \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= monitor_profile, has_bands image && get_bands image == 3\n\t\t= print_profile;\n\trender_intents = Option_enum (_ \"Render intent\") Render_intent.names\n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_rad_item = class\n\tMenupullright (_ \"_Radiance\") (_ \"convert to and from Radiance packed format\") {\n\tUnpack_item = class\n\t\tMenuaction (_ \"Unpack\") \n\t\t\t(_ \"unpack Radiance format to float\") {\n\t\taction x = map_unary rad2float x;\n\t}\n\n\tPack_item = class\n\t\tMenuaction (_ \"Pack\") \n\t\t\t(_ \"pack 3-band float to Radiance format\") {\n\t\taction x = map_unary float2rad x;\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure 0 0 in.width in.height \n\t\t\t\t\t(to_real pacross) (to_real pdown) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.26/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 1.5;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 50;\n\t\t\tfs = Scale \"Sharpen flat areas by\" (-2) 5 1;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" (-2) 5 2;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tlayers = Scale \"Layers\" 1 100 10;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\", \"Approximate\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf, aconvsep layers]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\t\t\trotate = Option \"Rotate\" [\n\t\t\t\t\"Don't rotate\", \n\t\t\t\t\"4 x 45 degrees\", \n\t\t\t\t\"8 x 45 degrees\", \n\t\t\t\t\"2 x 90 degrees\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_lindetect, !separable && type == 0 && rotate == 1\n\t\t\t\t\t\t= im_compass, !separable && type == 0 && rotate == 2\n\t\t\t\t\t\t= im_gradient, !separable && type == 0 && rotate == 3\n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_conv_f, !separable && type == 1\n\t\t\t\t\t\t= im_convsep_f, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 4) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tSegment_item = class\n\t\tMenuaction \"_Segment\" \"break image into disjoint regions\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsegments\n\t\t\t\t= Expression \"Number of disjoint regions\" \n\t\t\t\t\t(map_unary (get_header \"n-segments\") _result);\n\n\t\t\t_result = map_unary segment x;\n\t\t}\n\t}\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width.expr window_height.expr in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\nFilter_greyc_item = class \n\tMenupullright \"_GREYCstoration\" \"noise-removing filter\" {\n\tDenoise_item = class \n\t\tMenuaction \"Denoise\" \"Noise-removing filter\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\titerations = Scale \"Iterations\" 1 5 1;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 40;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.9;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.15;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.6;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.1;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) x;\n\t\t}\n\t}\n\n\tEnlarge_item = class\n\t\tMenuaction \"Enlarge\" \"Enlarge image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Enlarge\" 1 10 3;\n\t\t\titerations = Scale \"Iterations\" 1 5 3;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 20;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.2;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.9;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.1;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.5;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) \n\t\t\t\t\t(resize Interpolate_bilinear\n\t\t\t\t\t\t(to_real scale) (to_real scale) x);\n\t\t}\n\t}\n}\n\nFilter_magick_item = class\n\tMenupullright \"Magic_k\" \"various Image/Graphics Magick filters\" {\n\tsystem command x = map_unary (system_image command) x;\n\tradius_widget = Scale \"Radius\" 1 100 10;\n\tsigma_widget = Scale \"Sigma\" 0.1 10 1;\n\tangle_widget = Scale \"Angle\" (-360) 360 0;\n\ttext_widget = String \"Text to draw\" \"AaBbCcDdEe\";\n\n\tprint_colour triple\n\t\t= concat [\"\\\"#\", concat (map fmt triple), \"\\\"\"]\n\t{\n\t\tfmt x = reverse (take 2 (reverse (print_base 16 (x + 256))));\n\t}\n\n\tForeground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-fill \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Foreground triple;\n\t}\n\tforeground_widget = Foreground [0, 0, 0];\n\n\tBackground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-background \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Background triple;\n\t}\n\tbackground_widget = Background [255, 255, 255];\n\n\tAntialias value = class\n\t\tToggle \"Antialias\" value {\n\n\t\t_flag\n\t\t\t= \"-antialias\", value\n\t\t\t= \"+antialias\";\n\n\t\tToggle_edit caption value = this.Antialias value;\n\t}\n\tantialias_widget = Antialias true;\n\n\tGravity gravity = class\n\t\tOption_string \"Gravity\" [\n\t\t\t\"None\",\n\t\t\t\"Center\",\n\t\t\t\"East\",\n\t\t\t\"Forget\",\n\t\t\t\"NorthEast\",\n\t\t\t\"North\",\n\t\t\t\"NorthWest\",\n\t\t\t\"SouthEast\",\n\t\t\t\"South\",\n\t\t\t\"SouthWest\",\n\t\t\t\"West\",\n\t\t\t\"Static\"\n\t\t] gravity {\n\n\t\t_flag = \"-gravity \" ++ gravity;\n\n\t\tOption_edit caption labels value = this.Gravity labels?value;\n\t}\n\tgravity_widget = Gravity \"Center\";\n\n\tAlpha alpha = class\n\t\tOption_string \"Alpha\" [\n\t\t\t\"On\", \n\t\t\t\"Off\", \n\t\t\t\"Set\", \n\t\t\t\"Opaque\", \n\t\t\t\"Transparent\", \n\t\t\t\"Extract\", \n\t\t\t\"Copy\", \n\t\t\t\"Shape\", \n\t\t\t\"Background\"\n\t\t] alpha {\n\n\t\t_flag = \"-alpha \" ++ alpha;\n\n\t\tOption_edit caption labels value = this.Alpha labels?value;\n\t}\n\talpha_widget = Alpha \"On\";\n\n\tGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Y\" 0;\n\t\ty = Expression \"X\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 10;\n\t\tvoffset = Expression \"Vertical offset\" 10;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFont_widget = class {\n\t\t_vislevel = 3;\n\n\t\tfamily = Option_string \"Family\" [\n\t\t\t\"Arial\",\n\t\t\t\"ArialBlack\",\n\t\t\t\"AvantGarde\",\n\t\t\t\"BitstreamCharter\",\n\t\t\t\"Bookman\",\n\t\t\t\"CenturySchoolbook\",\n\t\t\t\"ComicSansMS\",\n\t\t\t\"Courier\",\n\t\t\t\"CourierNew\",\n\t\t\t\"DejaVuSans\",\n\t\t\t\"DejaVuSansMono\",\n\t\t\t\"DejaVuSerif\",\n\t\t\t\"Dingbats\",\n\t\t\t\"FreeMono\",\n\t\t\t\"FreeSans\",\n\t\t\t\"FreeSerif\",\n\t\t\t\"Garuda\",\n\t\t\t\"Georgia\",\n\t\t\t\"Helvetica\",\n\t\t\t\"HelveticaNarrow\",\n\t\t\t\"Impact\",\n\t\t\t\"LiberationMono\",\n\t\t\t\"LiberationSans\",\n\t\t\t\"LiberationSerif\",\n\t\t\t\"NewCenturySchlbk\",\n\t\t\t\"Palatino\",\n\t\t\t\"Purisa\",\n\t\t\t\"Symbol\",\n\t\t\t\"Times\",\n\t\t\t\"TimesNewRoman\",\n\t\t\t\"Ubuntu\",\n\t\t\t\"Verdana\",\n\t\t\t\"Webdings\"\n\t\t] \"Arial\";\n\t\tstyle = Option_string \"Style\" [\n\t\t\t\"Any\", \"Italic\", \"Normal\", \"Oblique\"\n\t\t] \"Normal\";\n\t\tweight = Scale \"Weight\" 1 800 400;\n\t\tsize = Scale \"Point size\" 1 100 12;\n\t\tstretch = Option_string \"Stretch\" [\n\t\t\t\"Any\", \"Condensed\", \"Expanded\", \"ExtraCondensed\", \"ExtraExpanded\", \n\t\t\t\"Normal\", \"SemiCondensed\", \"SemiExpanded\", \"UltraCondensed\", \n\t\t\t\"UltraExpanded\"\n\t\t] \"Normal\";\n\n\t\t_flag = join_sep \" \" [\n\t\t\t\t\"-family\", family.item,\n\t\t\t\t\"-weight\", print weight.value,\n\t\t\t\t\"-pointsize\", print size.value,\n\t\t\t\t\"-style\", style.item,\n\t\t\t\t\"-stretch\", stretch.item];\n\t}\n\n\tAdaptive_blur_item = class\n\t\tMenuaction \"_Adaptive Blur\" \"blur less near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = radius_widget; \n\t\t\tsigma = sigma_widget;\n\t\t\tcommand = magick_command (concat [\"-adaptive-blur \",\n\t\t\t\tprint radius.value, \"x\", print sigma.value]);\n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n\n\tAdaptive_sharpen_item = class\n\t\tMenuaction \"_Adaptive Sharpen\" \"sharpen more near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = radius_widget; \n\t\t\tsigma = sigma_widget;\n\t\t\tcommand = magick_command (concat [\"-adaptive-sharpen \",\n\t\t\t\tprint radius.value, \"x\", print sigma.value]);\n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n\n\tAlpha_item = class\n\t\tMenuaction \"_Alpha\" \"add/remove alpha channel\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\talpha = alpha_widget; \n\t\t\tcommand = magick_command alpha._flag; \n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n\n\tAnnotate_item = class\n\t\tMenuaction \"_Annotate\" \"add text annotation\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = text_widget;\n\t\t\tfont = Font_widget;\n\t\t\tgeometry = Geometry_widget; \n\t\t\tgravity = gravity_widget; \n\t\t\tforeground = foreground_widget;\n\t\t\tantialias = antialias_widget;\n\t\t\tcommand = magick_command (join_sep \" \" [\n\t\t\t\tfont._flag,\n\t\t\t\tantialias._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tforeground._flag,\n\t\t\t\t\"-annotate\", geometry._flag, \"\\\"\" ++ text.value ++ \"\\\"\"]);\n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n\n\tSwirl_item = class\n\t\tMenuaction \"_Swirl\" \"swirl around the centre\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tangle = angle_widget;\n\t\t\tcommand = magick_command (\"-swirl \" ++ print angle.value);\n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image\" \"use an image to blend two objects\" {\n\t\taction a b c = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ti = Toggle \"Invert mask\" false;\n\n\t\t\t_result \n\t\t\t\t= map_trinary process a b c\n\t\t\t{\n\t\t\t\tprocess a b c \n\t\t\t\t\t= blend condition in1 in2, !i\n\t\t\t\t\t= blend (invert condition) in1 in2\n\t\t\t\t{\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t\t= false,\n\t\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t\t= true;\n\t\t\t\t\t[condition, in1, in2] = sortc compare [a, b, c];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"_Alpha\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t_ \"Normal\" => NORMAL,\n\t\t\t_ \"If Lighter\" => IFLIGHTER,\n\t\t\t_ \"If Darker\" => IFDARKER,\n\t\t\t_ \"Multiply\" => MULTIPLY,\n\t\t\t_ \"Add\" => ADD,\n\t\t\t_ \"Subtract\" => SUBTRACT,\n\t\t\t_ \"Screen\" => SCREEN,\n\t\t\t_ \"Burn\" => BURN,\n\t\t\t_ \"Soft Light\" => SOFTLIGHT,\n\t\t\t_ \"Hard Light\" => HARDLIGHT,\n\t\t\t_ \"Lighten\" => LIGHTEN,\n\t\t\t_ \"Darken\" => DARKEN,\n\t\t\t_ \"Dodge\" => DODGE,\n\t\t\t_ \"Reflect\" => REFLECT,\n\t\t\t_ \"Freeze\" => FREEZE,\n\t\t\t_ \"Bitwise OR\" => OR,\n\t\t\t_ \"Bitwise AND\" => AND\n\t\t];\n\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum \"Blend mode\" names \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\t[mono, colour] = \n\t\t\t\t\tsortc (const (is_colour_type @ get_type)) [a, b];\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t_ \"Grey\",\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t_ \"North-west\",\n\t\t\t\t_ \"North\",\n\t\t\t\t_ \"North-east\",\n\t\t\t\t_ \"West\",\n\t\t\t\t_ \"Centre\",\n\t\t\t\t_ \"East\",\n\t\t\t\t_ \"South-west\",\n\t\t\t\t_ \"South\",\n\t\t\t\t_ \"South-east\",\n\t\t\t\t_ \"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.26/Histogram.def",
    "content": "Hist_new_item = class\n\tMenupullright \"_New\" \"new histogram\" {\n\tHist_item = class\n\t\tMenuaction \"Histogram\" \"make an identity histogram\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\t_result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d);\n\t\t}\n\t}\n\n\tHist_new_from_matrix = Matrix_buildlut_item; \n\n\tHist_from_image_item = class\n\t\tMenuaction \"Ta_g Image As Histogram\" \"set image Type to Histogram\" {\n\t\taction x = hist_tag x;\n\t}\n\n\tTone_item = class \n\t\tMenuaction \"_Tone Curve\" \"make a new tone mapping curve\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\t_result \n\t\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t\t{\n\t\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_convert_to_hist_item = class \n\tMenuaction \"Con_vert to Histogram\" \"convert anything to a histogram\" {\n\taction x = hist_tag (to_image x);\n}\n\nHist_find_item = class \n\tMenupullright \"_Find\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n\n\tIndexed_item = class\n\t\tMenuaction \"_Indexed\" \n\t\t\t\"use a 1-band index image to pick bins for an n-band image\" {\n\t\taction x y \n\t\t\t= map_binary map x y\n\t\t{\n\t\t\tmap a b\n\t\t\t\t= hist_find_indexed index im\n\t\t\t{\n\t\t\t\t[im, index] = sortc (const is_index) [a, b];\n\n\t\t\t\tis_index x\n\t\t\t\t\t= has_image x && b == 1 && \n\t\t\t\t\t\t(f == Image_format.UCHAR || f == Image_format.USHORT)\n\t\t\t\t{\n\t\t\t\t\tim = get_image x;\n\t\t\t\t\tb = get_bands x;\n\t\t\t\t\tf = get_format x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\t[im, hist] = sortc (const is_hist) [a, b];\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Integrate\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate\" \n\t\t\"find point-to-point differences (inverse of Integrate)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\tarea = extract_arrow \n\t\t\t\t\tdisplace.value vdisplace.value width.value arrow;\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize Interpolate_bilinear 1 (1 / width.value) area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary (extract_arrow \n\t\t\t\tdisplace.value vdisplace.value width.value) x;\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tformat = Option_enum \"Format\" Plot_format.names \"YYYY\";\n\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => style.value, $format => format.value] ++ range;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow 0 0 1 x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.26/Image.def",
    "content": "Image_new_item = class \n\tMenupullright \"_New\" \"make new things\" {\n\tImage_black_item = class \n\t\tMenuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \"Image type\"\n\t\t\t\tImage_type.type_names \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region on image using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\t[target, x] = sortc compare [a, b];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\nImage_number_format_item = class\n\tMenupullright \"_Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_header_item = class \n\tMenupullright \"_Header\" \"do stuff to the image header\" {\n\n\tImage_get_item = class\n\t\tMenupullright \"_Get\" \"get header fields\" {\n\n\t\t// the header fields we can get\n\t\tfields = class {\n\t\t\ttype = 0;\n\t\t\twidth = 1;\n\t\t\theight = 2;\n\t\t\tformat = 3;\n\t\t\tbands = 4;\n\t\t\txres = 5;\n\t\t\tyres = 6;\n\t\t\txoffset = 7;\n\t\t\tyoffset = 8;\n\t\t\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t$width => width,\n\t\t\t\t$height => height,\n\t\t\t\t$bands => bands,\n\t\t\t\t$format => format,\n\t\t\t\t$type => type,\n\t\t\t\t$xres => xres,\n\t\t\t\t$yres => yres,\n\t\t\t\t$xoffset => xoffset,\n\t\t\t\t$yoffset => yoffset,\n\t\t\t\t$coding => coding\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum (_ \"Field\") field_names name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tCustom_item = class\n\t\t\tMenuaction \"C_ustom\" \"get any header field\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tfield = String \"Field\" \"Xsize\";\n\t\t\t\tparse = Option \"Parse\" [\n\t\t\t\t\t\"No parsing\",\n\t\t\t\t\t\"Parse string as integer\",\n\t\t\t\t\t\"Parse string as real\",\n\t\t\t\t\t\"Parse string as hh:mm:ss\"\n\t\t\t\t] 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary (wrap @ process @ get_header field.value) x\n\t\t\t\t{\n\t\t\t\t\tparse_str parse str = parse (split is_space str)?0;\n\n\t\t\t\t\tparse_field name cast parse x\n\t\t\t\t\t\t= cast x, is_number x\n\t\t\t\t\t\t= parse_str parse x, is_string x\n\t\t\t\t\t\t= error (\"not \" ++ name);\n\n\t\t\t\t\tget_int = parse_field \"int\" \n\t\t\t\t\t\tcast_signed_int parse_int;\n\t\t\t\t\tget_float = parse_field \"float\" \n\t\t\t\t\t\tcast_float parse_float;\n\t\t\t\t\tget_time = parse_field \"hh:mm:ss\" \n\t\t\t\t\t\tcast_signed_int parse_time;\n\n\t\t\t\t\twrap x\n\t\t\t\t\t\t= Real x, is_real x\n\t\t\t\t\t\t= Vector x, is_real_list x\n\t\t\t\t\t\t= Image x, is_image x\n\t\t\t\t\t\t= Bool x, is_bool x\n\t\t\t\t\t\t= Matrix x, is_matrix x\n\t\t\t\t\t\t= String \"String\" x, is_string x\n\t\t\t\t\t\t= List x, is_list x\n\t\t\t\t\t\t= x;\n\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tget_int, \n\t\t\t\t\t\tget_float,\n\t\t\t\t\t\tget_time\n\t\t\t\t\t]?parse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum \"Image type\" Image_type.type_names \n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_cache_item = class\n\tMenuaction \"C_ache\" \"cache calculated image pixels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttile_width = Number \"Tile width\" 128;\n\t\ttile_height = Number \"Tile height\" 128;\n\t\tmax_tiles = Number \"Maximum number of tiles to cache\" (-1);\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= cache (to_real tile_width) (to_real tile_height) \n\t\t\t\t\t(to_real max_tiles) image;\n\t\t}\n\t}\n}\n\n#separator\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in = [\n\t\t\t\t\t\tin, \n\t\t\t\t\t\trot90 in,\n\t\t\t\t\t\trot180 in,\n\t\t\t\t\t\trot270 in\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate interp angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary straighten x\n\t\t\t\t{\n\t\t\t\t\tstraighten arrow\n\t\t\t\t\t\t= rotate interp angle'' arrow.image\n\t\t\t\t\t{\n\t\t\t\t\t\tx = arrow.width;\n\t\t\t\t\t\ty = arrow.height;\n\t\t\n\t\t\t\t\t\tangle = im (polar (x, y));\n\t\t\n\t\t\t\t\t\tangle'\n\t\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t\t= angle;\n\t\t\n\t\t\t\t\t\tangle''\n\t\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize interp xfactor yfactor image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\taspect = Toggle \"Break aspect ratio\" false;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize interp h v image, aspect\n\t\t\t\t\t\t= resize interp fac fac image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac > yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\tmin_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac < yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\t[h, v] = [\n\t\t\t\t\t\t\tmax_factor, \n\t\t\t\t\t\t\tmin_factor, \n\t\t\t\t\t\t\t[xfac, 1], \n\t\t\t\t\t\t\t[1, yfac]]?which;\n\n\t\t\t\t\t\tfac \n\t\t\t\t\t\t\t= h, v == 1\n\t\t\t\t\t\t\t= v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_within_item = class\n\t\t\tMenuaction \"Size _Within\" \"size to fit within a rectangle\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\t// the rects we size to fit within\n\t\t\t\t_rects = [\n\t\t\t\t\t[2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], \n\t\t\t\t\t[1280, 1024], [1024, 768], [800, 600], [640, 480] \n\t\t\t\t];\n\n\t\t\t\twithin = Option \"Fit within (pixels)\" (\n\t\t\t\t\t[print w ++ \" x \" ++ print h :: [w, h] <- _rects] ++\n\t\t\t\t\t[\"Custom\"]\n\t\t\t\t) 4;\n\t\t\t\tcustom_width = Expression \"Custom width\" 1000;\n\t\t\t\tcustom_height = Expression \"Custom height\" 1000;\n\t\t\t    size = Option \"Page size\" [\n\t\t\t\t\t\"Full page\", \"Half page\", \"Quarter page\" \n\t\t\t\t] 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t \t_result\n\t\t\t\t \t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\txdiv = [1, 2, 2]?size;\n\t\t\t\t\tydiv = [1, 1, 2]?size;\n\t\t\t\t\tallrect = _rects ++ [\n\t\t\t\t\t\t[custom_width.expr, custom_height.expr]\n\t\t\t\t\t];\n\t\t\t\t\t[width, height] = allrect?within;\n\n\t\t\t\t\tprocess x\n\t\t\t\t\t\t= resize interp fac fac x, fac < 1\n\t\t\t\t\t\t= x\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = (width / xdiv) / x.width;\n\t\t\t\t\t\tyfac = (height / ydiv) / x.height;\n\t\t\t\t\t\tfac = min_pair xfac yfac;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\" [\"Nearest\", \"Bilinear\"] 1;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_trn {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t[sample', trn, err] = transform_search \n\t\t\t\t\tmax_err max_iter order interp wrap\n\t\t\t\t\tsample reference;\n\t\t\t\ttransformed_image = Image sample';\n\t\t\t\t_trn = Transform trn reference.width reference.height;\n\t\t\t\tfinal_error = err;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\t[i, t] = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tBandwise_item = Image_join_item.Bandwise_item;\n\n    sep1 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldl1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find the image geometry ... don't bother trying to look\n\t\t// inside groups though\n\t\t_geo\n\t\t\t= x.rect, is_Image x\n\t\t\t= Rect 0 0 100 100;\n\n\t\tl = Expression \"Crop left\" ((int) (_geo.left + _geo.width / 4));\n\t\tt = Expression \"Crop top\" ((int) (_geo.top + _geo.height / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (_geo.width / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (_geo.height / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t[_a', _b'] = sortc _pred [a, b];\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_draw_item = class \n\tMenupullright \"_Draw\" \"draw lines, circles, rectangles, floods\" {\n\tLine_item = class Menuaction \"_Line\" \"draw line on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tx1 = Expression \"Start x\" 0;\n\t\t\ty1 = Expression \"Start y\" 0;\n\t\t\tx2 = Expression \"End x\" 100;\n\t\t\ty2 = Expression \"End y\" 100;\n\n\t\t\tink = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary line x\n\t\t\t{\n\t\t\t\tline im \n\t\t\t\t\t= draw_line x1.expr y1.expr x2.expr y2.expr ink.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tRect_item = class Menuaction \"_Rectangle\" \"draw rectangle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"Left\" 50;\n\t\t\ttop = Expression \"Top\" 50;\n\t\t\twidth = Expression \"Width\" 100;\n\t\t\theight = Expression \"Height\" 100;\n\n\t\t\tfill = Toggle \"Fill\" true;\n\n\t\t\tink = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary rect x\n\t\t\t{\n\t\t\t\trect im \n\t\t\t\t\t= draw_rect left.expr top.expr width.expr height.expr\n\t\t\t\t\t\t\tfill.value ink.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class Menuaction \"_Circle\" \"draw circle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcx = Expression \"Centre x\" 100;\n\t\t\tcy = Expression \"Centre y\" 100;\n\t\t\tr = Expression \"Radius\" 50;\n\n\t\t\tfill = Toggle \"Fill\" true;\n\n\t\t\tink = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary circle x\n\t\t\t{\n\t\t\t\tcircle im \n\t\t\t\t\t= draw_circle cx.expr cy.expr r.expr \n\t\t\t\t\t\tfill.value ink.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tFlood_item = class Menuaction \"_Flood\" \n\t\t\"flood bounded area of image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstartx = Expression \"Start x\" 100;\n\t\t\tstarty = Expression \"Start y\" 100;\n\n\t\t\tedge = Option \"Flood while\" [\n\t\t\t\t\"Not equal to ink\",\n\t\t\t\t\"Equal to start point\"\n\t\t\t] 0;\n\n\t\t\t// pick a default ink that won't flood, if we can\n\t\t\tink \n\t\t\t\t= Expression \"Ink\" default_ink\n\t\t\t{\n\t\t\t\tdefault_ink\n\t\t\t\t\t= [0], ! has_image x\n\t\t\t\t\t= pixel;\n\t\t\t\tpixel = map mean (bandsplit (extract_area left top 1 1 im));\n\t\t\t\tleft = startx.expr;\n\t\t\t\ttop = starty.expr;\n\t\t\t\tim = get_image x;\n\t\t\t}\n\n\t\t\t_result \n\t\t\t\t= map_unary flood x\n\t\t\t{\n\t\t\t\tflood im \n\t\t\t\t\t= draw_flood left top ink.expr im, edge == 0\n\t\t\t\t\t= draw_flood_blob left top ink.expr im\n\t\t\t\t{\n\t\t\t\t\tleft = startx.expr;\n\t\t\t\t\ttop = starty.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t// we can't use map_unary since chop-into-tiles returns a group of\n\t\t\t// groups and we want to be able to reassemble that\n\t\t\t// TODO: chop-into-tiles should return an array class which\n\t\t\t// displays as group but does not have the looping behaviour?\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n\n\tArrayFL_item = class\n\t\tMenuaction \"_Array from List\"\n\t\t\t\"join a list of images into a single image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tncol = Number \"Max. Number of Columns\" 1;\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t_l \n\t\t\t\t= split_lines ncol.value x.value, is_Group x\n\t\t\t\t= split_lines ncol.value x;\n\n\t\t\t_result\n\t\t\t\t= (image_set_origin 0 0 @\n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value\n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list _l));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tGaussian_item = class \n\t\tMenuaction \"Gaussian _Noise\" \"make an image of gaussian noise\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t_result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) \n\t\t\t\tmean.value deviation.value);\n\t\t}\n\t}\n\n\tFractal_item = class \n\t\tMenuaction \"_Fractal\" \"make a fractal image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t}\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n\tColour_atlas_item = class\n\tMenuaction \"_Colour Atlas\"\n\t\t\"make a grid of patches grouped around a colour\" {\n\t\taction = class \n\t\t\t_result {   \n\t\t\t_vislevel = 3;\n       \n\t\t\tstart = Colour_picker \"Lab\" [50,0,0];\n\t\t\tnstep = Expression \"Number of steps\" 9;\n\t\t\tssize = Expression \"Step size\" 10; \n\t\t\tpsize = Expression \"Patch size\" 32;\n\t\t\tsepsize = Expression \"Separator size\" 4;\n\t\n\t\t\t_result\n\t\t\t\t= colour_transform_to (get_type start) blocks'''\n\t\t\t{\n\t\t\t\tsize = (to_real nstep * 2 + 1) * to_real psize - \n\t\t\t\t\tto_real sepsize;\n\t\t\t\txy = make_xy size size; \n\n\t\t\t\txy_grid = (xy % to_real psize) < \n\t\t\t\t\t(to_real psize - to_real sepsize);\n\t\t\t\tgrid = xy_grid?0 & xy_grid?1;\n\n\t\t\t\tblocks = (int) (to_real ssize * ((int) (xy / to_real psize)));\n\t\t\t\tlab_start = colour_transform_to Image_type.LAB start;\n\t\t\t\tblocks' = blocks - to_real nstep * to_real ssize + \n\t\t\t\t\tVector (tl lab_start.value);\n\t\t\t\tblocks'' = hd lab_start.value ++ Image blocks';\n\t\t\t\tblocks''' \n\t\t\t\t\t= image_set_type Image_type.LAB blocks'', Image grid\n\t\t\t\t\t= 0;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.26/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/7.26\n\nstart_DATA = \\\n\tMath.def \\\n\tImage.def \\\n\tColour.def \\\n\tTasks.def \\\n\tObject.def \\\n\tFilter.def \\\n\tMatrix.def \\\n\tWidgets.def \\\n\tHistogram.def \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_convert.def \\\n\t_generate.def \\\n\t_list.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\t_Object.def \\\n\t_types.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/7.26/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_And\" \"bitwise and of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_Or\" \"bitwise or of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"E_xclusive Or\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_Not\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBand_or_item = class \n\t\tMenuaction \"Band O_r\" \"or the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_or @ bandsplit) im;\n\t}\n\n\tBand_and_item = class \n\t\tMenuaction \"Band A_nd\" \"and the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_and @ bandsplit) im;\n\t}\n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tDifference_item = class \n\t\tMenuaction \"_Difference\" \"difference of two lists\" {\n\t\taction a b = map_binary difference a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tValue_item = class \n\t\tMenuaction \"_Value\" \"value of point in object\" {\n\t\taction a = class _result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tposition = Expression \"Coordinate\" (0, 0);\n\t\n\t\t\t_result = map_binary point position.expr a;\n\t\t}\n\t}\n\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \n\t\t\t\"position of centre of gravity of histogram\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = linreg xes yes;\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = linregw xes yes devs;\n\t}\n\n\tCluster_item = class \n\t\tMenuaction \"_Cluster\" \"cluster a list of numbers\" {\n\t\taction l = class {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tthresh = Expression \"Threshold\" 10;\n\t\n\t\t\t[_r, _w] = cluster thresh.expr l;\n\t\n\t\t\tresult = _r;\n\t\t\tweights = _w;\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.26/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_identity_item = class \n\t\tMenuaction \"_Identity\" \"make an identity matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" 5;\n\n\t\t\t_result = Matrix (identity_matrix s.expr);\n\t\t}\n\t}\n\n\tMatrix_series_item = class \n\t\tMenuaction \"_Series\" \"make a series\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Start value\" 0;\n\t\t\tt = Expression \"Step by\" 1;\n\t\t\te = Expression \"End value\" 5;\n\n\t\t\t_result \n\t\t\t\t= Matrix (transpose [series])\n\t\t\t{\n\t\t\t\tseries = [to_real s, to_real t..  to_real e];\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_square_item = class \n\t\tMenuaction \"_Square\" \"make a square matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" 5;\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (s.expr ** 2) 0 square\n\t\t\t{\n\t\t\t\tline = take s.expr [1, 1 ..];\n\t\t\t\tsquare = replicate s.expr line;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_circular_item = class \n\t\tMenuaction \"_Circular\" \"make a circular matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tr = Expression \"Radius\" 5;\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum circle) 0 circle\n\t\t\t{\n\t\t\t\tline = [-r.expr .. r.expr];\n\t\t\t\txes = replicate (2 * r.expr + 1) line;\n\t\t\t\tyes = transpose xes;\n\t\t\t\tcircle = map2 (map2 pyth) xes yes\n\t\t\t\t{\n\t\t\t\t\tpyth a b \n\t\t\t\t\t\t= 1, (a**2 + b**2) ** 0.5 <= r.expr\n\t\t\t\t\t\t= 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\nMatrix_sort_item = class \n\tMenuaction \"_Sort\" \"sort by column or row\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\to = Option (_ \"Orientation\") [\n\t\t\t_ \"Sort by column\",\n\t\t\t_ \"Sort by row\"\n\t\t] 0;\n\t\ti = Expression (_ \"Sort on index\") 0;\n\t\td = Option (_ \"Direction\") [\n\t\t\t_ \"Ascending\",\n\t\t\t_ \"Descending\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary sort x\n\t\t{\n\t\t\tidx = to_real i;\n\t\t\tpred a b \n\t\t\t\t= a?idx <= b?idx, d == 0\n\t\t\t\t= a?idx >= b?idx;\n\t\t\tsort x\n\t\t\t\t= (x.Matrix_base @ sortc pred) x.value,\n\t\t\t\t\to == 0\n\t\t\t\t= (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value;\n\t\t}\n\t}\n}\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ \n\t\t\t\t\trange;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.26/Object.def",
    "content": "Object_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nObject_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nObject_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nObject_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nObject_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list (or group) of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.26/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\n\tCsv_import_item = class\n\t\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tstart_line = Expression \"Start at line\" 1;\n\t\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_csv2vips filename)\n\t\t\t{\n\t\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\t\tescape x \n\t\t\t\t\t= foldr prefix [] x\n\t\t\t\t{\n\t\t\t\t\tprefix x l\n\t\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t\t= x : l;\n\t\t\t\t}\n\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tRaw_import_item = class\n\t\tMenuaction \"_Raw Import\" \"read a file of binary values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tacross = Expression \"Pixels across\" 100;\n\t\t\tdown = Expression \"Pixels down\" 100;\n\t\t\tbytes = Expression \"Bytes per pixel\" 3;\n\t\t\tskip = Expression \"Skip over initial bytes\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_binfile path.value \n\t\t\t\t\tacross.expr down.expr bytes.expr skip.expr)\n\t\t\t{\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// interpret Analyze header for layout and calibration\n\tAnalyze7_header_item = class\n\t\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\t\"examine the Analyze header and set layout and value\" {\n\t\taction x \n\t\t\t= x'''\n\t\t{\n\t\t\t// read bits of header\n\t\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\t\tdim0 = dim 0 x;\n\t\t\tdim1 = dim 1 x;\n\t\t\tdim2 = dim 2 x;\n\t\t\tdim3 = dim 3 x;\n\t\t\tdim4 = dim 4 x;\n\t\t\tdim5 = dim 5 x;\n\t\t\tdim6 = dim 6 x;\n\t\t\tdim7 = dim 7 x;\n\t\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\t\n\t\t\t// oops, now a nop\n\t\t\tx' = x;\n\t\n\t\t\t// lay out higher dimensions width-ways\n\t\t\tx'' \n\t\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\t\tdim0 == 7\n\t\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\t\n\t\t\t// multiply by scale factor to get kBeq\n\t\t\tx''' = x'' * (cal_max / glmax);\n\t\t}\n\t}\n\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\t[image, patch] = sortc larger [a, b];\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\tmode = Option \"Input LUT\" [\n\t\t\t\t\"Linear input\",\n\t\t\t\t\"Fit intercept from chart greyscale\",\n\t\t\t\t\"Linearize input from chart greyscale\"\n\t\t\t] 2;\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = measure 0 0 image.width image.height 6 4 image.value;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb \n\t\t\t\t= Matrix [[0, 0], [1, 1]], mode == 0\n\t\t\t\t= Matrix [0: intercepts, replicate (_camera.width + 1) 1], \n\t\t\t\t\tmode == 1\n\t\t\t\t= Matrix (map2 cons _true_grey_Y' _camera_grey')\n\t\t\t{\n\t\t\t\tintercepts = [(linreg _true_grey_Y' cam).intercept :: \n\t\t\t\t\tcam <- transpose _camera_grey'];\n\t\t\t}\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\t// plot from 0 explicitly so we see the effect of mode1 (intercept\n\t\t\t// from greyscale)\n\t\t\tlinearising_lut = Plot [$ymin => 0] _linear_lut;\n\n\t\t\t// map the original image through the lineariser to \n\t\t\t// get linear 0-1 RGB image\n\t\t\t_image' = hist_map linearising_lut.value image.value;\n\n\t\t\t// remeasure and solve for RGB -> XYZ\n\t\t\t_camera' = im_measure _image' 0 0 image.width image.height 6 4;\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\tM = transpose (_pinv * transpose _camera' * _true_XYZ);\n\n\t\t\t// convert linear RGB camera to Lab \n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tcast_float @\n\t\t\t\trecomb M) _image';\n\n\t\t\t// measure again and compute dE76\n\t\t\t_camera'' = im_measure _result.value 0 0 \n\t\t\t\timage.width image.height 6 4;\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tfinal_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0 && i < len macbeth_names\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b = class\n\t\t\t(map_binary process a b) {\n\t\t\tprocess a b\n\t\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t\t{\n\t\t\t\t// the name of the calib object we need\n\t\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t\t// get the Calibrate_chart arg first\n\t\t\t\t[image, calib] = sortc (const (is_instanceof calib_name)) \n\t\t\t\t\t[a, b];\n\n\t\t\t\t// map the original image through the lineariser to get \n\t\t\t\t// linear 0-1 RGB image\n\t\t\t\timage' = hist_map calib.linearising_lut image;\n\n\t\t\t\t// convert linear RGB camera to Lab \n\t\t\t\tresult = colour_transform Image_type.XYZ Image_type.LAB \n\t\t\t\t\t((float) (recomb calib.M image'));\n\t\t\t}\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [$style => style.value] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\t!is_list_len 2 images\n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = all (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize Interpolate_bilinear xfactor yfactor scale_im;\n\t\t\t_offset_im = resize Interpolate_bilinear xfactor yfactor offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.26/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.26/_Object.def",
    "content": "/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0|1|2|3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \n\tjoin_sep \"|\" Image_type.colour_spaces.names];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide|VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad properties for \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"where\" ++ \"\\n\" ++ arg_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make arg type notes\n\targ_types = join_sep \"\\n\" (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"\\n\" ++ _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = join_sep \"\\n\" all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if those fail as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if that fails as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary'_function op a b\n\t= matches1?0, matches1 != []\n\t= matches2?0, op.symmetric && matches2 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0, matches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t// these should always be defined\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x = oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x = oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op = oo_unary_function (oo_unary_lookup op) this;\n\n\too_binary_table op x = [];\n\too_unary_table op = [];\n}\n"
  },
  {
    "path": "share/nip2/compat/7.26/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n// like to_image, but we do 1x1 pixel + x, then embed it up\n// always make an unwrapped image for speed ... this gets used by ifthenelse\n// and stuff like that\n// format can be NULL, meaning set format from x\nto_image_size width height bands format x\n\t= x, is_image x\n\t= x.value, is_Image x\n\t= im''\n{\n\t// we want x to set the target format if we don't have one, so we\n\t// can't use image_new\n\tim = im_black 1 1 bands + x;\n\tim'\n\t\t= clip2fmt format im, format != NULL\n\t\t= im;\n\tim'' = embed 1 0 0 width height im';\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && is_list_len 3 x\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The innermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x && !contains_Group x\n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), !is_list_len 2 parts \n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, !is_list_len 4 parts \n\t= (ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", member \".0123456789\",\n\t\tmember \"eE\", member \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), !is_list_len 5 parts \n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t$D93 => D93_whitepoint,\n\t$D75 => D75_whitepoint,\n\t$D65 => D65_whitepoint,\n\t$D55 => D55_whitepoint,\n\t$D50 => D50_whitepoint,\n\t$A => A_whitepoint,\n\t$B => B_whitepoint,\n\t$C => C_whitepoint,\n\t$E => E_whitepoint,\n\t$D3250 => D3250_whitepoint\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, image_set_type GREY16 @ im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l = join_sep path_separator l;\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 > 1 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n"
  },
  {
    "path": "share/nip2/compat/7.26/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= embed 1 0 0 w h im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black 1 1 (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = im_gauss_imask_sep (radius / 3) 0.2;\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.26/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 1;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" \n\t] 4;\n\n\tcontrol_selection mask im no\n\t\t= [\n\t\t\tif mask then im * 1.2 else im * 1,\n\t\t\tif mask then im * 0.8 else im * 1,\n\t\t\tif mask then 0 else im,\n\t\t\tif mask then 255 else im,\n\t\t\tif mask then im else 0,\n\t\t\tif mask then im else 255,\n\t\t\tmask\n\t\t]?no;\n\n\tRectangle = class\n\t\tMenuaction \"_Rectangle\"\n\t\t\t\"use line/arrow/rect x to define a rectangle\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_rect x;\n\t\t\t\tim = get_image x;\n\t\t\t\tselect_rect x\n\t\t\t\t\t= Image mask\n\t\t\t\t{\n\t\t\t\t\tim = Image (get_image x);\n\t\t\t\t\timc = make_xy im.width im.height;\t\n\t\t\t\t\tmask = imc?0 >= x.nleft & \n\t\t\t\t\t\t\timc?0 < x.nright & \n\t\t\t\t\t\t\timc?1 >= x.ntop & \n\t\t\t\t\t\t\timc?1 < x.nbottom;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = get_image a;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = get_image ((pt_list.value)?0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize Interpolate_bilinear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize Interpolate_bilinear f1 1 b1\n\t\t\t\t\t{b1 = resize Interpolate_bilinear 1 f2 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/7.26/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = Image (get_image line);\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = Image (get_image (pt_l?0));\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t};\n\nMount_options _ctype _ppcm = class \n  {\n  _vislevel = 3;\n  apply = Toggle \"Apply mount options\" false;\n  ls = Expression \"Lower mount section bigger by (cm)\" 0;\n  mount_colour = Colour _ctype [0, 0, 0];\n  _los = ls.expr * _ppcm;\n  };\n\nFrame_variables comp = class\n  {\n  _vislevel = 3;\n\n  scale_factor = Expression \"scale the size of the frame by\" 1;\n\n  /* These sliders define the fraction of the frames width or height is extracted\n   * to produce each of the particular regions.\n   */\n  corner_section = Scale \"Corner section\" 0.1 1 0.5;\n  edge_section = Scale \"Edge section\" 0.1 1 0.2, comp > 0\n\t\t\t\t  = \"Only required for complex frames\";\n  middle_section = Scale \"Middle section\" 0.1 1 0.2;\n  blend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n  option = Toggle \"Use mirror of left-side to make right\" true;\n  };\n\n"
  },
  {
    "path": "share/nip2/compat/7.26/_list.def",
    "content": "/* any l: or all the elements of list l together\n *\n * any (map (equal 0) list) == true, if any element of list is zero.\n * any :: [bool] -> bool\n */\nany = foldr logical_or false;\n\n/* all l: and all the elements of list l together\n *\n * all (map (==0) list) == true, if every element of list is zero.\n * all :: [bool] -> bool\n */\nall = foldr logical_and true;\n\n/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* delete eq x l: delete the first x from l\n *\n * delete equal 'b' \"abcdb\" == \"acdb\"\n * delete :: (* -> bool) -> * -> [*] -> [*]\n */\ndelete eq a l\n\t= [], l == []\n\t= y, eq a b\n\t= b : delete eq a y\n{\n\tb:y = l;\n}\n\n/* difference eq a b: delete b from a\n *\n * difference equal \"asdf\" \"ad\" == \"sf\"\n * difference :: (* -> bool) -> [*] -> [*] -> [*]\n */\ndifference = foldl @ converse @ delete;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn x, fn a\n\t= l\n{\n\ta:x = l;\n}\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st (hd l)) (tl l);\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn (hd l) (tl l);\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn (hd l) (foldr fn st (tl l));\n\n/* foldrl fn l: like foldr, but use the 1st element as the start value\n *\n * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= foldr fn (hd l) (tl l);\n\n/* Search a list for an element, returning its index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn (hd l)\n\t\t= search (tl l) (n + 1);\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= hd l : init (tl l);\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* join_sep sep l: join a list with a separator\n *\n * join_sep \", \" (map print [1 .. 4]) == \"1, 2, 3, 4\"\n * join_sep :: [*] -> [[*]] -> [*]\n */\njoin_sep sep l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ sep ++ b;\n}\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= hd l, tl l == []\n\t= last (tl l);\n\n/* len l: length of list l\n * (see also is_list_len and friends in predicate.def)\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta:b:x = l;\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = any (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge p l r\n\t= [], p == [] || l == [] || r == []\n\t= a : merge z x y, c\n\t= b : merge z x y\n{\n\ta:x = l;\n\tb:y = r;\n\tc:z = p;\n}\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta:x = l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scan fn st l: apply (fold fn r) to every initial segment of a list\n *\n * scan add 0 [1,2,3] == [1,3,6]\n * scan :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscan fn \n\t= g \n{\n\tg st l\n\t\t= [st], l == []\n\t\t= st : g (fn st a) x\n\t{\n\t\ta:x = l;\n\t}\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta:x = l1;\n\t\tb:y = l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/7.26/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = any (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && all (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* Test list length ... quicker than len x == n for large lists.\n */\nis_list_len n x\n\t= true, x == [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len (n - 1) (tl x);\n\nis_list_len_more n x\n\t= true, x != [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len_more (n - 1) (tl x);\n\nis_list_len_more_equal n x\n\t= true, n == 0\n\t= false, x == [] \n\t= is_list_len_more_equal (n - 1) (tl x);\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, all (map is_obj l)\n\t= true, all (map is_list l) &&\n\t\tall (map (not @ is_obj) l) &&\n\t\tall (map is_rectangular l) &&\n\t\tis_list_len_more 0 l &&\n\t\tall (map (is_list_len (len (hd l))) (tl l))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && is_list_len (len (hd l)) l;\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_NULL x = is_instanceof \"NULL\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && all (map xy l)\n{\n\txy l = is_real_list l && is_list_len 2 l;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && any (map is_Group l)\n\t= any (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= error (\"get_type: unable to get type from \" ++ print x)\n{\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\t// can have alpha, hence we let bands be one more than you might think\n\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.GREY16, type == Image_type.GREY16 && is_bands 1\n\t\t= Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && \n\t\t\t(width == 1 || height == 1)\n\t\t= Image_type.B_W, is_bands 1 \n\t\t= Image_type.CMYK, type == Image_type.CMYK && is_bands 4\n\t\t= type, is_colorimetric && is_bands 3\n\t\t= Image_type.sRGB, !is_colorimetric && is_bands 3\n\t\t= Image_type.MULTIBAND, !is_colorimetric && !is_bands 3\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\n\t\t// is bands n, with an optional alpha (ie. can be n + 1 too)\n\t\tis_bands n = bands == n || bands == n + 1;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= error (\"get_format: unable to get format from \" ++ print x);\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= error (\"get_bits: unable to get bits from \" ++ print x);\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= error (\"get_bands: unable to get bands from \" ++ print x);\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= error (\"get_coding: unable to get coding from \" ++ print x);\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= error (\"get_xres: unable to get xres from \" ++ print x);\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= error (\"get_yres: unable to get yres from \" ++ print x);\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= error (\"get_xoffset: unable to get xoffset from \" ++ print x);\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= error (\"get_yoffset: unable to get yoffset from \" ++ print x);\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= error (\"get_image: unable to get image from \" ++ print x);\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= error (\"get_number: unable to get number from \" ++ print x);\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= error (\"get_real: unable to get real from \" ++ print x);\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= error (\"get_width: unable to get width from \" ++ print x);\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= error (\"get_height: unable to get height from \" ++ print x);\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= error (\"get_left: unable to get left from \" ++ print x);\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= error (\"get_top: unable to get top from \" ++ print x);\n\n// like has/get member, but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.26/_stdenv.def",
    "content": "/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\nidivide a b = (int) ((int) a / (int) b);\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\n// 'difference' is defined in _list\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the function we call for \"a -> v\" expressions\nmksvpair s v\n\t= [s, v], is_string s\n\t= error \"not str on lhs of ->\";\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error (\"unimplemented vector operation: \" ++ op_name)\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n// make a name value pair\nmknvpair n v\n\t= [n, v], is_string n\n\t= error \"not [char] on LHS of =>\";\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined, has_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nsum x\n\t= oo_unary_function sum_op x, is_class x\n\t= im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x\n\t= sum_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"sum\")\n{\n\tsum_op = Operator \"sum\" sum Operator_type.COMPOUND false;\n\n\t// add elements in a nested-list thing\n\tsum_list l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nproduct x\n\t= oo_unary_function product_op x, is_class x\n\t= product_list x, is_list x \n\t// (product image) doesn't make much sense :(\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"product\")\n{\n\tproduct_op = Operator \"product\" product Operator_type.COMPOUND false;\n\n\tproduct_list l\n\t\t= foldr prod 1 l\n\t{\n\t\tprod x total\n\t\t\t= total * product x, is_list x\n\t\t\t= total * x;\n\t}\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image_hist x, is_image x && \n\t\t(fmt == Image_format.UCHAR || fmt == Image_format.USHORT)\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tfmt = get_format x;\n\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean, for any image type\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n\n\t// image mean for 8 and 16-bit unsigned images\n\t// we can use a histogram, yay, and save a pass through the image\n\tmeanze_image_hist i\n\t\t= sum / N\n\t{\n\t\t// histogram, knock out zeros\n\t\thist = hist_find i;\n\t\tblack = image_new 1 1 (get_bands hist) \n\t\t\t(get_format hist) (get_coding hist) (get_type hist) 0 0 0;\n\t\thistze = insert 0 0 black hist;\n\n\t\t// matching identity\n\t\tiden\n\t\t\t= im_identity_ushort (get_bands hist) (get_width hist),\n\t\t\t\t(get_width hist) > 256\n\t\t\t= im_identity (get_bands hist);\n\n\t\t// number of non-zero pixels\n\t\tN = mean histze * 256;\n\n\t\t// sum of pixels\n\t\tsum = mean (hist * iden) * 256;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_cache x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (\\row [row?x']) obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\")\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x \n\t\t\t= to_image_size target_width target_height \n\t\t\t\ttarget_bands target_format x;\n\n\t\t[then_image, else_image] = map to_image [then_part, else_part];\n\n\t\tblend_result_image = image_set_type target_type \n\t\t\t(im_blend cond then_image else_image);\n\t}\n}\n\n// do big first: we want to keep big's class, if possible\n// eg. big is a Plot, small is a 1x1 Image\ninsert x y small big\n\t= oo_binary'_function insert_op small big, is_class big\n\t= oo_binary_function insert_op small big, is_class small\n\t= im_insert big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n}\n\nmeasure x y w h u v image\n\t= oo_unary_function measure_op image, is_class image\n\t= im_measure image \n\t\t(to_real x) (to_real y) (to_real w) (to_real h)\n\t\t(to_real u) (to_real v), \n\t\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"measure\")\n{\n\tmeasure_op = Operator \"measure\" \n\t\t(measure x y w h u v) Operator_type.COMPOUND_REWRAP false;\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ninvert x\n\t= oo_unary_function invert_op x, is_class x\n\t= im_invert x, is_image x\n\t= 255 - x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"invert\")\n{\n\tinvert_op = Operator \"invert\" invert Operator_type.COMPOUND false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate interp angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_affinei_all image interp.value a (-b) b a 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\t(rotate interp) Operator_type.COMPOUND_REWRAP false;\n\ta = cos angle;\n\tb = sin angle;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_lr\")\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin_lr Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert (get_width a) 0 b a;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_tb\")\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin_tb Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert 0 (get_height a) b a;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\t// The [[real]] can contain 128 values ... squeeze them out!\n\timage = im_mask2vips (Matrix m2) == 255;\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\" ++ \": \" ++ \n\t\t\"conv (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvf mask image\n\t= oo_unary_function convf_op image, is_class image\n\t= im_conv_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convf\" ++ \": \" ++ \n\t\t\"convf (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconvf_op = Operator \"convf\" \n\t\t(convf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\naconvsep layers mask image \n\t= oo_unary_function aconvsep_op image, is_class image\n\t= im_aconvsep image (to_matrix mask) (to_real layers), is_image image\n\t= error (_ \"bad arguments to \" ++ \"aconvsep\")\n{\n\taconvsep_op = Operator \"aconvsep\" \n\t\t(aconvsep layers mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsep_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\ngreyc iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx x\n\t= oo_unary_function greyc_op x, is_class x\n\t= greyc_im x, is_image x\n\t= error (_ \"bad argument\" ++ \" (\" ++ print x ++ \") to \" ++ \"greyc\")\n{\n\tgreyc_op = Operator \"greyc\" (greyc\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im x = im_greyc x\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\ngreyc_mask iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx mask x\n\t= oo_binary_function greyc_mask_op mask x, is_class mask\n\t= oo_binary'_function greyc_mask_op mask x, is_class x\n\t= greyc_im mask x, is_image mask && is_image x\n\t= error (_ \"bad arguments\" ++ \n\t\t\" (\" ++ print mask ++ \", \" ++ print x ++ \") \" ++\n\t\t\"to \" ++ \"greyc\")\n{\n\tgreyc_mask_op = Operator \"greyc_mask\" (greyc_mask\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im mask x = im_greyc_mask x mask\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_indexed index value\n\t= oo_binary_function hist_find_indexed_op index value, is_class index\n\t= oo_binary'_function hist_find_indexed_op index value, is_class value\n\t= im_hist_indexed index value, is_image index && is_image value\n\t= error (_ \"bad arguments to \" ++ \"hist_find_indexed\")\n{\n\thist_find_indexed_op = Operator \"hist_find_indexed\" \n\t\t(compose (compose Plot_histogram) hist_find_indexed) \n\t\t\tOperator_type.COMPOUND false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h \n\t\t= (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h\n\t{\n\t\t// up the format so it can represent the whole range of\n\t\t// possible values from this mask\n\t\tfmt x\n\t\t\t= Image_format.SHORT, \n\t\t\t\tx == Image_format.UCHAR || x == Image_format.CHAR\n\t\t\t= Image_format.INT, \n\t\t\t\tx == Image_format.USHORT || x == Image_format.SHORT ||\n\t\t\t\tx == Image_format.UINT \n\t\t\t= x;\n\t}\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= lhisteq image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n\n\t// loop over bands, if necessary\n\tlhisteq im\n\t\t= im_lhisteq im (to_real w) (to_real h), get_bands im == 1\n\t\t= (foldl1 join @ map lhisteq @ bandsplit) im;\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nresize interp xfac yfac image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\t// is this interpolation nearest-neighbour?\n\tis_nn x = x.type == Interpolate_type.NEAREST_NEIGHBOUR;\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// upscale by any factor, nearest neighbour \n\t\t// upscale by integer part, then affine to exact size\n\t\t= scale xg?1 yg?1 (im_zoom im xg?0 yg?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// downscale by any factor, nearest neighbour \n\t\t// downscale by integer part, then affine to exact size\n\t\t= scale xs?1 ys?1 (im_subsample im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// upscale by any factor with affine\n\t\t= scale xfac' yfac' im,\n\t\t\txfac' >= 1 && yfac' >= 1 \n\n\t\t// downscale by any factor, bilinear\n\t\t// block shrink by integer factor, then resample to \n\t\t// exact with affine\n\t\t= scale xs?1 ys?1 (im_shrink im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 \n\n\t\t= error (\"resize: unimplemented argument combination:\\n\" ++ \n\t\t\t\"  xfac = \" ++ print xfac' ++ \"\\n\" ++\n\t\t\t\"  yfac = \" ++ print yfac' ++ \"\\n\" ++\n\t\t\t\"  interp = \" ++ print interp ++ \" (\" ++\n\t\t\t\tInterpolate_type.descriptions?interp.type ++ \")\")\n\t{\n\t\t// convert a float scale to integer plus fraction\n\t\t// eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25)\n\t\tbreak f = [floor f, f / floor f];\n\n\t\t// same, but for downsizing ... turn a float scale which is less than\n\t\t// 1 into an int shrink and a float scale\n\n\t\t// complicated: the int shrink may round the size down (eg. imagine\n\t\t// subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide\n\t\t// image, not a 3.666 pixel wide image), so pass in the size of image\n\t\t// we are operating on and adjust for any rounding\n\t\t\n\t\t// so ... x is (eg.) 467, f is (eg. 128/467, about 0.274)\n\t\trbreak x f \n\t\t\t= [int_shrink, float_resample]\n\t\t{\n\t\t\t// the size of image we are aiming for after the combined int and\n\t\t\t// float resample\n\t\t\tx' = x * f;\n\n\t\t\t// int part\n\t\t\tint_shrink = floor (1 / f);\n\n\t\t\t// size after int shrink\n\t\t\tx'' = floor (x / int_shrink);\n\n\t\t\t// therefore what we need for the float part\n\t\t\tfloat_resample = x' / x'';\n\t\t}\n\n\t\twidth = get_width im;\n\t\theight = get_height im;\n\n\t\t// grow and shrink factors\n\t\txg = break xfac';\n\t\tyg = break yfac';\n\t\txs = rbreak width xfac';\n\t\tys = rbreak height yfac';\n\n\t\t// resize\n\t\tscale xfac yfac im\n\t\t\t= im_affinei_all im interp.value xfac 0 0 yfac 0 0;\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ndraw_flood_blob x y ink image\n\t= oo_unary_function draw_flood_blob_op image, is_class image\n\t= im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood_blob\")\n{\n\tdraw_flood_blob_op = Operator \"draw_flood_blob\" \n\t\t(draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_flood x y ink image\n\t= oo_unary_function draw_flood_op image, is_class image\n\t= im_draw_flood image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood\")\n{\n\tdraw_flood_op = Operator \"draw_flood\" \n\t\t(draw_flood x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_rect x y w h f ink image\n\t= oo_unary_function draw_rect_op image, is_class image\n\t= im_draw_rect image (to_real x) (to_real y) \n\t\t(to_real w) (to_real h) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect\")\n{\n\tdraw_rect_op = Operator \"draw_rect\" \n\t\t(draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_circle x y r f ink image\n\t= oo_unary_function draw_circle_op image, is_class image\n\t= im_draw_circle image (to_real x) (to_real y) \n\t\t(to_real r) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_circle\")\n{\n\tdraw_circle_op = Operator \"draw_circle\" \n\t\t(draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_line x1 y1 x2 y2 ink image\n\t= oo_unary_function draw_line_op image, is_class image\n\t= im_draw_line image (to_real x1) (to_real y1) \n\t\t(to_real x2) (to_real y2) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_line\")\n{\n\tdraw_line_op = Operator \"draw_line\" \n\t\t(draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (\\x x % base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (\\x idivide x base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= NULL, any (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n/* Linear regression. Return a class with the stuff we need in.\n * from s15.2, p 665 NR in C\n */\nlinreg xes yes\n    = obj\n{\n    obj = class {\n        // in case we ever get shown in the workspace\n        _vislevel = 2;\n\n        slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2;\n        intercept = (sy - sx * slope) / ss;\n\n        chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes];\n\n        siga = (chi2 / (ss - 2)) ** 0.5 *\n            ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5;\n        sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5;\n\n        // for compat with linregw, see below\n        q = 1.0;\n    }\n\n    ss = len xes;\n    sx = sum xes;\n    sy = sum yes;\n    sxoss = sx / ss;\n\n    tes = [x - sxoss :: x <- xes];\n    st2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Weighted linear regression. Xes, yes and a list of deviations.\n */\nlinregw xes yes devs \n\t= obj\n{\n\tobj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: \n\t\t\t[x, y, sd] <- zip3 xes yes devs];\n\n\t\tsiga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (1 / st2) ** 0.5;\n\n\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\t}\n\n\twt = [sd ** -0.5 :: sd <- devs];\n\n\tss = sum wt;\n\tsx = sum [x * w :: [x, w] <- zip2 xes wt];\n\tsy = sum [y * w :: [y, w] <- zip2 yes wt];\n\tsxoss = sx / ss;\n\n\ttes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Clustering: pass in a list of points, repeatedly merge the\n * closest two points until no two points are closer than the threshold.\n * Return [merged-points, corresponding-weights]. A weight is a list of the\n * indexes we merged to make that point, ie. len weight == how significant\n * this point is.\n *\n * eg. \n *\tcluster 12 [152,154,155,42,159] == \n *\t\t[[155,42],[[1,2,0,4],[3]]]\n */\ncluster thresh points\n\t= oo_unary_function cluster_op points, is_class points\n\t// can't use [0..len points - 1], in case len points == 0\n\t= merge [points, map (converse cons []) (take (len points) [0 ..])],\n\t\tis_list points\n\t= error (_ \"bad arguments to \" ++ \"cluster\")\n{\n\tcluster_op = Operator \"cluster\" \n\t\t(cluster thresh) Operator_type.COMPOUND false;\n\n\tmerge x\n\t\t= x, m < 2 || d > thresh\n\t\t= merge [points', weights']\n\t{\n\t\t[points, weights] = x;\n\t\tm = len points;\n\n\t\t// generate indexes of all possible pairs, avoiding comparing a thing \n\t\t// to itself, and assuming that dist is reflexive\n\t\t// first index is always less than 2nd index\n\t\t// the +1,+2 makes sure we have an increasing generator, otherwise we\n\t\t// can get [3 .. 4] (for example), which will make a decreasing\n\t\t// sequence\n\t\tpairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]];\n\n\t\t// distance function\n\t\t// arg is eg. [3,1], meaning get distance from point 3 to point 1\n\t\tdist x \n\t\t\t= abs (points?i - points?j)\n\t\t{\n\t\t\t[i, j] = x;\n\t\t}\n\n\t\t// smallest distance, then the two points we merge\n\t\tp = minpos (map dist pairs);\n\t\td = dist pairs?p;\n\t\t[i, j] = pairs?p;\n\n\t\t// new point and new weight\n\t\tnw = weights?i ++ weights?j;\n\t\tnp = (points?i * len weights?i + points?j * len weights?j) / len nw;\n\n\t\t// remove element i from a list\n\t\tremove i l = take i l ++ drop (i + 1) l;\n\n\t\t// remove two old points, add the new merged one\n\t\t// i < j (see \"pairs\", above)\n\t\tpoints' = np : remove i (remove j points);\n\t\tweights' = nw : remove i (remove j weights);\n\t}\n}\n\n/* Extract the area of an image around an arrow.\n * Transform the image to make the arrow horizontal, then displace by hd and\n * vd pxels, then cut out a bit h pixels high centered on the arrow.\n */\nextract_arrow hd vd h arrow\n\t= extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im'\n{\n\t// the line as a polar vector\n\tpv = polar (arrow.width, arrow.height);\n\ta = im pv;\n\n\t// smallest rotation that will make the line horizontal\n\ta'\n\t\t= 360 - a, a > 270\n\t\t= 180 - a, a > 90\n\t\t= -a;\n\n\tim' = rotate Interpolate_bilinear a' arrow.image;\n\n\t// look at the start and end of the arrow, pick the leftmost\n\tp\n\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t= (arrow.right, arrow.bottom);\n\n\t// transform that point to im' space\n\tp' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset);\n}\n\n/* You'd think these would go in _convert, but they are not really colour ops,\n * so put them here.\n */\nrad2float image\n\t= oo_unary_function rad2float_op image, is_class image\n\t= im_rad2float image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"rad2float\")\n{\n\trad2float_op = Operator \"rad2float\" \n\t\trad2float Operator_type.COMPOUND_REWRAP false;\n}\n\nfloat2rad image\n\t= oo_unary_function float2rad_op image, is_class image\n\t= im_float2rad image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"float2rad\")\n{\n\tfloat2rad_op = Operator \"float2rad\" \n\t\tfloat2rad Operator_type.COMPOUND_REWRAP false;\n}\n\nsegment x\n\t= oo_unary_function segment_op x, is_class x\n\t= image', is_image x \n\t= error (_ \"bad arguments to \" ++ \"segment\")\n{\n\tsegment_op = Operator \"segment\" \n\t\tsegment Operator_type.COMPOUND_REWRAP false;\n\n\t[image, nsegs] = im_segment x;\n\timage' = im_copy_set_meta image \"n-segments\" nsegs;\n}\n\npoint a b\n\t= oo_binary_function point_op a b, is_class a\n\t= oo_binary'_function point_op a b, is_class b\n\t= im_read_point b x y, is_image b\n\t= [b?x?y], is_matrix b\n\t= [b?x], is_real_list b && y == 0\n\t= [b?y], is_real_list b && x == 0\n\t= error (_ \"bad arguments to \" ++ \"point\")\n{\n\tpoint_op = Operator \"point\" \n\t\t(\\a\\b Vector (point a b)) Operator_type.COMPOUND false;\n\n\t(x, y) \n\t\t= a, is_complex a;\n\t\t= (a?0, a?1), is_real_list a && is_list_len 2 a\n\t\t= error \"bad position format\";\n}\n\n/* Generate an ImageMagick (or GraphicsMagick) command suitable for \n * im_system_image. Use convert.exe in $VIPSHOME/bin, if it exists, otherwise\n * assume it's on the path somewhere.\n */\nmagick_command switch \n\t= join_sep \" \" [convert, \"\\\"%s\\\"\", switch, \"\\\"%s\\\"\"]\n{\n\tprefs = Workspaces.Preferences;\n\tuse_gm = prefs.USE_GRAPHICSMAGICK;\n\tname = if use_gm then \"gm\" else \"convert\";\n\texe = concat [name, expand \"$EXEEXT\"];\n\tvipsexe = path_absolute [expand \"$VIPSHOME\", \"bin\", exe];\n\tfinal_exe \n\t\t= vipsexe, search vipsexe != []\n\t\t= exe;\n\tconvert\t\n\t\t= join_sep \" \" [final_exe, \"convert\"], use_gm\n\t\t= final_exe;\n}\n\n/* Run a command on an image. See magick_command, for example.\n */\nsystem_image command x\n\t= oo_unary_function system_image_op x, is_class x\n\t= system x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"system_image\")\n{\n\tsystem_image_op = Operator \"system_image\" \n\t\t(system_image command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem im\n\t\t= image_out\n\t{\n\t\t[image_out, log] = \n\t\t\tim_system_image (get_image im) \"%s.tif\" \"%s.tif\" command;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.26/_types.def",
    "content": "/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary (\\a op.fn a x) this,\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// we can't call map_trinary directly, since it uses Group and we\n\t// don't support mutually recursive top-level functions :-(\n\t// copy-paste it here, keep in sync with the version in _stdenv\n\tmap_nary fn args\n\t\t= fn args, groups == []\n\t\t= Group (map process [0, 1 .. shortest - 1])\n\t{\n\t\tgroups = filter is_Group args;\n\t\n\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\tprocess n\n\t\t\t= NULL, any (map (is_noval n) args)\n\t\t\t= map_nary fn (map (extract n) args)\n\t\t{\n\t\t\textract n arg\n\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t= arg;\n\t\n\t\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t\t}\n\t}\n\n\t// need ite as a true trinary\n\tite a b c = if a then b else c;\n\n\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t];\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\n\t\t[op.fn this.value x,\n\t\t\top.type == Operator_type.COMPOUND]\n\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[is_list_len 3 value, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.item colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum \"Colour space\" Image_type.colour_spaces default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\n/* An option whose value is a string rather than a number.\n */\nOption_string caption labels item = class\n\tOption caption labels (index (equal item) labels) {\n\tOption_edit caption labels value \n\t\t= this.Option_string caption labels (labels?value);\n}\n\n/* Make an option from an enum.\n */\nOption_enum caption enum item = class\n\tOption_string caption enum.names item {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing item;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum caption enum (enum.names?value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNONE = 0;\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNONE = 0;\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n\tRAD = 6;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* Extract a column.\n\t */\n\tcolumn n = map (extract n) value;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (column col) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (column from);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = this.column 0; \n\tthings = this.column 1; \n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tLUMINANCE = 2;\n\tXRAY = 3;\n\tIR = 4;\n\tYUV = 5;\n\tRED_ONLY = 6;\n\tGREEN_ONLY = 7;\n\tBLUE_ONLY = 8;\n\tPOWER_SPECTRUM = 9;\n\tHISTOGRAM = 10;\n\tLUT = 11;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMC = 14;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t$MULTIBAND => MULTIBAND,\n\t\t$B_W => B_W,\n\t\t$LUMINANCE => LUMINANCE,\n\t\t$XRAY => XRAY,\n\t\t$IR => IR,\n\t\t$YUV => YUV,\n\t\t$RED_ONLY => RED_ONLY,\n\t\t$GREEN_ONLY => GREEN_ONLY,\n\t\t$BLUE_ONLY => BLUE_ONLY,\n\t\t$POWER_SPECTRUM => POWER_SPECTRUM,\n\t\t$HISTOGRAM => HISTOGRAM,\n\t\t$LUT => LUT,\n\t\t$XYZ => XYZ,\n\t\t$LAB => LAB,\n\t\t$CMC => CMC,\n\t\t$CMYK => CMYK,\n\t\t$LABQ => LABQ,\n\t\t$RGB => RGB,\n\t\t$UCS => UCS,\n\t\t$LCH => LCH,\n\t\t$LABS => LABS,\n\t\t$sRGB => sRGB,\n\t\t$YXY => YXY,\n\t\t$FOURIER => FOURIER,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options generated from this, so match the order to the order in the\n\t * Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t$sRGB => sRGB,\n\t\t$Lab => LAB,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t$Mono => B_W,\n\t\t$sRGB => sRGB,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$Lab => LAB,\n\t\t$LabQ => LABQ,\n\t\t$LabS => LABS,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \n\t\t// \"Image v == 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\t// if one of then/else is an image, get the target format from that\n\t\t// otherwise, let the non-image objects set the target\n\t\ttarget_format \n\t\t\t= get_member_list has_format get_format x, \n\t\t\t\thas_member_list has_format x\n\t\t\t= NULL;\n\n\t\tto_image x = to_image_size width height target_bands target_format x;\n\n\t\t[then', else'] = map to_image x;\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if value then then' else else');\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nInterpolate_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\tLBB = 3;\n\tNOHALO = 4;\n\tVSQBS = 5;\n\n\t// Should introspect to get the list of interpolators :-(\n        // We can \"dir\" on VipsInterpolate to get a list of them, but we\n        // can't get i18n'd descriptions until we have more\n        // introspection stuff in nip2.\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Bilinear\", \n\t\t_ \"Bicubic\",\n\t\t_ \"Upsize: reduced halo bicubic (LBB)\",\n\t\t_ \"Upsharp: reduced halo bicubic with edge sharpening (Nohalo)\",\n\t\t_ \"Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)\"\n\t];\n\n\t/* And to vips type names.\n\t */\n\ttypes = [\n\t\t\"VipsInterpolateNearest\",\n\t\t\"VipsInterpolateBilinear\",\n\t\t\"VipsInterpolateBicubic\",\n\t\t\"VipsInterpolateLbb\",\n\t\t\"VipsInterpolateNohalo\",\n\t\t\"VipsInterpolateVsqbs\"\n\t];\n}\n\nInterpolate type options = class {\n\tvalue = vips_object_new Interpolate_type.types?type [] options;\n}\n\nInterpolate_bilinear = Interpolate Interpolate_type.BILINEAR [];\n\nInterpolate_picker default = class \n\tInterpolate interp.value [] {\n\t_vislevel = 2;\n\n\tinterp = Option \"Interpolation\" Interpolate_type.descriptions default;\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t_ \"Perceptual\" => PERCEPTUAL,\n\t\t_ \"Relative\" => RELATIVE,\n\t\t_ \"Saturation\" => SATURATION,\n\t\t_ \"Absolute\" => ABSOLUTE\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t_ \"Point\" => POINT,\n\t\t_ \"Line\" => LINE,\n\t\t_ \"Spline\" => SPLINE,\n\t\t_ \"Bar\" => BAR\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t_ \"YYYY\" => YYYY,\n\t\t_ \"XYYY\" => XYXY,\n\t\t_ \"XYXY\" => XYXY\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [$format => Plot_format.XYYY] value {\n}\n\n/* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate\n * empty slots, for example.\n */\nNULL = class \n\t_Object {\n\too_binary_table op x = [\n\t\t// the only operation we allow is equality .. use pointer equality,\n\t\t// this lets us test a == NULL and a != NULL\n\t\t[this === x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"equal\"],\n\t\t[this !== x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"not_equal\"]\n\t] ++ super.oo_binary_table op x;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.28/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t[_L, _a, _b] = default_value;\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Convert to\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Tag as\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Colour Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum (_ \"Old whitepoint\") Whitepoints \"D65\";\n\t\t\tnew_white = Option_enum (_ \"New whitepoint\") Whitepoints \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= monitor_profile, has_bands image && get_bands image == 3\n\t\t= print_profile;\n\trender_intents = Option_enum (_ \"Render intent\") Render_intent.names\n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_rad_item = class\n\tMenupullright (_ \"_Radiance\") (_ \"convert to and from Radiance packed format\") {\n\tUnpack_item = class\n\t\tMenuaction (_ \"Unpack\") \n\t\t\t(_ \"unpack Radiance format to float\") {\n\t\taction x = map_unary rad2float x;\n\t}\n\n\tPack_item = class\n\t\tMenuaction (_ \"Pack\") \n\t\t\t(_ \"pack 3-band float to Radiance format\") {\n\t\taction x = map_unary float2rad x;\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure 0 0 in.width in.height \n\t\t\t\t\t(to_real pacross) (to_real pdown) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.28/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 1.5;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 50;\n\t\t\tfs = Scale \"Sharpen flat areas by\" (-2) 5 1;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" (-2) 5 2;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tlayers = Scale \"Layers\" 1 100 10;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\", \"Approximate\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf, aconvsep layers]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\t\t\trotate = Option \"Rotate\" [\n\t\t\t\t\"Don't rotate\", \n\t\t\t\t\"4 x 45 degrees\", \n\t\t\t\t\"8 x 45 degrees\", \n\t\t\t\t\"2 x 90 degrees\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_lindetect, !separable && type == 0 && rotate == 1\n\t\t\t\t\t\t= im_compass, !separable && type == 0 && rotate == 2\n\t\t\t\t\t\t= im_gradient, !separable && type == 0 && rotate == 3\n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_conv_f, !separable && type == 1\n\t\t\t\t\t\t= im_convsep_f, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 4) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width.expr window_height.expr in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\nFilter_greyc_item = class \n\tMenupullright \"_GREYCstoration\" \"noise-removing filter\" {\n\tDenoise_item = class \n\t\tMenuaction \"Denoise\" \"Noise-removing filter\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\titerations = Scale \"Iterations\" 1 5 1;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 40;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.9;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.15;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.6;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.1;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) x;\n\t\t}\n\t}\n\n\tEnlarge_item = class\n\t\tMenuaction \"Enlarge\" \"Enlarge image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Enlarge\" 1 10 3;\n\t\t\titerations = Scale \"Iterations\" 1 5 3;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 20;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.2;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.9;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.1;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.5;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) \n\t\t\t\t\t(resize Interpolate_bilinear\n\t\t\t\t\t\t(to_real scale) (to_real scale) x);\n\t\t}\n\t}\n}\n\nFilter_magick_item = class\n\tMenupullright \"Magic_k\" \"various Image/Graphics Magick filters\" {\n\tsystem command x = map_unary (system_image command) x;\n\tradius_widget = Scale \"Radius\" 1 100 10;\n\tsigma_widget = Scale \"Sigma\" 0.1 10 1;\n\tangle_widget = Scale \"Angle\" (-360) 360 0;\n\ttext_widget = String \"Text to draw\" \"AaBbCcDdEe\";\n\n\tprint_colour triple\n\t\t= concat [\"\\\"#\", concat (map fmt triple), \"\\\"\"]\n\t{\n\t\tfmt x = reverse (take 2 (reverse (print_base 16 (x + 256))));\n\t}\n\n\tForeground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-fill \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Foreground triple;\n\t}\n\tforeground_widget = Foreground [0, 0, 0];\n\n\tBackground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-background \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Background triple;\n\t}\n\tbackground_widget = Background [255, 255, 255];\n\n\tAntialias value = class\n\t\tToggle \"Antialias\" value {\n\n\t\t_flag\n\t\t\t= \"-antialias\", value\n\t\t\t= \"+antialias\";\n\n\t\tToggle_edit caption value = this.Antialias value;\n\t}\n\tantialias_widget = Antialias true;\n\n\tGravity gravity = class\n\t\tOption_string \"Gravity\" [\n\t\t\t\"None\",\n\t\t\t\"Center\",\n\t\t\t\"East\",\n\t\t\t\"Forget\",\n\t\t\t\"NorthEast\",\n\t\t\t\"North\",\n\t\t\t\"NorthWest\",\n\t\t\t\"SouthEast\",\n\t\t\t\"South\",\n\t\t\t\"SouthWest\",\n\t\t\t\"West\",\n\t\t\t\"Static\"\n\t\t] gravity {\n\n\t\t_flag = \"-gravity \" ++ gravity;\n\n\t\tOption_edit caption labels value = this.Gravity labels?value;\n\t}\n\tgravity_widget = Gravity \"Center\";\n\n\tAlpha alpha = class\n\t\tOption_string \"Alpha\" [\n\t\t\t\"On\", \n\t\t\t\"Off\", \n\t\t\t\"Set\", \n\t\t\t\"Opaque\", \n\t\t\t\"Transparent\", \n\t\t\t\"Extract\", \n\t\t\t\"Copy\", \n\t\t\t\"Shape\", \n\t\t\t\"Background\"\n\t\t] alpha {\n\n\t\t_flag = \"-alpha \" ++ alpha;\n\n\t\tOption_edit caption labels value = this.Alpha labels?value;\n\t}\n\talpha_widget = Alpha \"On\";\n\n\tGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Y\" 0;\n\t\ty = Expression \"X\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 10;\n\t\tvoffset = Expression \"Vertical offset\" 10;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFont_widget = class {\n\t\t_vislevel = 3;\n\n\t\tfamily = Option_string \"Family\" [\n\t\t\t\"Arial\",\n\t\t\t\"ArialBlack\",\n\t\t\t\"AvantGarde\",\n\t\t\t\"BitstreamCharter\",\n\t\t\t\"Bookman\",\n\t\t\t\"CenturySchoolbook\",\n\t\t\t\"ComicSansMS\",\n\t\t\t\"Courier\",\n\t\t\t\"CourierNew\",\n\t\t\t\"DejaVuSans\",\n\t\t\t\"DejaVuSansMono\",\n\t\t\t\"DejaVuSerif\",\n\t\t\t\"Dingbats\",\n\t\t\t\"FreeMono\",\n\t\t\t\"FreeSans\",\n\t\t\t\"FreeSerif\",\n\t\t\t\"Garuda\",\n\t\t\t\"Georgia\",\n\t\t\t\"Helvetica\",\n\t\t\t\"HelveticaNarrow\",\n\t\t\t\"Impact\",\n\t\t\t\"LiberationMono\",\n\t\t\t\"LiberationSans\",\n\t\t\t\"LiberationSerif\",\n\t\t\t\"NewCenturySchlbk\",\n\t\t\t\"Palatino\",\n\t\t\t\"Purisa\",\n\t\t\t\"Symbol\",\n\t\t\t\"Times\",\n\t\t\t\"TimesNewRoman\",\n\t\t\t\"Ubuntu\",\n\t\t\t\"Verdana\",\n\t\t\t\"Webdings\"\n\t\t] \"Arial\";\n\t\tstyle = Option_string \"Style\" [\n\t\t\t\"Any\", \"Italic\", \"Normal\", \"Oblique\"\n\t\t] \"Normal\";\n\t\tweight = Scale \"Weight\" 1 800 400;\n\t\tsize = Scale \"Point size\" 1 100 12;\n\t\tstretch = Option_string \"Stretch\" [\n\t\t\t\"Any\", \"Condensed\", \"Expanded\", \"ExtraCondensed\", \"ExtraExpanded\", \n\t\t\t\"Normal\", \"SemiCondensed\", \"SemiExpanded\", \"UltraCondensed\", \n\t\t\t\"UltraExpanded\"\n\t\t] \"Normal\";\n\n\t\t_flag = join_sep \" \" [\n\t\t\t\t\"-family\", family.item,\n\t\t\t\t\"-weight\", print weight.value,\n\t\t\t\t\"-pointsize\", print size.value,\n\t\t\t\t\"-style\", style.item,\n\t\t\t\t\"-stretch\", stretch.item];\n\t}\n\n\tAdaptive_blur_item = class\n\t\tMenuaction \"_Adaptive Blur\" \"blur less near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = radius_widget; \n\t\t\tsigma = sigma_widget;\n\t\t\tcommand = magick_command (concat [\"-adaptive-blur \",\n\t\t\t\tprint radius.value, \"x\", print sigma.value]);\n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n\n\tAdaptive_sharpen_item = class\n\t\tMenuaction \"_Adaptive Sharpen\" \"sharpen more near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = radius_widget; \n\t\t\tsigma = sigma_widget;\n\t\t\tcommand = magick_command (concat [\"-adaptive-sharpen \",\n\t\t\t\tprint radius.value, \"x\", print sigma.value]);\n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n\n\tAlpha_item = class\n\t\tMenuaction \"_Alpha\" \"add/remove alpha channel\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\talpha = alpha_widget; \n\t\t\tcommand = magick_command alpha._flag; \n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n\n\tAnnotate_item = class\n\t\tMenuaction \"_Annotate\" \"add text annotation\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = text_widget;\n\t\t\tfont = Font_widget;\n\t\t\tgeometry = Geometry_widget; \n\t\t\tgravity = gravity_widget; \n\t\t\tforeground = foreground_widget;\n\t\t\tantialias = antialias_widget;\n\t\t\tcommand = magick_command (join_sep \" \" [\n\t\t\t\tfont._flag,\n\t\t\t\tantialias._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tforeground._flag,\n\t\t\t\t\"-annotate\", geometry._flag, \"\\\"\" ++ text.value ++ \"\\\"\"]);\n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n\n\tSwirl_item = class\n\t\tMenuaction \"_Swirl\" \"swirl around the centre\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tangle = angle_widget;\n\t\t\tcommand = magick_command (\"-swirl \" ++ print angle.value);\n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image\" \"use an image to blend two objects\" {\n\t\taction a b c = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ti = Toggle \"Invert mask\" false;\n\n\t\t\t_result \n\t\t\t\t= map_trinary process a b c\n\t\t\t{\n\t\t\t\tprocess a b c \n\t\t\t\t\t= blend condition in1 in2, !i\n\t\t\t\t\t= blend (invert condition) in1 in2\n\t\t\t\t{\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t\t= false,\n\t\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t\t= true;\n\t\t\t\t\t[condition, in1, in2] = sortc compare [a, b, c];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"_Alpha\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t_ \"Normal\" => NORMAL,\n\t\t\t_ \"If Lighter\" => IFLIGHTER,\n\t\t\t_ \"If Darker\" => IFDARKER,\n\t\t\t_ \"Multiply\" => MULTIPLY,\n\t\t\t_ \"Add\" => ADD,\n\t\t\t_ \"Subtract\" => SUBTRACT,\n\t\t\t_ \"Screen\" => SCREEN,\n\t\t\t_ \"Burn\" => BURN,\n\t\t\t_ \"Soft Light\" => SOFTLIGHT,\n\t\t\t_ \"Hard Light\" => HARDLIGHT,\n\t\t\t_ \"Lighten\" => LIGHTEN,\n\t\t\t_ \"Darken\" => DARKEN,\n\t\t\t_ \"Dodge\" => DODGE,\n\t\t\t_ \"Reflect\" => REFLECT,\n\t\t\t_ \"Freeze\" => FREEZE,\n\t\t\t_ \"Bitwise OR\" => OR,\n\t\t\t_ \"Bitwise AND\" => AND\n\t\t];\n\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum \"Blend mode\" names \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\t[mono, colour] = \n\t\t\t\t\tsortc (const (is_colour_type @ get_type)) [a, b];\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t_ \"Grey\",\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t_ \"North-west\",\n\t\t\t\t_ \"North\",\n\t\t\t\t_ \"North-east\",\n\t\t\t\t_ \"West\",\n\t\t\t\t_ \"Centre\",\n\t\t\t\t_ \"East\",\n\t\t\t\t_ \"South-west\",\n\t\t\t\t_ \"South\",\n\t\t\t\t_ \"South-east\",\n\t\t\t\t_ \"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.28/Histogram.def",
    "content": "Hist_new_item = class\n\tMenupullright \"_New\" \"new histogram\" {\n\tHist_item = class\n\t\tMenuaction \"Histogram\" \"make an identity histogram\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\t_result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d);\n\t\t}\n\t}\n\n\tHist_new_from_matrix = Matrix_buildlut_item; \n\n\tHist_from_image_item = class\n\t\tMenuaction \"Ta_g Image As Histogram\" \"set image Type to Histogram\" {\n\t\taction x = hist_tag x;\n\t}\n\n\tTone_item = class \n\t\tMenuaction \"_Tone Curve\" \"make a new tone mapping curve\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\t_result \n\t\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t\t{\n\t\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_convert_to_hist_item = class \n\tMenuaction \"Con_vert to Histogram\" \"convert anything to a histogram\" {\n\taction x = hist_tag (to_image x);\n}\n\nHist_find_item = class \n\tMenupullright \"_Find\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n\n\tIndexed_item = class\n\t\tMenuaction \"_Indexed\" \n\t\t\t\"use a 1-band index image to pick bins for an n-band image\" {\n\t\taction x y \n\t\t\t= map_binary map x y\n\t\t{\n\t\t\tmap a b\n\t\t\t\t= hist_find_indexed index im\n\t\t\t{\n\t\t\t\t[im, index] = sortc (const is_index) [a, b];\n\n\t\t\t\tis_index x\n\t\t\t\t\t= has_image x && b == 1 && \n\t\t\t\t\t\t(f == Image_format.UCHAR || f == Image_format.USHORT)\n\t\t\t\t{\n\t\t\t\t\tim = get_image x;\n\t\t\t\t\tb = get_bands x;\n\t\t\t\t\tf = get_format x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\t[im, hist] = sortc (const is_hist) [a, b];\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Integrate\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate\" \n\t\t\"find point-to-point differences (inverse of Integrate)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\tarea = extract_arrow \n\t\t\t\t\tdisplace.value vdisplace.value width.value arrow;\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize Interpolate_bilinear 1 (1 / width.value) area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary (extract_arrow \n\t\t\t\tdisplace.value vdisplace.value width.value) x;\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tformat = Option_enum \"Format\" Plot_format.names \"YYYY\";\n\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => style.value, $format => format.value] ++ range;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow 0 0 1 x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.28/Image.def",
    "content": "Image_new_item = class Menupullright \"_New\" \"make new things\" {\n\tImage_black_item = class Menuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \"Image type\"\n\t\t\t\tImage_type.type_names \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region on image using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\t[target, x] = sortc compare [a, b];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\nImage_number_format_item = class\n\tMenupullright \"_Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_header_item = class \n\tMenupullright \"_Header\" \"do stuff to the image header\" {\n\n\tImage_get_item = class\n\t\tMenupullright \"_Get\" \"get header fields\" {\n\n\t\t// the header fields we can get\n\t\tfields = class {\n\t\t\ttype = 0;\n\t\t\twidth = 1;\n\t\t\theight = 2;\n\t\t\tformat = 3;\n\t\t\tbands = 4;\n\t\t\txres = 5;\n\t\t\tyres = 6;\n\t\t\txoffset = 7;\n\t\t\tyoffset = 8;\n\t\t\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t$width => width,\n\t\t\t\t$height => height,\n\t\t\t\t$bands => bands,\n\t\t\t\t$format => format,\n\t\t\t\t$type => type,\n\t\t\t\t$xres => xres,\n\t\t\t\t$yres => yres,\n\t\t\t\t$xoffset => xoffset,\n\t\t\t\t$yoffset => yoffset,\n\t\t\t\t$coding => coding\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum (_ \"Field\") field_names name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tCustom_item = class\n\t\t\tMenuaction \"C_ustom\" \"get any header field\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tfield = String \"Field\" \"Xsize\";\n\t\t\t\tparse = Option \"Parse\" [\n\t\t\t\t\t\"No parsing\",\n\t\t\t\t\t\"Parse string as integer\",\n\t\t\t\t\t\"Parse string as real\",\n\t\t\t\t\t\"Parse string as hh:mm:ss\"\n\t\t\t\t] 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary (wrap @ process @ get_header field.value) x\n\t\t\t\t{\n\t\t\t\t\tparse_str parse str = parse (split is_space str)?0;\n\n\t\t\t\t\tparse_field name cast parse x\n\t\t\t\t\t\t= cast x, is_number x\n\t\t\t\t\t\t= parse_str parse x, is_string x\n\t\t\t\t\t\t= error (\"not \" ++ name);\n\n\t\t\t\t\tget_int = parse_field \"int\" \n\t\t\t\t\t\tcast_signed_int parse_int;\n\t\t\t\t\tget_float = parse_field \"float\" \n\t\t\t\t\t\tcast_float parse_float;\n\t\t\t\t\tget_time = parse_field \"hh:mm:ss\" \n\t\t\t\t\t\tcast_signed_int parse_time;\n\n\t\t\t\t\twrap x\n\t\t\t\t\t\t= Real x, is_real x\n\t\t\t\t\t\t= Vector x, is_real_list x\n\t\t\t\t\t\t= Image x, is_image x\n\t\t\t\t\t\t= Bool x, is_bool x\n\t\t\t\t\t\t= Matrix x, is_matrix x\n\t\t\t\t\t\t= String \"String\" x, is_string x\n\t\t\t\t\t\t= List x, is_list x\n\t\t\t\t\t\t= x;\n\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tget_int, \n\t\t\t\t\t\tget_float,\n\t\t\t\t\t\tget_time\n\t\t\t\t\t]?parse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum \"Image type\" Image_type.type_names \n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_cache_item = class\n\tMenuaction \"C_ache\" \"cache calculated image pixels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttile_width = Number \"Tile width\" 128;\n\t\ttile_height = Number \"Tile height\" 128;\n\t\tmax_tiles = Number \"Maximum number of tiles to cache\" (-1);\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= cache (to_real tile_width) (to_real tile_height) \n\t\t\t\t\t(to_real max_tiles) image;\n\t\t}\n\t}\n}\n\n#separator\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in = [\n\t\t\t\t\t\tin, \n\t\t\t\t\t\trot90 in,\n\t\t\t\t\t\trot180 in,\n\t\t\t\t\t\trot270 in\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate interp angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary straighten x\n\t\t\t\t{\n\t\t\t\t\tstraighten arrow\n\t\t\t\t\t\t= rotate interp angle'' arrow.image\n\t\t\t\t\t{\n\t\t\t\t\t\tx = arrow.width;\n\t\t\t\t\t\ty = arrow.height;\n\t\t\n\t\t\t\t\t\tangle = im (polar (x, y));\n\t\t\n\t\t\t\t\t\tangle'\n\t\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t\t= angle;\n\t\t\n\t\t\t\t\t\tangle''\n\t\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize interp xfactor yfactor image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\taspect = Toggle \"Break aspect ratio\" false;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize interp h v image, aspect\n\t\t\t\t\t\t= resize interp fac fac image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac > yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\tmin_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac < yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\t[h, v] = [\n\t\t\t\t\t\t\tmax_factor, \n\t\t\t\t\t\t\tmin_factor, \n\t\t\t\t\t\t\t[xfac, 1], \n\t\t\t\t\t\t\t[1, yfac]]?which;\n\n\t\t\t\t\t\tfac \n\t\t\t\t\t\t\t= h, v == 1\n\t\t\t\t\t\t\t= v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_within_item = class\n\t\t\tMenuaction \"Size _Within\" \"size to fit within a rectangle\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\t// the rects we size to fit within\n\t\t\t\t_rects = [\n\t\t\t\t\t[2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], \n\t\t\t\t\t[1280, 1024], [1024, 768], [800, 600], [640, 480] \n\t\t\t\t];\n\n\t\t\t\twithin = Option \"Fit within (pixels)\" (\n\t\t\t\t\t[print w ++ \" x \" ++ print h :: [w, h] <- _rects] ++\n\t\t\t\t\t[\"Custom\"]\n\t\t\t\t) 4;\n\t\t\t\tcustom_width = Expression \"Custom width\" 1000;\n\t\t\t\tcustom_height = Expression \"Custom height\" 1000;\n\t\t\t    size = Option \"Page size\" [\n\t\t\t\t\t\"Full page\", \"Half page\", \"Quarter page\" \n\t\t\t\t] 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t \t_result\n\t\t\t\t \t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\txdiv = [1, 2, 2]?size;\n\t\t\t\t\tydiv = [1, 1, 2]?size;\n\t\t\t\t\tallrect = _rects ++ [\n\t\t\t\t\t\t[custom_width.expr, custom_height.expr]\n\t\t\t\t\t];\n\t\t\t\t\t[width, height] = allrect?within;\n\n\t\t\t\t\tprocess x\n\t\t\t\t\t\t= resize interp fac fac x, fac < 1\n\t\t\t\t\t\t= x\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = (width / xdiv) / x.width;\n\t\t\t\t\t\tyfac = (height / ydiv) / x.height;\n\t\t\t\t\t\tfac = min_pair xfac yfac;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\" [\"Nearest\", \"Bilinear\"] 1;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_trn {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t[sample', trn, err] = transform_search \n\t\t\t\t\tmax_err max_iter order interp wrap\n\t\t\t\t\tsample reference;\n\t\t\t\ttransformed_image = Image sample';\n\t\t\t\t_trn = Transform trn reference.width reference.height;\n\t\t\t\tfinal_error = err;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\t[i, t] = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tBandwise_item = Image_join_item.Bandwise_item;\n\n    sep1 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldl1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find the image geometry ... don't bother trying to look\n\t\t// inside groups though\n\t\t_geo\n\t\t\t= x.rect, is_Image x\n\t\t\t= Rect 0 0 100 100;\n\n\t\tl = Expression \"Crop left\" ((int) (_geo.left + _geo.width / 4));\n\t\tt = Expression \"Crop top\" ((int) (_geo.top + _geo.height / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (_geo.width / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (_geo.height / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t[_a', _b'] = sortc _pred [a, b];\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_draw_item = class \n\tMenupullright \"_Draw\" \"draw lines, circles, rectangles, floods\" {\n\tLine_item = class Menuaction \"_Line\" \"draw line on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tx1 = Expression \"Start x\" 0;\n\t\t\ty1 = Expression \"Start y\" 0;\n\t\t\tx2 = Expression \"End x\" 100;\n\t\t\ty2 = Expression \"End y\" 100;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary line x\n\t\t\t{\n\t\t\t\tline im \n\t\t\t\t\t= draw_line x1 y1 x2 y2 i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tRect_item = class Menuaction \"_Rectangle\" \"draw rectangle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\trx = Expression \"Left\" 50;\n\t\t\try = Expression \"Top\" 50;\n\t\t\trw = Expression \"Width\" 100;\n\t\t\trh = Expression \"Height\" 100;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\tt = Scale \"Line thickness\" 1 50 3;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary rect x\n\t\t\t{\n\t\t\t\trect im \n\t\t\t\t\t= draw_rect_width rx ry rw rh f t i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class Menuaction \"_Circle\" \"draw circle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcx = Expression \"Centre x\" 100;\n\t\t\tcy = Expression \"Centre y\" 100;\n\t\t\tr = Expression \"Radius\" 50;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary circle x\n\t\t\t{\n\t\t\t\tcircle im \n\t\t\t\t\t= draw_circle cx cy r f i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tFlood_item = class Menuaction \"_Flood\" \"flood bounded area of image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsx = Expression \"Start x\" 100;\n\t\t\tsy = Expression \"Start y\" 100;\n\n\t\t\te = Option \"Flood while\" [\n\t\t\t\t\"Not equal to ink\",\n\t\t\t\t\"Equal to start point\"\n\t\t\t] 0;\n\n\t\t\t// pick a default ink that won't flood, if we can\n\t\t\ti \n\t\t\t\t= Expression \"Ink\" default_ink\n\t\t\t{\n\t\t\t\tdefault_ink\n\t\t\t\t\t= [0], ! has_image x\n\t\t\t\t\t= pixel;\n\t\t\t\tpixel = map mean (bandsplit (extract_area sx sy 1 1 im));\n\t\t\t\tim = get_image x;\n\t\t\t}\n\n\t\t\t_result \n\t\t\t\t= map_unary flood x\n\t\t\t{\n\t\t\t\tflood im \n\t\t\t\t\t= draw_flood sx sy i.expr im, e == 0\n\t\t\t\t\t= draw_flood_blob sx sy i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tDraw_scalebar_item = class Menuaction \"_Scale\" \"draw scale bar\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpx = Expression \"Left\" 50;\n\t\t\tpy = Expression \"Top\" 50;\n\t\t\twid = Expression \"Width\" 100;\n\t\t\tthick = Scale \"Line thickness\" 1 50 3;\n\t\t\ttext = String \"Dimension text\" \"50μm\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\tpos = Option \"Position Text\" [\"Above\", \"Below\"] 1;\n\t\t\tvp = Option \"Dimension by\" [\n\t\t\t\t\"Inner Vertical Edge\", \n\t\t\t\t\"Centre of Vertical\", \n\t\t\t\t\"Outer Vertical Edge\"\n\t\t\t] 1;\n            dpi = Expression \"DPI\" 100;\n            ink = Colour \"Lab\" [50,0,0];\n      \n            _result\n                = map_unary process x\n            {\n                process im\n                    = blend (Image scale) ink' im\n                {\n                    // make an ink compatible with the image\n                    ink' = colour_transform_to (get_type im) ink;\n\n                    x = to_real px;\n                    y = to_real py;\n                    w = to_real wid;\n                    d = to_real dpi;\n\n                    t = floor thick;\n\n                    bg = image_new (get_width im) (get_height im) (get_bands im)\n                        (get_format im) (get_coding im) (get_type im) 0 0 0;\n                    draw_block x y w t im =\n                        draw_rect_width x y w t true 1 [255] im;\n                    label = im_text text.value font.value w 1 d;\n                    lw = get_width label;\n                    lh = get_height label;\n                    ly = [y - lh - t, y + 2 * t]?pos;\n                    vx = [\n\t\t\t\t\t\t[x - t, x + w],\n\t\t\t\t\t\t[x - t / 2, x + w - t / 2],\n\t\t\t\t\t\t[x, x + w - t]\n\t\t\t\t\t]?vp;\n\n\t\t\t\t\tscale = (draw_block x y w t @\n\t\t\t\t\t\tdraw_block vx?0 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tdraw_block vx?1 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tinsert_noexpand (x + w / 2 - lw / 2) ly label)\n\t\t\t\t\t\tbg;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t// we can't use map_unary since chop-into-tiles returns a group of\n\t\t\t// groups and we want to be able to reassemble that\n\t\t\t// TODO: chop-into-tiles should return an array class which\n\t\t\t// displays as group but does not have the looping behaviour?\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n\n\tArrayFL_item = class\n\t\tMenuaction \"_Array from List\"\n\t\t\t\"join a list of images into a single image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tncol = Number \"Max. Number of Columns\" 1;\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t_l \n\t\t\t\t= split_lines ncol.value x.value, is_Group x\n\t\t\t\t= split_lines ncol.value x;\n\n\t\t\t_result\n\t\t\t\t= (image_set_origin 0 0 @\n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value\n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list _l));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tGaussian_item = class \n\t\tMenuaction \"Gaussian _Noise\" \"make an image of gaussian noise\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t_result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) \n\t\t\t\tmean.value deviation.value);\n\t\t}\n\t}\n\n\tFractal_item = class \n\t\tMenuaction \"_Fractal\" \"make a fractal image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t}\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n\tColour_atlas_item = class\n\tMenuaction \"_Colour Atlas\"\n\t\t\"make a grid of patches grouped around a colour\" {\n\t\taction = class \n\t\t\t_result {   \n\t\t\t_vislevel = 3;\n       \n\t\t\tstart = Colour_picker \"Lab\" [50,0,0];\n\t\t\tnstep = Expression \"Number of steps\" 9;\n\t\t\tssize = Expression \"Step size\" 10; \n\t\t\tpsize = Expression \"Patch size\" 32;\n\t\t\tsepsize = Expression \"Separator size\" 4;\n\t\n\t\t\t_result\n\t\t\t\t= colour_transform_to (get_type start) blocks'''\n\t\t\t{\n\t\t\t\tsize = (to_real nstep * 2 + 1) * to_real psize - \n\t\t\t\t\tto_real sepsize;\n\t\t\t\txy = make_xy size size; \n\n\t\t\t\txy_grid = (xy % to_real psize) < \n\t\t\t\t\t(to_real psize - to_real sepsize);\n\t\t\t\tgrid = xy_grid?0 & xy_grid?1;\n\n\t\t\t\tblocks = (int) (to_real ssize * ((int) (xy / to_real psize)));\n\t\t\t\tlab_start = colour_transform_to Image_type.LAB start;\n\t\t\t\tblocks' = blocks - to_real nstep * to_real ssize + \n\t\t\t\t\tVector (tl lab_start.value);\n\t\t\t\tblocks'' = hd lab_start.value ++ Image blocks';\n\t\t\t\tblocks''' \n\t\t\t\t\t= image_set_type Image_type.LAB blocks'', Image grid\n\t\t\t\t\t= 0;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.28/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/7.28\n\nstart_DATA = \\\n\tMath.def \\\n\tImage.def \\\n\tColour.def \\\n\tTasks.def \\\n\tObject.def \\\n\tFilter.def \\\n\tMatrix.def \\\n\tWidgets.def \\\n\tHistogram.def \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_convert.def \\\n\t_generate.def \\\n\t_list.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\t_Object.def \\\n\t_types.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/7.28/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_And\" \"bitwise and of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_Or\" \"bitwise or of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"E_xclusive Or\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_Not\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBand_or_item = class \n\t\tMenuaction \"Band O_r\" \"or the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_or @ bandsplit) im;\n\t}\n\n\tBand_and_item = class \n\t\tMenuaction \"Band A_nd\" \"and the bands of an image together\" {\n\t\taction im = map_unary (foldr1 bitwise_and @ bandsplit) im;\n\t}\n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tDifference_item = class \n\t\tMenuaction \"_Difference\" \"difference of two lists\" {\n\t\taction a b = map_binary difference a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tValue_item = class \n\t\tMenuaction \"_Value\" \"value of point in object\" {\n\t\taction a = class _result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tposition = Expression \"Coordinate\" (0, 0);\n\t\n\t\t\t_result = map_binary point position.expr a;\n\t\t}\n\t}\n\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \n\t\t\t\"position of centre of gravity of histogram\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = linreg xes yes;\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = linregw xes yes devs;\n\t}\n\n\tCluster_item = class \n\t\tMenuaction \"_Cluster\" \"cluster a list of numbers\" {\n\t\taction l = class {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tthresh = Expression \"Threshold\" 10;\n\t\n\t\t\t[_r, _w] = cluster thresh.expr l;\n\t\n\t\t\tresult = _r;\n\t\t\tweights = _w;\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.28/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_identity_item = class \n\t\tMenuaction \"_Identity\" \"make an identity matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" 5;\n\n\t\t\t_result = Matrix (identity_matrix s.expr);\n\t\t}\n\t}\n\n\tMatrix_series_item = class \n\t\tMenuaction \"_Series\" \"make a series\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Start value\" 0;\n\t\t\tt = Expression \"Step by\" 1;\n\t\t\te = Expression \"End value\" 5;\n\n\t\t\t_result \n\t\t\t\t= Matrix (transpose [series])\n\t\t\t{\n\t\t\t\tseries = [to_real s, to_real t..  to_real e];\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_square_item = class \n\t\tMenuaction \"_Square\" \"make a square matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" 5;\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (s.expr ** 2) 0 square\n\t\t\t{\n\t\t\t\tline = take s.expr [1, 1 ..];\n\t\t\t\tsquare = replicate s.expr line;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_circular_item = class \n\t\tMenuaction \"_Circular\" \"make a circular matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tr = Expression \"Radius\" 5;\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum circle) 0 circle\n\t\t\t{\n\t\t\t\tline = [-r.expr .. r.expr];\n\t\t\t\txes = replicate (2 * r.expr + 1) line;\n\t\t\t\tyes = transpose xes;\n\t\t\t\tcircle = map2 (map2 pyth) xes yes\n\t\t\t\t{\n\t\t\t\t\tpyth a b \n\t\t\t\t\t\t= 1, (a**2 + b**2) ** 0.5 <= r.expr\n\t\t\t\t\t\t= 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\nMatrix_sort_item = class \n\tMenuaction \"_Sort\" \"sort by column or row\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\to = Option (_ \"Orientation\") [\n\t\t\t_ \"Sort by column\",\n\t\t\t_ \"Sort by row\"\n\t\t] 0;\n\t\ti = Expression (_ \"Sort on index\") 0;\n\t\td = Option (_ \"Direction\") [\n\t\t\t_ \"Ascending\",\n\t\t\t_ \"Descending\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary sort x\n\t\t{\n\t\t\tidx = to_real i;\n\t\t\tpred a b \n\t\t\t\t= a?idx <= b?idx, d == 0\n\t\t\t\t= a?idx >= b?idx;\n\t\t\tsort x\n\t\t\t\t= (x.Matrix_base @ sortc pred) x.value,\n\t\t\t\t\to == 0\n\t\t\t\t= (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value;\n\t\t}\n\t}\n}\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ \n\t\t\t\t\trange;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.28/Object.def",
    "content": "Object_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nObject_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nObject_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nObject_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nObject_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list (or group) of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.28/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\n\tCsv_import_item = class\n\t\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tstart_line = Expression \"Start at line\" 1;\n\t\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_csv2vips filename)\n\t\t\t{\n\t\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\t\tescape x \n\t\t\t\t\t= foldr prefix [] x\n\t\t\t\t{\n\t\t\t\t\tprefix x l\n\t\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t\t= x : l;\n\t\t\t\t}\n\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tRaw_import_item = class\n\t\tMenuaction \"_Raw Import\" \"read a file of binary values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tacross = Expression \"Pixels across\" 100;\n\t\t\tdown = Expression \"Pixels down\" 100;\n\t\t\tbytes = Expression \"Bytes per pixel\" 3;\n\t\t\tskip = Expression \"Skip over initial bytes\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_binfile path.value \n\t\t\t\t\tacross.expr down.expr bytes.expr skip.expr)\n\t\t\t{\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// interpret Analyze header for layout and calibration\n\tAnalyze7_header_item = class\n\t\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\t\"examine the Analyze header and set layout and value\" {\n\t\taction x \n\t\t\t= x'''\n\t\t{\n\t\t\t// read bits of header\n\t\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\t\tdim0 = dim 0 x;\n\t\t\tdim1 = dim 1 x;\n\t\t\tdim2 = dim 2 x;\n\t\t\tdim3 = dim 3 x;\n\t\t\tdim4 = dim 4 x;\n\t\t\tdim5 = dim 5 x;\n\t\t\tdim6 = dim 6 x;\n\t\t\tdim7 = dim 7 x;\n\t\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\t\n\t\t\t// oops, now a nop\n\t\t\tx' = x;\n\t\n\t\t\t// lay out higher dimensions width-ways\n\t\t\tx'' \n\t\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\t\tdim0 == 7\n\t\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\t\n\t\t\t// multiply by scale factor to get kBeq\n\t\t\tx''' = x'' * (cal_max / glmax);\n\t\t}\n\t}\n\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\t[image, patch] = sortc larger [a, b];\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\tmode = Option \"Input LUT\" [\n\t\t\t\t\"Linear input\",\n\t\t\t\t\"Fit intercept from chart greyscale\",\n\t\t\t\t\"Linearize input from chart greyscale\"\n\t\t\t] 2;\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = measure 0 0 image.width image.height 6 4 image.value;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb \n\t\t\t\t= Matrix [[0, 0], [1, 1]], mode == 0\n\t\t\t\t= Matrix [0: intercepts, replicate (_camera.width + 1) 1], \n\t\t\t\t\tmode == 1\n\t\t\t\t= Matrix (map2 cons _true_grey_Y' _camera_grey')\n\t\t\t{\n\t\t\t\tintercepts = [(linreg _true_grey_Y' cam).intercept :: \n\t\t\t\t\tcam <- transpose _camera_grey'];\n\t\t\t}\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\t// plot from 0 explicitly so we see the effect of mode1 (intercept\n\t\t\t// from greyscale)\n\t\t\tlinearising_lut = Plot [$ymin => 0] _linear_lut;\n\n\t\t\t// map the original image through the lineariser to \n\t\t\t// get linear 0-1 RGB image\n\t\t\t_image' = hist_map linearising_lut.value image.value;\n\n\t\t\t// remeasure and solve for RGB -> XYZ\n\t\t\t_camera' = im_measure _image' 0 0 image.width image.height 6 4;\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\tM = transpose (_pinv * transpose _camera' * _true_XYZ);\n\n\t\t\t// convert linear RGB camera to Lab \n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tcast_float @\n\t\t\t\trecomb M) _image';\n\n\t\t\t// measure again and compute dE76\n\t\t\t_camera'' = im_measure _result.value 0 0 \n\t\t\t\timage.width image.height 6 4;\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tfinal_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0 && i < len macbeth_names\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b = class\n\t\t\t(map_binary process a b) {\n\t\t\tprocess a b\n\t\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t\t{\n\t\t\t\t// the name of the calib object we need\n\t\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t\t// get the Calibrate_chart arg first\n\t\t\t\t[image, calib] = sortc (const (is_instanceof calib_name)) \n\t\t\t\t\t[a, b];\n\n\t\t\t\t// map the original image through the lineariser to get \n\t\t\t\t// linear 0-1 RGB image\n\t\t\t\timage' = hist_map calib.linearising_lut image;\n\n\t\t\t\t// convert linear RGB camera to Lab \n\t\t\t\tresult = colour_transform Image_type.XYZ Image_type.LAB \n\t\t\t\t\t((float) (recomb calib.M image'));\n\t\t\t}\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [$style => style.value] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\t!is_list_len 2 images\n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = all (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize Interpolate_bilinear xfactor yfactor scale_im;\n\t\t\t_offset_im = resize Interpolate_bilinear xfactor yfactor offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.28/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.28/_Object.def",
    "content": "/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0|1|2|3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \n\tjoin_sep \"|\" Image_type.colour_spaces.names];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide|VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad properties for \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"where\" ++ \"\\n\" ++ arg_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make arg type notes\n\targ_types = join_sep \"\\n\" (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"\\n\" ++ _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = join_sep \"\\n\" all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if those fail as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if that fails as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary'_function op a b\n\t= matches1?0, matches1 != []\n\t= matches2?0, op.symmetric && matches2 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0, matches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t// these should always be defined\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x = oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x = oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op = oo_unary_function (oo_unary_lookup op) this;\n\n\too_binary_table op x = [];\n\too_unary_table op = [];\n}\n"
  },
  {
    "path": "share/nip2/compat/7.28/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n// like to_image, but we do 1x1 pixel + x, then embed it up\n// always make an unwrapped image for speed ... this gets used by ifthenelse\n// and stuff like that\n// format can be NULL, meaning set format from x\nto_image_size width height bands format x\n\t= x, is_image x\n\t= x.value, is_Image x\n\t= im''\n{\n\t// we want x to set the target format if we don't have one, so we\n\t// can't use image_new\n\tim = im_black 1 1 bands + x;\n\tim'\n\t\t= clip2fmt format im, format != NULL\n\t\t= im;\n\tim'' = embed 1 0 0 width height im';\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && is_list_len 3 x\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\nto_int x = (int) (to_real x);\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The innermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x && !contains_Group x\n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), !is_list_len 2 parts \n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, !is_list_len 4 parts \n\t= (ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", member \".0123456789\",\n\t\tmember \"eE\", member \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), !is_list_len 5 parts \n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t$D93 => D93_whitepoint,\n\t$D75 => D75_whitepoint,\n\t$D65 => D65_whitepoint,\n\t$D55 => D55_whitepoint,\n\t$D50 => D50_whitepoint,\n\t$A => A_whitepoint,\n\t$B => B_whitepoint,\n\t$C => C_whitepoint,\n\t$E => E_whitepoint,\n\t$D3250 => D3250_whitepoint\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, image_set_type GREY16 @ im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l = join_sep path_separator l;\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 > 1 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n"
  },
  {
    "path": "share/nip2/compat/7.28/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= embed 1 0 0 w h im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black 1 1 (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = im_gauss_imask_sep (radius / 3) 0.2;\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.28/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 1;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" \n\t] 4;\n\n\tcontrol_selection mask im no\n\t\t= [\n\t\t\tif mask then im * 1.2 else im * 1,\n\t\t\tif mask then im * 0.8 else im * 1,\n\t\t\tif mask then 0 else im,\n\t\t\tif mask then 255 else im,\n\t\t\tif mask then im else 0,\n\t\t\tif mask then im else 255,\n\t\t\tmask\n\t\t]?no;\n\n\tRectangle = class\n\t\tMenuaction \"_Rectangle\"\n\t\t\t\"use line/arrow/rect x to define a rectangle\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_rect x;\n\t\t\t\tim = get_image x;\n\t\t\t\tselect_rect x\n\t\t\t\t\t= Image mask\n\t\t\t\t{\n\t\t\t\t\tim = Image (get_image x);\n\t\t\t\t\timc = make_xy im.width im.height;\t\n\t\t\t\t\tmask = imc?0 >= x.nleft & \n\t\t\t\t\t\t\timc?0 < x.nright & \n\t\t\t\t\t\t\timc?1 >= x.ntop & \n\t\t\t\t\t\t\timc?1 < x.nbottom;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = get_image a;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = get_image ((pt_list.value)?0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tSegment_item = class\n\t\tMenuaction \"_Segment\" \"break image into disjoint regions\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsegments\n\t\t\t\t= Expression \"Number of disjoint regions\" \n\t\t\t\t\t(map_unary (get_header \"n-segments\") _result);\n\n\t\t\t_result = map_unary segment x;\n\t\t}\n\t}\n\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize Interpolate_bilinear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize Interpolate_bilinear f1 1 b1\n\t\t\t\t\t{b1 = resize Interpolate_bilinear 1 f2 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/7.28/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = Image (get_image line);\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = Image (get_image (pt_l?0));\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t};\n\nMount_options _ctype _ppcm = class \n  {\n  _vislevel = 3;\n  apply = Toggle \"Apply mount options\" false;\n  ls = Expression \"Lower mount section bigger by (cm)\" 0;\n  mount_colour = Colour _ctype [0, 0, 0];\n  _los = ls.expr * _ppcm;\n  };\n\nFrame_variables comp = class\n  {\n  _vislevel = 3;\n\n  scale_factor = Expression \"scale the size of the frame by\" 1;\n\n  /* These sliders define the fraction of the frames width or height is extracted\n   * to produce each of the particular regions.\n   */\n  corner_section = Scale \"Corner section\" 0.1 1 0.5;\n  edge_section = Scale \"Edge section\" 0.1 1 0.2, comp > 0\n\t\t\t\t  = \"Only required for complex frames\";\n  middle_section = Scale \"Middle section\" 0.1 1 0.2;\n  blend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n  option = Toggle \"Use mirror of left-side to make right\" true;\n  };\n\n"
  },
  {
    "path": "share/nip2/compat/7.28/_list.def",
    "content": "/* any l: or all the elements of list l together\n *\n * any (map (equal 0) list) == true, if any element of list is zero.\n * any :: [bool] -> bool\n */\nany = foldr logical_or false;\n\n/* all l: and all the elements of list l together\n *\n * all (map (==0) list) == true, if every element of list is zero.\n * all :: [bool] -> bool\n */\nall = foldr logical_and true;\n\n/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* delete eq x l: delete the first x from l\n *\n * delete equal 'b' \"abcdb\" == \"acdb\"\n * delete :: (* -> bool) -> * -> [*] -> [*]\n */\ndelete eq a l\n\t= [], l == []\n\t= y, eq a b\n\t= b : delete eq a y\n{\n\tb:y = l;\n}\n\n/* difference eq a b: delete b from a\n *\n * difference equal \"asdf\" \"ad\" == \"sf\"\n * difference :: (* -> bool) -> [*] -> [*] -> [*]\n */\ndifference = foldl @ converse @ delete;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn x, fn a\n\t= l\n{\n\ta:x = l;\n}\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st (hd l)) (tl l);\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn (hd l) (tl l);\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn (hd l) (foldr fn st (tl l));\n\n/* foldrl fn l: like foldr, but use the 1st element as the start value\n *\n * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= foldr fn (hd l) (tl l);\n\n/* Search a list for an element, returning its index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn (hd l)\n\t\t= search (tl l) (n + 1);\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= hd l : init (tl l);\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* join_sep sep l: join a list with a separator\n *\n * join_sep \", \" (map print [1 .. 4]) == \"1, 2, 3, 4\"\n * join_sep :: [*] -> [[*]] -> [*]\n */\njoin_sep sep l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ sep ++ b;\n}\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= hd l, tl l == []\n\t= last (tl l);\n\n/* len l: length of list l\n * (see also is_list_len and friends in predicate.def)\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta:b:x = l;\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = any (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge p l r\n\t= [], p == [] || l == [] || r == []\n\t= a : merge z x y, c\n\t= b : merge z x y\n{\n\ta:x = l;\n\tb:y = r;\n\tc:z = p;\n}\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta:x = l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scan fn st l: apply (fold fn r) to every initial segment of a list\n *\n * scan add 0 [1,2,3] == [1,3,6]\n * scan :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscan fn \n\t= g \n{\n\tg st l\n\t\t= [st], l == []\n\t\t= st : g (fn st a) x\n\t{\n\t\ta:x = l;\n\t}\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta:x = l1;\n\t\tb:y = l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/7.28/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = any (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && all (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* Test list length ... quicker than len x == n for large lists.\n */\nis_list_len n x\n\t= true, x == [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len (n - 1) (tl x);\n\nis_list_len_more n x\n\t= true, x != [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len_more (n - 1) (tl x);\n\nis_list_len_more_equal n x\n\t= true, n == 0\n\t= false, x == [] \n\t= is_list_len_more_equal (n - 1) (tl x);\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, all (map is_obj l)\n\t= true, all (map is_list l) &&\n\t\tall (map (not @ is_obj) l) &&\n\t\tall (map is_rectangular l) &&\n\t\tis_list_len_more 0 l &&\n\t\tall (map (is_list_len (len (hd l))) (tl l))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && is_list_len (len (hd l)) l;\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_NULL x = is_instanceof \"NULL\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && all (map xy l)\n{\n\txy l = is_real_list l && is_list_len 2 l;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && any (map is_Group l)\n\t= any (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= error (\"get_type: unable to get type from \" ++ print x)\n{\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\t// can have alpha, hence we let bands be one more than you might think\n\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.GREY16, type == Image_type.GREY16 && is_bands 1\n\t\t= Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && \n\t\t\t(width == 1 || height == 1)\n\t\t= Image_type.B_W, is_bands 1 \n\t\t= Image_type.CMYK, type == Image_type.CMYK && is_bands 4\n\t\t= type, is_colorimetric && is_bands 3\n\t\t= Image_type.sRGB, !is_colorimetric && is_bands 3\n\t\t= Image_type.MULTIBAND, !is_colorimetric && !is_bands 3\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\n\t\t// is bands n, with an optional alpha (ie. can be n + 1 too)\n\t\tis_bands n = bands == n || bands == n + 1;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= error (\"get_format: unable to get format from \" ++ print x);\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= error (\"get_bits: unable to get bits from \" ++ print x);\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= error (\"get_bands: unable to get bands from \" ++ print x);\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= error (\"get_coding: unable to get coding from \" ++ print x);\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= error (\"get_xres: unable to get xres from \" ++ print x);\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= error (\"get_yres: unable to get yres from \" ++ print x);\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= error (\"get_xoffset: unable to get xoffset from \" ++ print x);\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= error (\"get_yoffset: unable to get yoffset from \" ++ print x);\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= error (\"get_image: unable to get image from \" ++ print x);\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= error (\"get_number: unable to get number from \" ++ print x);\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= error (\"get_real: unable to get real from \" ++ print x);\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= error (\"get_width: unable to get width from \" ++ print x);\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= error (\"get_height: unable to get height from \" ++ print x);\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= error (\"get_left: unable to get left from \" ++ print x);\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= error (\"get_top: unable to get top from \" ++ print x);\n\n// like has/get member, but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.28/_stdenv.def",
    "content": "/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\nidivide a b = (int) ((int) a / (int) b);\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\n// 'difference' is defined in _list\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the function we call for \"a -> v\" expressions\nmksvpair s v\n\t= [s, v], is_string s\n\t= error \"not str on lhs of ->\";\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error (\"unimplemented vector operation: \" ++ op_name)\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n// make a name value pair\nmknvpair n v\n\t= [n, v], is_string n\n\t= error \"not [char] on LHS of =>\";\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined, has_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nsum x\n\t= oo_unary_function sum_op x, is_class x\n\t= im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x\n\t= sum_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"sum\")\n{\n\tsum_op = Operator \"sum\" sum Operator_type.COMPOUND false;\n\n\t// add elements in a nested-list thing\n\tsum_list l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nproduct x\n\t= oo_unary_function product_op x, is_class x\n\t= product_list x, is_list x \n\t// (product image) doesn't make much sense :(\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"product\")\n{\n\tproduct_op = Operator \"product\" product Operator_type.COMPOUND false;\n\n\tproduct_list l\n\t\t= foldr prod 1 l\n\t{\n\t\tprod x total\n\t\t\t= total * product x, is_list x\n\t\t\t= total * x;\n\t}\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image_hist x, is_image x && \n\t\t(fmt == Image_format.UCHAR || fmt == Image_format.USHORT)\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tfmt = get_format x;\n\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean, for any image type\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n\n\t// image mean for 8 and 16-bit unsigned images\n\t// we can use a histogram, yay, and save a pass through the image\n\tmeanze_image_hist i\n\t\t= sum / N\n\t{\n\t\t// histogram, knock out zeros\n\t\thist = hist_find i;\n\t\tblack = image_new 1 1 (get_bands hist) \n\t\t\t(get_format hist) (get_coding hist) (get_type hist) 0 0 0;\n\t\thistze = insert 0 0 black hist;\n\n\t\t// matching identity\n\t\tiden\n\t\t\t= im_identity_ushort (get_bands hist) (get_width hist),\n\t\t\t\t(get_width hist) > 256\n\t\t\t= im_identity (get_bands hist);\n\n\t\t// number of non-zero pixels\n\t\tN = mean histze * 256;\n\n\t\t// sum of pixels\n\t\tsum = mean (hist * iden) * 256;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_cache x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (\\row [row?x']) obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\" ++ \": \" ++\n\t\tjoin_sep \", \" (map print [cond, in1, in2]))\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x \n\t\t\t= to_image_size target_width target_height \n\t\t\t\ttarget_bands target_format x;\n\n\t\t[then_image, else_image] = map to_image [then_part, else_part];\n\n\t\tblend_result_image = image_set_type target_type \n\t\t\t(im_blend cond then_image else_image);\n\t}\n}\n\n// do big first: we want to keep big's class, if possible\n// eg. big is a Plot, small is a 1x1 Image\ninsert x y small big\n\t= oo_binary'_function insert_op small big, is_class big\n\t= oo_binary_function insert_op small big, is_class small\n\t= im_insert big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n}\n\nmeasure x y w h u v image\n\t= oo_unary_function measure_op image, is_class image\n\t= im_measure image \n\t\t(to_real x) (to_real y) (to_real w) (to_real h)\n\t\t(to_real u) (to_real v), \n\t\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"measure\")\n{\n\tmeasure_op = Operator \"measure\" \n\t\t(measure x y w h u v) Operator_type.COMPOUND_REWRAP false;\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ninvert x\n\t= oo_unary_function invert_op x, is_class x\n\t= im_invert x, is_image x\n\t= 255 - x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"invert\")\n{\n\tinvert_op = Operator \"invert\" invert Operator_type.COMPOUND false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate interp angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_affinei_all image interp.value a (-b) b a 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\t(rotate interp) Operator_type.COMPOUND_REWRAP false;\n\ta = cos angle;\n\tb = sin angle;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_lr\")\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin_lr Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert (get_width a) 0 b a;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_tb\")\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin_tb Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert 0 (get_height a) b a;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\t// The [[real]] can contain 128 values ... squeeze them out!\n\timage = im_mask2vips (Matrix m2) == 255;\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\" ++ \": \" ++ \n\t\t\"conv (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvf mask image\n\t= oo_unary_function convf_op image, is_class image\n\t= im_conv_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convf\" ++ \": \" ++ \n\t\t\"convf (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconvf_op = Operator \"convf\" \n\t\t(convf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\naconvsep layers mask image \n\t= oo_unary_function aconvsep_op image, is_class image\n\t= im_aconvsep image (to_matrix mask) (to_real layers), is_image image\n\t= error (_ \"bad arguments to \" ++ \"aconvsep\")\n{\n\taconvsep_op = Operator \"aconvsep\" \n\t\t(aconvsep layers mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsep_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\ngreyc iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx x\n\t= oo_unary_function greyc_op x, is_class x\n\t= greyc_im x, is_image x\n\t= error (_ \"bad argument\" ++ \" (\" ++ print x ++ \") to \" ++ \"greyc\")\n{\n\tgreyc_op = Operator \"greyc\" (greyc\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im x = im_greyc x\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\ngreyc_mask iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx mask x\n\t= oo_binary_function greyc_mask_op mask x, is_class mask\n\t= oo_binary'_function greyc_mask_op mask x, is_class x\n\t= greyc_im mask x, is_image mask && is_image x\n\t= error (_ \"bad arguments\" ++ \n\t\t\" (\" ++ print mask ++ \", \" ++ print x ++ \") \" ++\n\t\t\"to \" ++ \"greyc\")\n{\n\tgreyc_mask_op = Operator \"greyc_mask\" (greyc_mask\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im mask x = im_greyc_mask x mask\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_indexed index value\n\t= oo_binary_function hist_find_indexed_op index value, is_class index\n\t= oo_binary'_function hist_find_indexed_op index value, is_class value\n\t= im_hist_indexed index value, is_image index && is_image value\n\t= error (_ \"bad arguments to \" ++ \"hist_find_indexed\")\n{\n\thist_find_indexed_op = Operator \"hist_find_indexed\" \n\t\t(compose (compose Plot_histogram) hist_find_indexed) \n\t\t\tOperator_type.COMPOUND false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h \n\t\t= (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h\n\t{\n\t\t// up the format so it can represent the whole range of\n\t\t// possible values from this mask\n\t\tfmt x\n\t\t\t= Image_format.SHORT, \n\t\t\t\tx == Image_format.UCHAR || x == Image_format.CHAR\n\t\t\t= Image_format.INT, \n\t\t\t\tx == Image_format.USHORT || x == Image_format.SHORT ||\n\t\t\t\tx == Image_format.UINT \n\t\t\t= x;\n\t}\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= lhisteq image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n\n\t// loop over bands, if necessary\n\tlhisteq im\n\t\t= im_lhisteq im (to_real w) (to_real h), get_bands im == 1\n\t\t= (foldl1 join @ map lhisteq @ bandsplit) im;\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nresize interp xfac yfac image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\t// is this interpolation nearest-neighbour?\n\tis_nn x = x.type == Interpolate_type.NEAREST_NEIGHBOUR;\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// upscale by any factor, nearest neighbour \n\t\t// upscale by integer part, then affine to exact size\n\t\t= scale xg?1 yg?1 (im_zoom im xg?0 yg?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// downscale by any factor, nearest neighbour \n\t\t// downscale by integer part, then affine to exact size\n\t\t= scale xs?1 ys?1 (im_subsample im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// upscale by any factor with affine\n\t\t= scale xfac' yfac' im,\n\t\t\txfac' >= 1 && yfac' >= 1 \n\n\t\t// downscale by any factor, bilinear\n\t\t// block shrink by integer factor, then resample to \n\t\t// exact with affine\n\t\t= scale xs?1 ys?1 (im_shrink im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 \n\n\t\t= error (\"resize: unimplemented argument combination:\\n\" ++ \n\t\t\t\"  xfac = \" ++ print xfac' ++ \"\\n\" ++\n\t\t\t\"  yfac = \" ++ print yfac' ++ \"\\n\" ++\n\t\t\t\"  interp = \" ++ print interp ++ \" (\" ++\n\t\t\t\tInterpolate_type.descriptions?interp.type ++ \")\")\n\t{\n\t\t// convert a float scale to integer plus fraction\n\t\t// eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25)\n\t\tbreak f = [floor f, f / floor f];\n\n\t\t// same, but for downsizing ... turn a float scale which is less than\n\t\t// 1 into an int shrink and a float scale\n\n\t\t// complicated: the int shrink may round the size down (eg. imagine\n\t\t// subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide\n\t\t// image, not a 3.666 pixel wide image), so pass in the size of image\n\t\t// we are operating on and adjust for any rounding\n\t\t\n\t\t// so ... x is (eg.) 467, f is (eg. 128/467, about 0.274)\n\t\trbreak x f \n\t\t\t= [int_shrink, float_resample]\n\t\t{\n\t\t\t// the size of image we are aiming for after the combined int and\n\t\t\t// float resample\n\t\t\tx' = x * f;\n\n\t\t\t// int part\n\t\t\tint_shrink = floor (1 / f);\n\n\t\t\t// size after int shrink\n\t\t\tx'' = floor (x / int_shrink);\n\n\t\t\t// therefore what we need for the float part\n\t\t\tfloat_resample = x' / x'';\n\t\t}\n\n\t\twidth = get_width im;\n\t\theight = get_height im;\n\n\t\t// grow and shrink factors\n\t\txg = break xfac';\n\t\tyg = break yfac';\n\t\txs = rbreak width xfac';\n\t\tys = rbreak height yfac';\n\n\t\t// resize\n\t\tscale xfac yfac im\n\t\t\t= im_affinei_all im interp.value xfac 0 0 yfac 0 0;\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\n\n// Given a xywh rect, flip it around so wh are always positive\nrect_normalise x y w h \n\t= [x', y', w', h']\n{\n\tx'\n\t\t= x + w, w < 0\n\t\t= x;\n\ty'\n\t\t= y + h, h < 0\n\t\t= y;\n\tw' = abs w;\n\th' = abs h;\n}\n\ndraw_flood_blob x y ink image\n\t= oo_unary_function draw_flood_blob_op image, is_class image\n\t= im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood_blob\")\n{\n\tdraw_flood_blob_op = Operator \"draw_flood_blob\" \n\t\t(draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_flood x y ink image\n\t= oo_unary_function draw_flood_op image, is_class image\n\t= im_draw_flood image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood\")\n{\n\tdraw_flood_op = Operator \"draw_flood\" \n\t\t(draw_flood x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* This version of draw_rect uses insert_noexpand and will be fast, even for\n * huge images.\n */\ndraw_rect_width x y w h f t ink image\n\t= oo_unary_function draw_rect_width_op image, is_class image\n\t= my_draw_rect_width image (to_int x) (to_int y) \n\t\t(to_int w) (to_int h) (to_int f) (to_int t) ink, \n\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_width\")\n{\n\tdraw_rect_width_op = Operator \"draw_rect_width\" \n\t\t(draw_rect_width x y w h f t ink) \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\tmy_draw_rect_width image x y w h f t ink\n\t\t= insert x' y' (block w' h') image, f == 1\n\t\t= (insert x' y' (block w' t) @ \n\t\t\tinsert (x' + w' - t) y' (block t h') @ \n\t\t\tinsert x' (y' + h' - t) (block w' t) @ \n\t\t\tinsert x' y' (block t h')) image\n\t{\n\t\tinsert = insert_noexpand;\n\t\tblock w h = image_new w h (get_bands image) (get_format image)\n\t\t\t(get_coding image) (get_type image) ink' 0 0;\n\t\tink' \n\t\t\t= Vector ink, is_list ink\n\t\t\t= ink;\n\t\t[x', y', w', h'] = rect_normalise x y w h;\n\t}\n}\n\n/* Default to 1 pixel wide edges.\n */\ndraw_rect x y w h f ink image\n\t= draw_rect_width x y w h f 1 ink image;\n\n/* This version of draw_rect uses the paintbox rect draw operation. It is an\n * inplace operation and will use bucketloads of memory.\n */\ndraw_rect_paintbox x y w h f ink image\n\t= oo_unary_function draw_rect_op image, is_class image\n\t= im_draw_rect image (to_real x) (to_real y) \n\t\t(to_real w) (to_real h) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_paintbox\")\n{\n\tdraw_rect_op = Operator \"draw_rect\" \n\t\t(draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_circle x y r f ink image\n\t= oo_unary_function draw_circle_op image, is_class image\n\t= im_draw_circle image (to_real x) (to_real y) \n\t\t(to_real r) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_circle\")\n{\n\tdraw_circle_op = Operator \"draw_circle\" \n\t\t(draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_line x1 y1 x2 y2 ink image\n\t= oo_unary_function draw_line_op image, is_class image\n\t= im_draw_line image (to_real x1) (to_real y1) \n\t\t(to_real x2) (to_real y2) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_line\")\n{\n\tdraw_line_op = Operator \"draw_line\" \n\t\t(draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (\\x x % base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (\\x idivide x base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= NULL, any (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n/* Linear regression. Return a class with the stuff we need in.\n * from s15.2, p 665 NR in C\n */\nlinreg xes yes\n    = obj\n{\n    obj = class {\n        // in case we ever get shown in the workspace\n        _vislevel = 2;\n\n        slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2;\n        intercept = (sy - sx * slope) / ss;\n\n        chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes];\n\n        siga = (chi2 / (ss - 2)) ** 0.5 *\n            ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5;\n        sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5;\n\n        // for compat with linregw, see below\n        q = 1.0;\n    }\n\n    ss = len xes;\n    sx = sum xes;\n    sy = sum yes;\n    sxoss = sx / ss;\n\n    tes = [x - sxoss :: x <- xes];\n    st2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Weighted linear regression. Xes, yes and a list of deviations.\n */\nlinregw xes yes devs \n\t= obj\n{\n\tobj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: \n\t\t\t[x, y, sd] <- zip3 xes yes devs];\n\n\t\tsiga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (1 / st2) ** 0.5;\n\n\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\t}\n\n\twt = [sd ** -0.5 :: sd <- devs];\n\n\tss = sum wt;\n\tsx = sum [x * w :: [x, w] <- zip2 xes wt];\n\tsy = sum [y * w :: [y, w] <- zip2 yes wt];\n\tsxoss = sx / ss;\n\n\ttes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Clustering: pass in a list of points, repeatedly merge the\n * closest two points until no two points are closer than the threshold.\n * Return [merged-points, corresponding-weights]. A weight is a list of the\n * indexes we merged to make that point, ie. len weight == how significant\n * this point is.\n *\n * eg. \n *\tcluster 12 [152,154,155,42,159] == \n *\t\t[[155,42],[[1,2,0,4],[3]]]\n */\ncluster thresh points\n\t= oo_unary_function cluster_op points, is_class points\n\t// can't use [0..len points - 1], in case len points == 0\n\t= merge [points, map (converse cons []) (take (len points) [0 ..])],\n\t\tis_list points\n\t= error (_ \"bad arguments to \" ++ \"cluster\")\n{\n\tcluster_op = Operator \"cluster\" \n\t\t(cluster thresh) Operator_type.COMPOUND false;\n\n\tmerge x\n\t\t= x, m < 2 || d > thresh\n\t\t= merge [points', weights']\n\t{\n\t\t[points, weights] = x;\n\t\tm = len points;\n\n\t\t// generate indexes of all possible pairs, avoiding comparing a thing \n\t\t// to itself, and assuming that dist is reflexive\n\t\t// first index is always less than 2nd index\n\t\t// the +1,+2 makes sure we have an increasing generator, otherwise we\n\t\t// can get [3 .. 4] (for example), which will make a decreasing\n\t\t// sequence\n\t\tpairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]];\n\n\t\t// distance function\n\t\t// arg is eg. [3,1], meaning get distance from point 3 to point 1\n\t\tdist x \n\t\t\t= abs (points?i - points?j)\n\t\t{\n\t\t\t[i, j] = x;\n\t\t}\n\n\t\t// smallest distance, then the two points we merge\n\t\tp = minpos (map dist pairs);\n\t\td = dist pairs?p;\n\t\t[i, j] = pairs?p;\n\n\t\t// new point and new weight\n\t\tnw = weights?i ++ weights?j;\n\t\tnp = (points?i * len weights?i + points?j * len weights?j) / len nw;\n\n\t\t// remove element i from a list\n\t\tremove i l = take i l ++ drop (i + 1) l;\n\n\t\t// remove two old points, add the new merged one\n\t\t// i < j (see \"pairs\", above)\n\t\tpoints' = np : remove i (remove j points);\n\t\tweights' = nw : remove i (remove j weights);\n\t}\n}\n\n/* Extract the area of an image around an arrow.\n * Transform the image to make the arrow horizontal, then displace by hd and\n * vd pxels, then cut out a bit h pixels high centered on the arrow.\n */\nextract_arrow hd vd h arrow\n\t= extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im'\n{\n\t// the line as a polar vector\n\tpv = polar (arrow.width, arrow.height);\n\ta = im pv;\n\n\t// smallest rotation that will make the line horizontal\n\ta'\n\t\t= 360 - a, a > 270\n\t\t= 180 - a, a > 90\n\t\t= -a;\n\n\tim' = rotate Interpolate_bilinear a' arrow.image;\n\n\t// look at the start and end of the arrow, pick the leftmost\n\tp\n\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t= (arrow.right, arrow.bottom);\n\n\t// transform that point to im' space\n\tp' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset);\n}\n\n/* You'd think these would go in _convert, but they are not really colour ops,\n * so put them here.\n */\nrad2float image\n\t= oo_unary_function rad2float_op image, is_class image\n\t= im_rad2float image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"rad2float\")\n{\n\trad2float_op = Operator \"rad2float\" \n\t\trad2float Operator_type.COMPOUND_REWRAP false;\n}\n\nfloat2rad image\n\t= oo_unary_function float2rad_op image, is_class image\n\t= im_float2rad image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"float2rad\")\n{\n\tfloat2rad_op = Operator \"float2rad\" \n\t\tfloat2rad Operator_type.COMPOUND_REWRAP false;\n}\n\nsegment x\n\t= oo_unary_function segment_op x, is_class x\n\t= image', is_image x \n\t= error (_ \"bad arguments to \" ++ \"segment\")\n{\n\tsegment_op = Operator \"segment\" \n\t\tsegment Operator_type.COMPOUND_REWRAP false;\n\n\t[image, nsegs] = im_segment x;\n\timage' = im_copy_set_meta image \"n-segments\" nsegs;\n}\n\npoint a b\n\t= oo_binary_function point_op a b, is_class a\n\t= oo_binary'_function point_op a b, is_class b\n\t= im_read_point b x y, is_image b\n\t= [b?x?y], is_matrix b\n\t= [b?x], is_real_list b && y == 0\n\t= [b?y], is_real_list b && x == 0\n\t= error (_ \"bad arguments to \" ++ \"point\")\n{\n\tpoint_op = Operator \"point\" \n\t\t(\\a\\b Vector (point a b)) Operator_type.COMPOUND false;\n\n\t(x, y) \n\t\t= a, is_complex a;\n\t\t= (a?0, a?1), is_real_list a && is_list_len 2 a\n\t\t= error \"bad position format\";\n}\n\n/* Generate an ImageMagick (or GraphicsMagick) command suitable for \n * im_system_image. Use convert.exe in $VIPSHOME/bin, if it exists, otherwise\n * assume it's on the path somewhere.\n */\nmagick_command switch \n\t= join_sep \" \" [convert, \"\\\"%s\\\"\", switch, \"\\\"%s\\\"\"]\n{\n\tprefs = Workspaces.Preferences;\n\tuse_gm = prefs.USE_GRAPHICSMAGICK;\n\tname = if use_gm then \"gm\" else \"convert\";\n\texe = concat [name, expand \"$EXEEXT\"];\n\tvipsexe = path_absolute [expand \"$VIPSHOME\", \"bin\", exe];\n\tfinal_exe \n\t\t= vipsexe, search vipsexe != []\n\t\t= exe;\n\tconvert\t\n\t\t= join_sep \" \" [final_exe, \"convert\"], use_gm\n\t\t= final_exe;\n}\n\n/* Run a command on an image. See magick_command, for example.\n */\nsystem_image command x\n\t= oo_unary_function system_image_op x, is_class x\n\t= system x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"system_image\")\n{\n\tsystem_image_op = Operator \"system_image\" \n\t\t(system_image command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem im\n\t\t= image_out\n\t{\n\t\t[image_out, log] = \n\t\t\tim_system_image (get_image im) \"%s.tif\" \"%s.tif\" command;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.28/_types.def",
    "content": "/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary (\\a op.fn a x) this,\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// we can't call map_trinary directly, since it uses Group and we\n\t// don't support mutually recursive top-level functions :-(\n\t// copy-paste it here, keep in sync with the version in _stdenv\n\tmap_nary fn args\n\t\t= fn args, groups == []\n\t\t= Group (map process [0, 1 .. shortest - 1])\n\t{\n\t\tgroups = filter is_Group args;\n\t\n\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\tprocess n\n\t\t\t= NULL, any (map (is_noval n) args)\n\t\t\t= map_nary fn (map (extract n) args)\n\t\t{\n\t\t\textract n arg\n\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t= arg;\n\t\n\t\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t\t}\n\t}\n\n\t// need ite as a true trinary\n\tite a b c = if a then b else c;\n\n\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t];\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\n\t\t[op.fn this.value x,\n\t\t\top.type == Operator_type.COMPOUND]\n\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[is_list_len 3 value, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.item colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum \"Colour space\" Image_type.colour_spaces default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\n/* An option whose value is a string rather than a number.\n */\nOption_string caption labels item = class\n\tOption caption labels (index (equal item) labels) {\n\tOption_edit caption labels value \n\t\t= this.Option_string caption labels (labels?value);\n}\n\n/* Make an option from an enum.\n */\nOption_enum caption enum item = class\n\tOption_string caption enum.names item {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing item;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum caption enum (enum.names?value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNONE = 0;\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNONE = 0;\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n\tRAD = 6;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* Extract a column.\n\t */\n\tcolumn n = map (extract n) value;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (column col) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (column from);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = this.column 0; \n\tthings = this.column 1; \n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tHISTOGRAM = 10;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tARRAY = 27;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t$MULTIBAND => MULTIBAND,\n\t\t$B_W => B_W,\n\t\t$HISTOGRAM => HISTOGRAM,\n\t\t$XYZ => XYZ,\n\t\t$LAB => LAB,\n\t\t$CMYK => CMYK,\n\t\t$LABQ => LABQ,\n\t\t$RGB => RGB,\n\t\t$UCS => UCS,\n\t\t$LCH => LCH,\n\t\t$LABS => LABS,\n\t\t$sRGB => sRGB,\n\t\t$YXY => YXY,\n\t\t$FOURIER => FOURIER,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$ARRAY => ARRAY\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options generated from this, so match the order to the order in the\n\t * Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t$sRGB => sRGB,\n\t\t$Lab => LAB,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t$Mono => B_W,\n\t\t$sRGB => sRGB,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$Lab => LAB,\n\t\t$LabQ => LABQ,\n\t\t$LabS => LABS,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \n\t\t// \"Image v == 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\t// if one of then/else is an image, get the target format from that\n\t\t// otherwise, let the non-image objects set the target\n\t\ttarget_format \n\t\t\t= get_member_list has_format get_format x, \n\t\t\t\thas_member_list has_format x\n\t\t\t= NULL;\n\n\t\tto_image x = to_image_size width height target_bands target_format x;\n\n\t\t[then', else'] = map to_image x;\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if value then then' else else');\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nInterpolate_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\tLBB = 3;\n\tNOHALO = 4;\n\tVSQBS = 5;\n\n\t// Should introspect to get the list of interpolators :-(\n        // We can \"dir\" on VipsInterpolate to get a list of them, but we\n        // can't get i18n'd descriptions until we have more\n        // introspection stuff in nip2.\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Bilinear\", \n\t\t_ \"Bicubic\",\n\t\t_ \"Upsize: reduced halo bicubic (LBB)\",\n\t\t_ \"Upsharp: reduced halo bicubic with edge sharpening (Nohalo)\",\n\t\t_ \"Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)\"\n\t];\n\n\t/* And to vips type names.\n\t */\n\ttypes = [\n\t\t\"VipsInterpolateNearest\",\n\t\t\"VipsInterpolateBilinear\",\n\t\t\"VipsInterpolateBicubic\",\n\t\t\"VipsInterpolateLbb\",\n\t\t\"VipsInterpolateNohalo\",\n\t\t\"VipsInterpolateVsqbs\"\n\t];\n}\n\nInterpolate type options = class {\n\tvalue = vips_object_new Interpolate_type.types?type [] options;\n}\n\nInterpolate_bilinear = Interpolate Interpolate_type.BILINEAR [];\n\nInterpolate_picker default = class \n\tInterpolate interp.value [] {\n\t_vislevel = 2;\n\n\tinterp = Option \"Interpolation\" Interpolate_type.descriptions default;\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t_ \"Perceptual\" => PERCEPTUAL,\n\t\t_ \"Relative\" => RELATIVE,\n\t\t_ \"Saturation\" => SATURATION,\n\t\t_ \"Absolute\" => ABSOLUTE\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t_ \"Point\" => POINT,\n\t\t_ \"Line\" => LINE,\n\t\t_ \"Spline\" => SPLINE,\n\t\t_ \"Bar\" => BAR\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t_ \"YYYY\" => YYYY,\n\t\t_ \"XYYY\" => XYXY,\n\t\t_ \"XYXY\" => XYXY\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [$format => Plot_format.XYYY] value {\n}\n\n/* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate\n * empty slots, for example.\n */\nNULL = class \n\t_Object {\n\too_binary_table op x = [\n\t\t// the only operation we allow is equality .. use pointer equality,\n\t\t// this lets us test a == NULL and a != NULL\n\t\t[this === x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"equal\"],\n\t\t[this !== x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"not_equal\"]\n\t] ++ super.oo_binary_table op x;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.38/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t[_L, _a, _b] = default_value;\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n\n\tCCT_colour = class\n\t\tMenuaction (_ \"Colour from CCT\") (_ \"pick colour by CCT\") {\n\t\taction = widget 6500;\n\n\t\twidget x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tT = Scale \"CCT\" 1800 25000 x;\n\n\t\t\t_result = colour_from_temp (to_real T);\n\n\t\t\tColour_edit space value \n\t\t\t\t= widget (temp_from_colour (Colour space value));\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Convert to\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Tag as\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum (_ \"Old whitepoint\") Whitepoints \"D65\";\n\t\t\tnew_white = Option_enum (_ \"New whitepoint\") Whitepoints \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCCT_item = class\n\t\tMenuaction (_ \"Calculate temperature\")\n\t\t\t(_ \"estimate CCT using the McCamy approximation\") {\n\t\taction z = map_unary temp_from_colour z;\n\t}\n\n\tColour_item = Colour_new_item.CCT_colour;\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= monitor_profile, has_bands image && get_bands image == 3\n\t\t= print_profile;\n\trender_intents = Option_enum (_ \"Render intent\") Render_intent.names\n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_rad_item = class\n\tMenupullright (_ \"_Radiance\") (_ \"convert to and from Radiance packed format\") {\n\tUnpack_item = class\n\t\tMenuaction (_ \"Unpack\") \n\t\t\t(_ \"unpack Radiance format to float\") {\n\t\taction x = map_unary rad2float x;\n\t}\n\n\tPack_item = class\n\t\tMenuaction (_ \"Pack\") \n\t\t\t(_ \"pack 3-band float to Radiance format\") {\n\t\taction x = map_unary float2rad x;\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n        // get a representative image from an arg\n        get_image x\n            = get_image x.value?0, is_Group x\n            = x;\n\n        _im = get_image x; \n\t\tsample = measure_draw (to_real pacross) (to_real pdown) \n\t\t\t\t(to_real measure) _im;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure_sample (to_real pacross) (to_real pdown) \n\t\t\t\t\t(to_real measure) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.38/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 1.5;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 50;\n\t\t\tfs = Scale \"Sharpen flat areas by\" (-2) 5 1;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" (-2) 5 2;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tlayers = Scale \"Layers\" 1 100 10;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\", \"Approximate\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf, aconvsep layers]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\t\t\trotate = Option \"Rotate\" [\n\t\t\t\t\"Don't rotate\", \n\t\t\t\t\"4 x 45 degrees\", \n\t\t\t\t\"8 x 45 degrees\", \n\t\t\t\t\"2 x 90 degrees\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_lindetect, !separable && type == 0 && rotate == 1\n\t\t\t\t\t\t= im_compass, !separable && type == 0 && rotate == 2\n\t\t\t\t\t\t= im_gradient, !separable && type == 0 && rotate == 3\n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_conv_f, !separable && type == 1\n\t\t\t\t\t\t= im_convsep_f, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 4) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width.expr window_height.expr in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\nFilter_greyc_item = class \n\tMenupullright \"_GREYCstoration\" \"noise-removing filter\" {\n\tDenoise_item = class \n\t\tMenuaction \"Denoise\" \"Noise-removing filter\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\titerations = Scale \"Iterations\" 1 5 1;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 40;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.9;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.15;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.6;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.1;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) x;\n\t\t}\n\t}\n\n\tEnlarge_item = class\n\t\tMenuaction \"Enlarge\" \"Enlarge image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Enlarge\" 1 10 3;\n\t\t\titerations = Scale \"Iterations\" 1 5 3;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 20;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.2;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.9;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.1;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.5;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) \n\t\t\t\t\t(resize Interpolate_bilinear\n\t\t\t\t\t\t(to_real scale) (to_real scale) x);\n\t\t}\n\t}\n}\n\nFilter_magick_item = class\n\tMenupullright \"Magic_k\" \"various Image/Graphics Magick filters\" {\n\tsystem command x = map_unary (system_image command) x;\n\tradius_widget = Scale \"Radius\" 1 100 10;\n\tsigma_widget = Scale \"Sigma\" 0.1 10 1;\n\tangle_widget = Scale \"Angle\" (-360) 360 0;\n\ttext_widget = String \"Text to draw\" \"AaBbCcDdEe\";\n\n\tprint_colour triple\n\t\t= concat [\"\\\"#\", concat (map fmt triple), \"\\\"\"]\n\t{\n\t\tfmt x = reverse (take 2 (reverse (print_base 16 (x + 256))));\n\t}\n\n\tForeground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-fill \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Foreground triple;\n\t}\n\tforeground_widget = Foreground [0, 0, 0];\n\n\tBackground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-background \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Background triple;\n\t}\n\tbackground_widget = Background [255, 255, 255];\n\n\tAntialias value = class\n\t\tToggle \"Antialias\" value {\n\n\t\t_flag\n\t\t\t= \"-antialias\", value\n\t\t\t= \"+antialias\";\n\n\t\tToggle_edit caption value = this.Antialias value;\n\t}\n\tantialias_widget = Antialias true;\n\n\tGravity gravity = class\n\t\tOption_string \"Gravity\" [\n\t\t\t\"None\",\n\t\t\t\"Center\",\n\t\t\t\"East\",\n\t\t\t\"Forget\",\n\t\t\t\"NorthEast\",\n\t\t\t\"North\",\n\t\t\t\"NorthWest\",\n\t\t\t\"SouthEast\",\n\t\t\t\"South\",\n\t\t\t\"SouthWest\",\n\t\t\t\"West\",\n\t\t\t\"Static\"\n\t\t] gravity {\n\n\t\t_flag = \"-gravity \" ++ gravity;\n\n\t\tOption_edit caption labels value = this.Gravity labels?value;\n\t}\n\tgravity_widget = Gravity \"Center\";\n\n\tAlpha alpha = class\n\t\tOption_string \"Alpha\" [\n\t\t\t\"On\", \n\t\t\t\"Off\", \n\t\t\t\"Set\", \n\t\t\t\"Opaque\", \n\t\t\t\"Transparent\", \n\t\t\t\"Extract\", \n\t\t\t\"Copy\", \n\t\t\t\"Shape\", \n\t\t\t\"Background\"\n\t\t] alpha {\n\n\t\t_flag = \"-alpha \" ++ alpha;\n\n\t\tOption_edit caption labels value = this.Alpha labels?value;\n\t}\n\talpha_widget = Alpha \"On\";\n\n\tGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Y\" 0;\n\t\ty = Expression \"X\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 10;\n\t\tvoffset = Expression \"Vertical offset\" 10;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFont_widget = class {\n\t\t_vislevel = 3;\n\n\t\tfamily = Option_string \"Family\" [\n\t\t\t\"Arial\",\n\t\t\t\"ArialBlack\",\n\t\t\t\"AvantGarde\",\n\t\t\t\"BitstreamCharter\",\n\t\t\t\"Bookman\",\n\t\t\t\"CenturySchoolbook\",\n\t\t\t\"ComicSansMS\",\n\t\t\t\"Courier\",\n\t\t\t\"CourierNew\",\n\t\t\t\"DejaVuSans\",\n\t\t\t\"DejaVuSansMono\",\n\t\t\t\"DejaVuSerif\",\n\t\t\t\"Dingbats\",\n\t\t\t\"FreeMono\",\n\t\t\t\"FreeSans\",\n\t\t\t\"FreeSerif\",\n\t\t\t\"Garuda\",\n\t\t\t\"Georgia\",\n\t\t\t\"Helvetica\",\n\t\t\t\"HelveticaNarrow\",\n\t\t\t\"Impact\",\n\t\t\t\"LiberationMono\",\n\t\t\t\"LiberationSans\",\n\t\t\t\"LiberationSerif\",\n\t\t\t\"NewCenturySchlbk\",\n\t\t\t\"Palatino\",\n\t\t\t\"Purisa\",\n\t\t\t\"Symbol\",\n\t\t\t\"Times\",\n\t\t\t\"TimesNewRoman\",\n\t\t\t\"Ubuntu\",\n\t\t\t\"Verdana\",\n\t\t\t\"Webdings\"\n\t\t] \"Arial\";\n\t\tstyle = Option_string \"Style\" [\n\t\t\t\"Any\", \"Italic\", \"Normal\", \"Oblique\"\n\t\t] \"Normal\";\n\t\tweight = Scale \"Weight\" 1 800 400;\n\t\tsize = Scale \"Point size\" 1 100 12;\n\t\tstretch = Option_string \"Stretch\" [\n\t\t\t\"Any\", \"Condensed\", \"Expanded\", \"ExtraCondensed\", \"ExtraExpanded\", \n\t\t\t\"Normal\", \"SemiCondensed\", \"SemiExpanded\", \"UltraCondensed\", \n\t\t\t\"UltraExpanded\"\n\t\t] \"Normal\";\n\n\t\t_flag = join_sep \" \" [\n\t\t\t\t\"-family\", family.item,\n\t\t\t\t\"-weight\", print weight.value,\n\t\t\t\t\"-pointsize\", print size.value,\n\t\t\t\t\"-style\", style.item,\n\t\t\t\t\"-stretch\", stretch.item];\n\t}\n\n\tAdaptive_blur_item = class\n\t\tMenuaction \"_Adaptive Blur\" \"blur less near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = radius_widget; \n\t\t\tsigma = sigma_widget;\n\t\t\tcommand = magick_command (concat [\"-adaptive-blur \",\n\t\t\t\tprint radius.value, \"x\", print sigma.value]);\n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n\n\tAdaptive_sharpen_item = class\n\t\tMenuaction \"_Adaptive Sharpen\" \"sharpen more near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = radius_widget; \n\t\t\tsigma = sigma_widget;\n\t\t\tcommand = magick_command (concat [\"-adaptive-sharpen \",\n\t\t\t\tprint radius.value, \"x\", print sigma.value]);\n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n\n\tAlpha_item = class\n\t\tMenuaction \"_Alpha\" \"add/remove alpha channel\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\talpha = alpha_widget; \n\t\t\tcommand = magick_command alpha._flag; \n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n\n\tAnnotate_item = class\n\t\tMenuaction \"_Annotate\" \"add text annotation\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = text_widget;\n\t\t\tfont = Font_widget;\n\t\t\tgeometry = Geometry_widget; \n\t\t\tgravity = gravity_widget; \n\t\t\tforeground = foreground_widget;\n\t\t\tantialias = antialias_widget;\n\t\t\tcommand = magick_command (join_sep \" \" [\n\t\t\t\tfont._flag,\n\t\t\t\tantialias._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tforeground._flag,\n\t\t\t\t\"-annotate\", geometry._flag, \"\\\"\" ++ text.value ++ \"\\\"\"]);\n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n\n\tSwirl_item = class\n\t\tMenuaction \"_Swirl\" \"swirl around the centre\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tangle = angle_widget;\n\t\t\tcommand = magick_command (\"-swirl \" ++ print angle.value);\n\n\t\t\t_result = system command x; \n\t\t}\n\t}\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image\" \"use an image to blend two objects\" {\n\t\taction a b c = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ti = Toggle \"Invert mask\" false;\n\n\t\t\t_result \n\t\t\t\t= map_trinary process a b c\n\t\t\t{\n\t\t\t\tprocess a b c \n\t\t\t\t\t= blend condition in1 in2, !i\n\t\t\t\t\t= blend (invert condition) in1 in2\n\t\t\t\t{\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t\t= false,\n\t\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t\t= true;\n\t\t\t\t\t[condition, in1, in2] = sortc compare [a, b, c];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"_Alpha\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t_ \"Normal\" => NORMAL,\n\t\t\t_ \"If Lighter\" => IFLIGHTER,\n\t\t\t_ \"If Darker\" => IFDARKER,\n\t\t\t_ \"Multiply\" => MULTIPLY,\n\t\t\t_ \"Add\" => ADD,\n\t\t\t_ \"Subtract\" => SUBTRACT,\n\t\t\t_ \"Screen\" => SCREEN,\n\t\t\t_ \"Burn\" => BURN,\n\t\t\t_ \"Soft Light\" => SOFTLIGHT,\n\t\t\t_ \"Hard Light\" => HARDLIGHT,\n\t\t\t_ \"Lighten\" => LIGHTEN,\n\t\t\t_ \"Darken\" => DARKEN,\n\t\t\t_ \"Dodge\" => DODGE,\n\t\t\t_ \"Reflect\" => REFLECT,\n\t\t\t_ \"Freeze\" => FREEZE,\n\t\t\t_ \"Bitwise OR\" => OR,\n\t\t\t_ \"Bitwise AND\" => AND\n\t\t];\n\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum \"Blend mode\" names \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\t[mono, colour] = \n\t\t\t\t\tsortc (const (is_colour_type @ get_type)) [a, b];\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t_ \"Grey\",\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t_ \"North-west\",\n\t\t\t\t_ \"North\",\n\t\t\t\t_ \"North-east\",\n\t\t\t\t_ \"West\",\n\t\t\t\t_ \"Centre\",\n\t\t\t\t_ \"East\",\n\t\t\t\t_ \"South-west\",\n\t\t\t\t_ \"South\",\n\t\t\t\t_ \"South-east\",\n\t\t\t\t_ \"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.38/Histogram.def",
    "content": "Hist_new_item = class\n\tMenupullright \"_New\" \"new histogram\" {\n\tHist_item = class\n\t\tMenuaction \"_Identity\" \"make an identity histogram\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\t_result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d);\n\t\t}\n\t}\n\n\tHist_new_from_matrix = Matrix_buildlut_item; \n\n\tHist_from_image_item = class\n\t\tMenuaction \"Ta_g Image As Histogram\" \"set image Type to Histogram\" {\n\t\taction x = hist_tag x;\n\t}\n\n\tTone_item = class \n\t\tMenuaction \"_Tone Curve\" \"make a new tone mapping curve\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\t_result \n\t\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t\t{\n\t\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_convert_to_hist_item = class \n\tMenuaction \"Con_vert to Histogram\" \"convert anything to a histogram\" {\n\taction x = hist_tag (to_image x);\n}\n\nHist_find_item = class \n\tMenupullright \"_Find\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n\n\tIndexed_item = class\n\t\tMenuaction \"_Indexed\" \n\t\t\t\"use a 1-band index image to pick bins for an n-band image\" {\n\t\taction x y \n\t\t\t= map_binary map x y\n\t\t{\n\t\t\tmap a b\n\t\t\t\t= hist_find_indexed index im\n\t\t\t{\n\t\t\t\t[im, index] = sortc (const is_index) [a, b];\n\n\t\t\t\tis_index x\n\t\t\t\t\t= has_image x && b == 1 && \n\t\t\t\t\t\t(f == Image_format.UCHAR || f == Image_format.USHORT)\n\t\t\t\t{\n\t\t\t\t\tim = get_image x;\n\t\t\t\t\tb = get_bands x;\n\t\t\t\t\tf = get_format x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\t[im, hist] = sortc (const is_hist) [a, b];\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Integrate\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate\" \n\t\t\"find point-to-point differences (inverse of Integrate)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_inv_item = class \n\tMenuaction \"In_vert\" \"invert a histogram\" {\n\taction x = map_unary hist_inv x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\tarea = extract_arrow \n\t\t\t\t\tdisplace.value vdisplace.value width.value arrow;\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize Interpolate_bilinear 1 (1 / width.value) area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary (extract_arrow \n\t\t\t\tdisplace.value vdisplace.value width.value) x;\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tformat = Option_enum \"Format\" Plot_format.names \"YYYY\";\n\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => style.value, $format => format.value] ++ range;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow 0 0 1 x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.38/Image.def",
    "content": "Image_new_item = class Menupullright \"_New\" \"make new things\" {\n\tImage_black_item = class Menuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \"Image type\"\n\t\t\t\tImage_type.type_names \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region on image using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\t[target, x] = sortc compare [a, b];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\nImage_number_format_item = class\n\tMenupullright \"_Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_header_item = class \n\tMenupullright \"_Header\" \"do stuff to the image header\" {\n\n\tImage_get_item = class\n\t\tMenupullright \"_Get\" \"get header fields\" {\n\n\t\t// the header fields we can get\n\t\tfields = class {\n\t\t\ttype = 0;\n\t\t\twidth = 1;\n\t\t\theight = 2;\n\t\t\tformat = 3;\n\t\t\tbands = 4;\n\t\t\txres = 5;\n\t\t\tyres = 6;\n\t\t\txoffset = 7;\n\t\t\tyoffset = 8;\n\t\t\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t$width => width,\n\t\t\t\t$height => height,\n\t\t\t\t$bands => bands,\n\t\t\t\t$format => format,\n\t\t\t\t$type => type,\n\t\t\t\t$xres => xres,\n\t\t\t\t$yres => yres,\n\t\t\t\t$xoffset => xoffset,\n\t\t\t\t$yoffset => yoffset,\n\t\t\t\t$coding => coding\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum (_ \"Field\") field_names name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tCustom_item = class\n\t\t\tMenuaction \"C_ustom\" \"get any header field\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tfield = String \"Field\" \"Xsize\";\n\t\t\t\tparse = Option \"Parse\" [\n\t\t\t\t\t\"No parsing\",\n\t\t\t\t\t\"Parse string as integer\",\n\t\t\t\t\t\"Parse string as real\",\n\t\t\t\t\t\"Parse string as hh:mm:ss\"\n\t\t\t\t] 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary (wrap @ process @ get_header field.value) x\n\t\t\t\t{\n\t\t\t\t\tparse_str parse str = parse (split is_space str)?0;\n\n\t\t\t\t\tparse_field name cast parse x\n\t\t\t\t\t\t= cast x, is_number x\n\t\t\t\t\t\t= parse_str parse x, is_string x\n\t\t\t\t\t\t= error (\"not \" ++ name);\n\n\t\t\t\t\tget_int = parse_field \"int\" \n\t\t\t\t\t\tcast_signed_int parse_int;\n\t\t\t\t\tget_float = parse_field \"float\" \n\t\t\t\t\t\tcast_float parse_float;\n\t\t\t\t\tget_time = parse_field \"hh:mm:ss\" \n\t\t\t\t\t\tcast_signed_int parse_time;\n\n\t\t\t\t\twrap x\n\t\t\t\t\t\t= Real x, is_real x\n\t\t\t\t\t\t= Vector x, is_real_list x\n\t\t\t\t\t\t= Image x, is_image x\n\t\t\t\t\t\t= Bool x, is_bool x\n\t\t\t\t\t\t= Matrix x, is_matrix x\n\t\t\t\t\t\t= String \"String\" x, is_string x\n\t\t\t\t\t\t= List x, is_list x\n\t\t\t\t\t\t= x;\n\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tget_int, \n\t\t\t\t\t\tget_float,\n\t\t\t\t\t\tget_time\n\t\t\t\t\t]?parse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum \"Image type\" Image_type.type_names \n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_cache_item = class\n\tMenuaction \"C_ache\" \"cache calculated image pixels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttile_width = Number \"Tile width\" 128;\n\t\ttile_height = Number \"Tile height\" 128;\n\t\tmax_tiles = Number \"Maximum number of tiles to cache\" (-1);\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= cache (to_real tile_width) (to_real tile_height) \n\t\t\t\t\t(to_real max_tiles) image;\n\t\t}\n\t}\n}\n\n#separator\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\t// we can't use id here since we want to \"declass\"\n\t\t\t\t\t\t// the members of x ... consider if x is a crop class,\n\t\t\t\t\t\t// for example, we don't want to inherit from crop, we\n\t\t\t\t\t\t// want to make a new image class\n\t\t\t\t\t\trot180 @ rot180,\n\t\t\t\t\t\trot90,\n\t\t\t\t\t\trot180,\n\t\t\t\t\t\trot270\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate interp angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary straighten x\n\t\t\t\t{\n\t\t\t\t\tstraighten arrow\n\t\t\t\t\t\t= rotate interp angle'' arrow.image\n\t\t\t\t\t{\n\t\t\t\t\t\tx = arrow.width;\n\t\t\t\t\t\ty = arrow.height;\n\t\t\n\t\t\t\t\t\tangle = im (polar (x, y));\n\t\t\n\t\t\t\t\t\tangle'\n\t\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t\t= angle;\n\t\t\n\t\t\t\t\t\tangle''\n\t\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize interp xfactor yfactor image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\taspect = Toggle \"Break aspect ratio\" false;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize interp h v image, aspect\n\t\t\t\t\t\t= resize interp fac fac image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac > yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\tmin_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac < yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\t[h, v] = [\n\t\t\t\t\t\t\tmax_factor, \n\t\t\t\t\t\t\tmin_factor, \n\t\t\t\t\t\t\t[xfac, 1], \n\t\t\t\t\t\t\t[1, yfac]]?which;\n\n\t\t\t\t\t\tfac \n\t\t\t\t\t\t\t= h, v == 1\n\t\t\t\t\t\t\t= v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_within_item = class\n\t\t\tMenuaction \"Size _Within\" \"size to fit within a rectangle\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\t// the rects we size to fit within\n\t\t\t\t_rects = [\n\t\t\t\t\t[2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], \n\t\t\t\t\t[1280, 1024], [1024, 768], [800, 600], [640, 480] \n\t\t\t\t];\n\n\t\t\t\twithin = Option \"Fit within (pixels)\" (\n\t\t\t\t\t[print w ++ \" x \" ++ print h :: [w, h] <- _rects] ++\n\t\t\t\t\t[\"Custom\"]\n\t\t\t\t) 4;\n\t\t\t\tcustom_width = Expression \"Custom width\" 1000;\n\t\t\t\tcustom_height = Expression \"Custom height\" 1000;\n\t\t\t    size = Option \"Page size\" [\n\t\t\t\t\t\"Full page\", \"Half page\", \"Quarter page\" \n\t\t\t\t] 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t \t_result\n\t\t\t\t \t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\txdiv = [1, 2, 2]?size;\n\t\t\t\t\tydiv = [1, 1, 2]?size;\n\t\t\t\t\tallrect = _rects ++ [\n\t\t\t\t\t\t[custom_width.expr, custom_height.expr]\n\t\t\t\t\t];\n\t\t\t\t\t[width, height] = allrect?within;\n\n\t\t\t\t\tprocess x\n\t\t\t\t\t\t= resize interp fac fac x, fac < 1\n\t\t\t\t\t\t= x\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = (width / xdiv) / x.width;\n\t\t\t\t\t\tyfac = (height / ydiv) / x.height;\n\t\t\t\t\t\tfac = min_pair xfac yfac;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\" [\"Nearest\", \"Bilinear\"] 1;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_trn {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t[sample', trn, err] = transform_search \n\t\t\t\t\tmax_err max_iter order interp wrap\n\t\t\t\t\tsample reference;\n\t\t\t\ttransformed_image = Image sample';\n\t\t\t\t_trn = Transform trn reference.width reference.height;\n\t\t\t\tfinal_error = err;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\t[i, t] = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tBandwise_item = Image_join_item.Bandwise_item;\n\n    sep1 = Menuseparator;\n\n\tBandand_item = class\n\t\tMenuaction \"Bitwise Band AND\" \"bitwise AND of image bands\" {\n\t\taction x = bandand x;\n\t}\n\n\tBandor_item = class\n\t\tMenuaction \"Bitwise Band OR\" \"bitwise OR of image bands\" {\n\t\taction x = bandor x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldl1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x \n\t\t= crop x [l, t, w, h]\n\t{\n\t\tfields = [\n\t\t\t[has_left, get_left, 0],\n\t\t\t[has_top, get_top, 0],\n\t\t\t[has_width, get_width, 100],\n\t\t\t[has_height, get_height, 100]\n\t\t];\n\n\t\t[l, t, w, h] \n\t\t\t= map get_default fields\n\t\t{\n\t\t\tget_default line\n\t\t\t\t= get x, has x\n\t\t\t\t= default\n\t\t\t{\n\t\t\t\t[has, get, default] = line;\n\t\t\t}\n\t\t}\n\t}\n\n\tcrop x geo = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tl = Expression \"Crop left\" ((int) (geo?0 + geo?2 / 4));\n\t\tt = Expression \"Crop top\" ((int) (geo?1 + geo?3 / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (geo?2 / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (geo?3 / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t[_a', _b'] = sortc _pred [a, b];\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_draw_item = class \n\tMenupullright \"_Draw\" \"draw lines, circles, rectangles, floods\" {\n\tLine_item = class Menuaction \"_Line\" \"draw line on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tx1 = Expression \"Start x\" 0;\n\t\t\ty1 = Expression \"Start y\" 0;\n\t\t\tx2 = Expression \"End x\" 100;\n\t\t\ty2 = Expression \"End y\" 100;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary line x\n\t\t\t{\n\t\t\t\tline im \n\t\t\t\t\t= draw_line x1 y1 x2 y2 i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tRect_item = class Menuaction \"_Rectangle\" \"draw rectangle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\trx = Expression \"Left\" 50;\n\t\t\try = Expression \"Top\" 50;\n\t\t\trw = Expression \"Width\" 100;\n\t\t\trh = Expression \"Height\" 100;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\tt = Scale \"Line thickness\" 1 50 3;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary rect x\n\t\t\t{\n\t\t\t\trect im \n\t\t\t\t\t= draw_rect_width rx ry rw rh f t i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class Menuaction \"_Circle\" \"draw circle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcx = Expression \"Centre x\" 100;\n\t\t\tcy = Expression \"Centre y\" 100;\n\t\t\tr = Expression \"Radius\" 50;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary circle x\n\t\t\t{\n\t\t\t\tcircle im \n\t\t\t\t\t= draw_circle cx cy r f i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tFlood_item = class Menuaction \"_Flood\" \"flood bounded area of image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsx = Expression \"Start x\" 100;\n\t\t\tsy = Expression \"Start y\" 100;\n\n\t\t\te = Option \"Flood while\" [\n\t\t\t\t\"Not equal to ink\",\n\t\t\t\t\"Equal to start point\"\n\t\t\t] 0;\n\n\t\t\t// pick a default ink that won't flood, if we can\n\t\t\ti \n\t\t\t\t= Expression \"Ink\" default_ink\n\t\t\t{\n\t\t\t\tdefault_ink\n\t\t\t\t\t= [0], ! has_image x\n\t\t\t\t\t= pixel;\n\t\t\t\tpixel = map mean (bandsplit (extract_area sx sy 1 1 im));\n\t\t\t\tim = get_image x;\n\t\t\t}\n\n\t\t\t_result \n\t\t\t\t= map_unary flood x\n\t\t\t{\n\t\t\t\tflood im \n\t\t\t\t\t= draw_flood sx sy i.expr im, e == 0\n\t\t\t\t\t= draw_flood_blob sx sy i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tDraw_scalebar_item = class Menuaction \"_Scale\" \"draw scale bar\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpx = Expression \"Left\" 50;\n\t\t\tpy = Expression \"Top\" 50;\n\t\t\twid = Expression \"Width\" 100;\n\t\t\tthick = Scale \"Line thickness\" 1 50 3;\n\t\t\ttext = String \"Dimension text\" \"50μm\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\tpos = Option \"Position Text\" [\"Above\", \"Below\"] 1;\n\t\t\tvp = Option \"Dimension by\" [\n\t\t\t\t\"Inner Vertical Edge\", \n\t\t\t\t\"Centre of Vertical\", \n\t\t\t\t\"Outer Vertical Edge\"\n\t\t\t] 1;\n            dpi = Expression \"DPI\" 100;\n            ink = Colour \"Lab\" [50,0,0];\n      \n            _result\n                = map_unary process x\n            {\n                process im\n                    = blend (Image scale) ink' im\n                {\n                    // make an ink compatible with the image\n                    ink' = colour_transform_to (get_type im) ink;\n\n                    x = to_real px;\n                    y = to_real py;\n                    w = to_real wid;\n                    d = to_real dpi;\n\n                    t = floor thick;\n\n                    bg = image_new (get_width im) (get_height im) (get_bands im)\n                        (get_format im) (get_coding im) (get_type im) 0 0 0;\n                    draw_block x y w t im =\n                        draw_rect_width x y w t true 1 [255] im;\n                    label = im_text text.value font.value w 1 d;\n                    lw = get_width label;\n                    lh = get_height label;\n                    ly = [y - lh - t, y + 2 * t]?pos;\n                    vx = [\n\t\t\t\t\t\t[x - t, x + w],\n\t\t\t\t\t\t[x - t / 2, x + w - t / 2],\n\t\t\t\t\t\t[x, x + w - t]\n\t\t\t\t\t]?vp;\n\n\t\t\t\t\tscale = (draw_block x y w t @\n\t\t\t\t\t\tdraw_block vx?0 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tdraw_block vx?1 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tinsert_noexpand (x + w / 2 - lw / 2) ly label)\n\t\t\t\t\t\tbg;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise Join\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t// we can't use map_unary since chop-into-tiles returns a group of\n\t\t\t// groups and we want to be able to reassemble that\n\t\t\t// TODO: chop-into-tiles should return an array class which\n\t\t\t// displays as group but does not have the looping behaviour?\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n\n\tArrayFL_item = class\n\t\tMenuaction \"_Array from List\"\n\t\t\t\"join a list of images into a single image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tncol = Number \"Max. Number of Columns\" 1;\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t_l \n\t\t\t\t= split_lines ncol.value x.value, is_Group x\n\t\t\t\t= split_lines ncol.value x;\n\n\t\t\t_result\n\t\t\t\t= (image_set_origin 0 0 @\n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value\n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list _l));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tGaussian_item = class \n\t\tMenuaction \"Gaussian _Noise\" \"make an image of gaussian noise\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t_result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) \n\t\t\t\tmean.value deviation.value);\n\t\t}\n\t}\n\n\tFractal_item = class \n\t\tMenuaction \"_Fractal\" \"make a fractal image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t}\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n\tColour_atlas_item = class\n\tMenuaction \"_Colour Atlas\"\n\t\t\"make a grid of patches grouped around a colour\" {\n\t\taction = class \n\t\t\t_result {   \n\t\t\t_vislevel = 3;\n       \n\t\t\tstart = Colour_picker \"Lab\" [50,0,0];\n\t\t\tnstep = Expression \"Number of steps\" 9;\n\t\t\tssize = Expression \"Step size\" 10; \n\t\t\tpsize = Expression \"Patch size\" 32;\n\t\t\tsepsize = Expression \"Separator size\" 4;\n\t\n\t\t\t_result\n\t\t\t\t= colour_transform_to (get_type start) blocks'''\n\t\t\t{\n\t\t\t\tsize = (to_real nstep * 2 + 1) * to_real psize - \n\t\t\t\t\tto_real sepsize;\n\t\t\t\txy = make_xy size size; \n\n\t\t\t\txy_grid = (xy % to_real psize) < \n\t\t\t\t\t(to_real psize - to_real sepsize);\n\t\t\t\tgrid = xy_grid?0 & xy_grid?1;\n\n\t\t\t\tblocks = (int) (to_real ssize * ((int) (xy / to_real psize)));\n\t\t\t\tlab_start = colour_transform_to Image_type.LAB start;\n\t\t\t\tblocks' = blocks - to_real nstep * to_real ssize + \n\t\t\t\t\tVector (tl lab_start.value);\n\t\t\t\tblocks'' = hd lab_start.value ++ Image blocks';\n\t\t\t\tblocks''' \n\t\t\t\t\t= image_set_type Image_type.LAB blocks'', Image grid\n\t\t\t\t\t= 0;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.38/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/7.38\n\nstart_DATA = \\\n\tMath.def \\\n\tImage.def \\\n\tColour.def \\\n\tTasks.def \\\n\tObject.def \\\n\tFilter.def \\\n\tMatrix.def \\\n\tWidgets.def \\\n\tHistogram.def \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_convert.def \\\n\t_generate.def \\\n\t_list.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\t_Object.def \\\n\t_types.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/7.38/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_AND\" \"bitwise AND of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_OR\" \"bitwise OR of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"_XOR\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_NOT\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBandand_item = Image_band_item.Bandand_item; \n\n\tBandor_item = Image_band_item.Bandor_item; \n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tDifference_item = class \n\t\tMenuaction \"_Difference\" \"difference of two lists\" {\n\t\taction a b = map_binary difference a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tValue_item = class \n\t\tMenuaction \"_Value\" \"value of point in object\" {\n\t\taction a = class _result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tposition = Expression \"Coordinate\" (0, 0);\n\t\n\t\t\t_result = map_binary point position.expr a;\n\t\t}\n\t}\n\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tSkew_item = class \n\t\tMenuaction \"S_kew\" \"skew of image or list or vector\" {\n\t\taction a = map_unary skew a;\n\t}\n\n\tKurtosis_item = class \n\t\tMenuaction \"Kurtosis\" \"kurtosis of image or list or vector\" {\n\t\taction a = map_unary kurtosis a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \n\t\t\t\"position of centre of gravity of histogram\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = linreg xes yes;\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = linregw xes yes devs;\n\t}\n\n\tCluster_item = class \n\t\tMenuaction \"_Cluster\" \"cluster a list of numbers\" {\n\t\taction l = class {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tthresh = Expression \"Threshold\" 10;\n\t\n\t\t\t[_r, _w] = cluster thresh.expr l;\n\t\n\t\t\tresult = _r;\n\t\t\tweights = _w;\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.38/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_identity_item = class \n\t\tMenuaction \"_Identity\" \"make an identity matrix\" {\n\t\taction = identity (identity_matrix 5);\n\t\t\n\t\tidentity v = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix (identity_matrix (to_real s)), to_real s != len v;\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = identity value;\n\t\t}\n\t}\n\n\tMatrix_series_item = class \n\t\tMenuaction \"_Series\" \"make a series\" {\n\t\taction = series (mkseries 0 1 5);\n\n\t\tmkseries s t e \n\t\t\t= transpose [[to_real s, to_real s + to_real t .. to_real e]];\n\n\t\tseries v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t_s = v?0?0;\n\t\t\t_t = v?1?0 - v?0?0;\n\t\t\t_e = (last v)?0;\n\n\t\t\ts = Expression \"Start value\" _s;\n\t\t\tt = Expression \"Step by\" _t;\n\t\t\te = Expression \"End value\" _e;\n\n\t\t\t_result \n\t\t\t\t= Matrix (mkseries s t e), \n\t\t\t\t\t\tto_real s != _s || to_real t != _t || to_real e != _e\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = series value;\n\t\t}\n\t}\n\n\tMatrix_square_item = class \n\t\tMenuaction \"_Square\" \"make a square matrix\" {\n\t\taction = square (mksquare 5);\n\n\t\tmksquare s = replicate s (take s [1, 1 ..]);\n\n\t\tsquare v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == to_real s\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mksquare (to_real s); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = square value;\n\t\t}\n\t}\n\n\tMatrix_circular_item = class \n\t\tMenuaction \"_Circular\" \"make a circular matrix\" {\n\t\taction = circle (mkcircle 3);\n\n\t\tmkcircle r\n\t\t\t\t= map2 (map2 pyth) xes yes\n\t\t{\n\t\t\tline = [-r .. r];\n\t\t\txes = replicate (2 * r + 1) line;\n\t\t\tyes = transpose xes;\n\t\t\tpyth a b \n\t\t\t\t\t= 1, (a**2 + b**2) ** 0.5 <= r\n\t\t\t\t\t= 0;\n\t\t}\n\n\t\tcircle v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tr = Expression \"Radius\" ((len v - 1) / 2);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mkcircle (to_real r); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = circle value;\n\t\t}\n\t}\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\nMatrix_sort_item = class \n\tMenuaction \"_Sort\" \"sort by column or row\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\to = Option (_ \"Orientation\") [\n\t\t\t_ \"Sort by column\",\n\t\t\t_ \"Sort by row\"\n\t\t] 0;\n\t\ti = Expression (_ \"Sort on index\") 0;\n\t\td = Option (_ \"Direction\") [\n\t\t\t_ \"Ascending\",\n\t\t\t_ \"Descending\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary sort x\n\t\t{\n\t\t\tidx = to_real i;\n\t\t\tpred a b \n\t\t\t\t= a?idx <= b?idx, d == 0\n\t\t\t\t= a?idx >= b?idx;\n\t\t\tsort x\n\t\t\t\t= (x.Matrix_base @ sortc pred) x.value,\n\t\t\t\t\to == 0\n\t\t\t\t= (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value;\n\t\t}\n\t}\n}\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ \n\t\t\t\t\trange;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.38/Object.def",
    "content": "Object_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nObject_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nObject_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nObject_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nObject_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.38/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\n\tCsv_import_item = class\n\t\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tstart_line = Expression \"Start at line\" 1;\n\t\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_csv2vips filename)\n\t\t\t{\n\t\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\t\tescape x \n\t\t\t\t\t= foldr prefix [] x\n\t\t\t\t{\n\t\t\t\t\tprefix x l\n\t\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t\t= x : l;\n\t\t\t\t}\n\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tRaw_import_item = class\n\t\tMenuaction \"_Raw Import\" \"read a file of binary values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tacross = Expression \"Pixels across\" 100;\n\t\t\tdown = Expression \"Pixels down\" 100;\n\t\t\tbytes = Expression \"Bytes per pixel\" 3;\n\t\t\tskip = Expression \"Skip over initial bytes\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_binfile path.value \n\t\t\t\t\tacross.expr down.expr bytes.expr skip.expr)\n\t\t\t{\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// interpret Analyze header for layout and calibration\n\tAnalyze7_header_item = class\n\t\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\t\"examine the Analyze header and set layout and value\" {\n\t\taction x \n\t\t\t= x'''\n\t\t{\n\t\t\t// read bits of header\n\t\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\t\tdim0 = dim 0 x;\n\t\t\tdim1 = dim 1 x;\n\t\t\tdim2 = dim 2 x;\n\t\t\tdim3 = dim 3 x;\n\t\t\tdim4 = dim 4 x;\n\t\t\tdim5 = dim 5 x;\n\t\t\tdim6 = dim 6 x;\n\t\t\tdim7 = dim 7 x;\n\t\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\t\n\t\t\t// oops, now a nop\n\t\t\tx' = x;\n\t\n\t\t\t// lay out higher dimensions width-ways\n\t\t\tx'' \n\t\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\t\tdim0 == 7\n\t\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\t\n\t\t\t// multiply by scale factor to get kBeq\n\t\t\tx''' = x'' * (cal_max / glmax);\n\t\t}\n\t}\n\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\t[image, patch] = sortc larger [a, b];\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n\t\t\tsample = measure_draw 6 4 (to_real measure) image;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\tmode = Option \"Input LUT\" [\n\t\t\t\t\"Linearize from chart greyscale\",\n\t\t\t\t\"Fit intercept from chart greyscale\",\n\t\t\t\t\"Linear input, set brightness from chart\",\n\t\t\t\t\"Linear input\"\n\t\t\t] 0;\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = measure_sample 6 4 (to_real measure) image;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb \n\t\t\t\t= Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0\n\t\t\t\t= Matrix [0: intercepts, replicate (_camera.width + 1) 1], \n\t\t\t\t\tmode == 1\n\t\t\t\t= Matrix [[0, 0], [1, 1]]\n\t\t\t{\n\t\t\t\tintercepts = [(linreg _true_grey_Y' cam).intercept :: \n\t\t\t\t\tcam <- transpose _camera_grey'];\n\t\t\t}\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\t// plot from 0 explicitly so we see the effect of mode1 (intercept\n\t\t\t// from greyscale)\n\t\t\tlinearising_lut = Plot [$ymin => 0] _linear_lut;\n\n\t\t\t// map an image though the lineariser\n\t\t\tlinear x\n\t\t\t\t= hist_map linearising_lut.value x, mode == 0 || mode == 1\n\t\t\t\t= x;\n\n\t\t\t// map the chart measurements though the lineariser\n\t\t\t_camera' = (to_matrix @ linear @ to_image) _camera;\n\n\t\t\t// solve for RGB -> XYZ\n\t\t\t// normalise: the 2nd row is what makes Y, so divide by that to\n\t\t\t// get Y in 0-1.\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\t_full_M = transpose (_pinv * (transpose _camera' * _true_XYZ));\n\t\t\tM = _full_M / scale;\n\t\t\tscale = sum _full_M.value?1;\n\n\t\t\t// now turn the camera to LAB and calculate dE76\n\t\t\t_camera'' = (to_matrix @ \n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @ \n\t\t\t\trecomb M @ \n\t\t\t\tmultiply scale @\n\t\t\t\tto_image) _camera';\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tavg_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0 && i < len macbeth_names\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\n\t\t\t// normalise brightness ... in linear mode, we optionally don't\n\t\t\t// set the brightness from the Macbeth chart\n\t\t\tnorm x \n\t\t\t\t= x * scale, mode != 3\n\t\t\t\t= x;\n\n\t\t\t// convert RGB camera to Lab\n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tnorm @\n\t\t\t\trecomb M @\n\t\t\t\tcast_float @\n\t\t\t\tlinear) image.value;\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b = class\n\t\t\t(map_binary process a b) {\n\t\t\tprocess a b\n\t\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t\t{\n\t\t\t\t// the name of the calib object we need\n\t\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t\t// get the Calibrate_chart arg first\n\t\t\t\t[image, calib] = sortc (const (is_instanceof calib_name)) \n\t\t\t\t\t[a, b];\n\n\t\t\t\tresult = (Image @\n\t\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\t\tcalib.norm @\n\t\t\t\t\trecomb calib.M @\n\t\t\t\t\tcast_float @\n\t\t\t\t\tcalib.linear) image.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [$style => style.value] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\t!is_list_len 2 images\n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = all (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize Interpolate_bilinear xfactor yfactor scale_im;\n\t\t\t_offset_im = resize Interpolate_bilinear xfactor yfactor offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.38/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.38/_Object.def",
    "content": "/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0|1|2|3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \n\tjoin_sep \"|\" Image_type.colour_spaces.names];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide|VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad properties for \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"where\" ++ \"\\n\" ++ arg_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make arg type notes\n\targ_types = join_sep \"\\n\" (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"\\n\" ++ _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = join_sep \"\\n\" all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if those fail as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if that fails as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary'_function op a b\n\t= matches1?0, matches1 != []\n\t= matches2?0, op.symmetric && matches2 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0, matches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t// these should always be defined\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x = oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x = oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op = oo_unary_function (oo_unary_lookup op) this;\n\n\too_binary_table op x = [];\n\too_unary_table op = [];\n}\n"
  },
  {
    "path": "share/nip2/compat/7.38/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= Image x.value, is_Plot x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n// like to_image, but we do 1x1 pixel + x, then embed it up\n// always make an unwrapped image for speed ... this gets used by ifthenelse\n// and stuff like that\n// format can be NULL, meaning set format from x\nto_image_size width height bands format x\n\t= x, is_image x\n\t= x.value, is_Image x\n\t= im''\n{\n\t// we want x to set the target format if we don't have one, so we\n\t// can't use image_new\n\tim = im_black 1 1 bands + x;\n\tim'\n\t\t= clip2fmt format im, format != NULL\n\t\t= im;\n\tim'' = embed 1 0 0 width height im';\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && is_list_len 3 x\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\nto_int x = (int) (to_real x);\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The outermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x \n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), !is_list_len 2 parts \n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, !is_list_len 4 parts \n\t= sign * (abs ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", \n\t\tmember \".0123456789\",\n\t\tmember \"eE\", \n\t\tmember \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tsign \n\t\t= 1, ipart > 0\n\t\t= -1;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), !is_list_len 5 parts \n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t$D93 => D93_whitepoint,\n\t$D75 => D75_whitepoint,\n\t$D65 => D65_whitepoint,\n\t$D55 => D55_whitepoint,\n\t$D50 => D50_whitepoint,\n\t$A => A_whitepoint,\n\t$B => B_whitepoint,\n\t$C => C_whitepoint,\n\t$E => E_whitepoint,\n\t$D3250 => D3250_whitepoint\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, image_set_type GREY16 @ im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l = join_sep path_separator l;\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 > 1 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n"
  },
  {
    "path": "share/nip2/compat/7.38/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= embed 1 0 0 w h im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black 1 1 (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\nmkim options x y b\n    = Image (image_new x y b\n        (opt $format) (opt $coding) (opt $type)\n        (opt $pixel)\n        (opt $xoffset) (opt $yoffset))\n{\n    opt = get_option options [\n        $format => Image_format.UCHAR,\n        $coding => Image_coding.NOCODING,\n        $type => Image_type.sRGB,\n        $pixel => 0,\n        $xoffset => 0,\n        $yoffset => 0\n    ];\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = im_gauss_imask_sep (radius / 3) 0.2;\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n/* Make a colour from a temperature.\n */\ncolour_from_temp T\n\t= error (_ \"T out of range\"), T < 1667 || T > 25000\n\t= Colour \"Yxy\" [50, x, y]\n{\n\t// Kim et all approximation\n\t// see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation\n\tx\n\t\t= -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 +\n\t\t\t0.8776956 * 10 ** 3 / T + 0.179910, T < 4000\n\t\t= -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 +\n\t\t\t0.2226347 * 10 ** 3 / T + 0.240390;\n\n\ty \n\t\t= -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + \n\t\t\t2.18555832 * x - 0.20219638, T < 2222\n\t\t= -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + \n\t\t\t2.09137015 * x - 0.16748867, T < 4000\n\t\t=  3.0817580 * x ** 3 - 5.87338670 * x ** 2 +\n\t\t\t3.75112997 * x - 0.37001483;\n}\n\ntemp_from_colour z\n\t= T\n{\n\tc = colour_transform_to Image_type.YXY (to_colour z);\n\tx = c.value?1;\n\ty = c.value?2;\n\n\t// McCamy's approximation, see eg. \n\t// http://en.wikipedia.org/wiki/Color_temperature#Approximation\n\n\txe = 0.332;\n\tye = 0.1858;\n\tn = (x - xe) / (y - ye);\n\tT = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33;\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.38/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 1;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" \n\t] 4;\n\n\tcontrol_selection mask im no\n\t\t= [\n\t\t\tif mask then im * 1.2 else im * 1,\n\t\t\tif mask then im * 0.8 else im * 1,\n\t\t\tif mask then 0 else im,\n\t\t\tif mask then 255 else im,\n\t\t\tif mask then im else 0,\n\t\t\tif mask then im else 255,\n\t\t\tmask\n\t\t]?no;\n\n\tRectangle = class\n        Menuaction \"_Rectangle\"\n            \"use an Arrow or Region x to define a rectangle\"\n        {\n        action x = class\n            _result {\n            _vislevel = 3;\n\n            control = _control;   \n\n            _result = control_selection mask im control\n                  {\n                \tim = x.image;\n                \tmask = Image m\n                    {\n\t\t\t\t\t\trx     \n\t\t\t\t\t\t\t= x.region_rect, is_Region x\n\t\t\t\t\t\t\t= x;\n\t\t\t\t\t\tb     = image_new im.width im.height 1 0 0 1 0 0 0;\n\t\t\t\t\t\tw     = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0;\n\t\t\t\t\t\tm     = insert_noexpand rx.nleft rx.ntop w b; \n                     }\n                   }\n            }\n        }\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = get_image a;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = get_image ((pt_list.value)?0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tSegment_item = class\n\t\tMenuaction \"_Segment\" \"break image into disjoint regions\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsegments\n\t\t\t\t= Expression \"Number of disjoint regions\" \n\t\t\t\t\t(map_unary (get_header \"n-segments\") _result);\n\n\t\t\t_result = map_unary segment x;\n\t\t}\n\t}\n\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize Interpolate_bilinear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize Interpolate_bilinear f1 1 b1\n\t\t\t\t\t{b1 = resize Interpolate_bilinear 1 f2 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/7.38/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = Image (get_image line);\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = Image (get_image (pt_l?0));\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t};\n\nMount_options _ctype _ppcm = class \n  {\n  _vislevel = 3;\n  apply = Toggle \"Apply mount options\" false;\n  ls = Expression \"Lower mount section bigger by (cm)\" 0;\n  mount_colour = Colour _ctype [0, 0, 0];\n  _los = ls.expr * _ppcm;\n  };\n\nFrame_variables comp = class\n  {\n  _vislevel = 3;\n\n  scale_factor = Expression \"scale the size of the frame by\" 1;\n\n  /* These sliders define the fraction of the frames width or height is extracted\n   * to produce each of the particular regions.\n   */\n  corner_section = Scale \"Corner section\" 0.1 1 0.5;\n  edge_section = Scale \"Edge section\" 0.1 1 0.2, comp > 0\n\t\t\t\t  = \"Only required for complex frames\";\n  middle_section = Scale \"Middle section\" 0.1 1 0.2;\n  blend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n  option = Toggle \"Use mirror of left-side to make right\" true;\n  };\n\n"
  },
  {
    "path": "share/nip2/compat/7.38/_list.def",
    "content": "/* any l: or all the elements of list l together\n *\n * any (map (equal 0) list) == true, if any element of list is zero.\n * any :: [bool] -> bool\n */\nany = foldr logical_or false;\n\n/* all l: and all the elements of list l together\n *\n * all (map (==0) list) == true, if every element of list is zero.\n * all :: [bool] -> bool\n */\nall = foldr logical_and true;\n\n/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* delete eq x l: delete the first x from l\n *\n * delete equal 'b' \"abcdb\" == \"acdb\"\n * delete :: (* -> bool) -> * -> [*] -> [*]\n */\ndelete eq a l\n\t= [], l == []\n\t= y, eq a b\n\t= b : delete eq a y\n{\n\tb:y = l;\n}\n\n/* difference eq a b: delete b from a\n *\n * difference equal \"asdf\" \"ad\" == \"sf\"\n * difference :: (* -> bool) -> [*] -> [*] -> [*]\n */\ndifference = foldl @ converse @ delete;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn x, fn a\n\t= l\n{\n\ta:x = l;\n}\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* flatten x: flatten a list of lists of things into a simple list\n *\n * flatten :: [[*]] -> [*]\n */\nflatten x\n\t= foldr flat [] x, is_list x\n\t= x\n{\n\tflat x sofar\n\t\t= foldr flat sofar x, is_list x\n\t\t= x : sofar;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st x) xs\n{\n\tx:xs = l;\n}\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn x xs\n{\n\tx:xs = l;\n}\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn x (foldr fn st xs)\n{\n\tx:xs = l;\n}\n\n/* foldr1 fn l: like foldr, but use the last element as the start value\n *\n * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= x, xs == []\n\t= fn x (foldr1 fn xs)\n{\n\tx:xs = l;\n}\n\n/* Search a list for an element, returning its index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn x\n\t\t= search xs (n + 1)\n\t\t{\n\t\t\tx:xs = l;\n\t\t}\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= x : init xs\n{\n\tx:xs = l;\n}\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* join_sep sep l: join a list with a separator\n *\n * join_sep \", \" (map print [1 .. 4]) == \"1, 2, 3, 4\"\n * join_sep :: [*] -> [[*]] -> [*]\n */\njoin_sep sep l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ sep ++ b;\n}\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= x, xs == []\n\t= last xs\n{\n\tx:xs = l;\n}\n\n/* len l: length of list l\n * (see also is_list_len and friends in predicate.def)\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta:b:x = l;\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = any (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge p l r\n\t= [], p == [] || l == [] || r == []\n\t= a : merge z x y, c\n\t= b : merge z x y\n{\n\ta:x = l;\n\tb:y = r;\n\tc:z = p;\n}\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta:x = l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scanl fn st l: apply (foldl fn r) to every initial segment of a list\n *\n * scanl add 0 [1,2,3] == [1,3,6]\n * scanl :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscanl fn st l\n\t= st, l == []\n\t= st' : scanl fn st' xs\n{\n\tx:xs = l;\n\tst' = fn st x;\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta:x = l1;\n\t\tb:y = l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/7.38/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = any (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && all (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* Test list length ... quicker than len x == n for large lists.\n */\nis_list_len n x\n\t= true, x == [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len (n - 1) (tl x);\n\nis_list_len_more n x\n\t= true, x != [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len_more (n - 1) (tl x);\n\nis_list_len_more_equal n x\n\t= true, n == 0\n\t= false, x == [] \n\t= is_list_len_more_equal (n - 1) (tl x);\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, all (map is_obj l)\n\t= true, all (map is_list l) &&\n\t\tall (map (not @ is_obj) l) &&\n\t\tall (map is_rectangular l) &&\n\t\tis_list_len_more 0 l &&\n\t\tall (map (is_list_len (len (hd l))) (tl l))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && is_list_len (len (hd l)) l;\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_NULL x = is_instanceof \"NULL\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Plot x = is_instanceof \"Plot\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && all (map xy l)\n{\n\txy l = is_real_list l && is_list_len 2 l;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && any (map is_Group l)\n\t= any (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= oo_unary_function get_type_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_type\")\n{\n\tget_type_op = Operator \"get_type\" get_type \n\t\tOperator_type.COMPOUND false;\n\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\t// can have alpha, hence we let bands be one more than you might think\n\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.GREY16, type == Image_type.GREY16 && is_bands 1\n\t\t= Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && \n\t\t\t(width == 1 || height == 1)\n\t\t= Image_type.B_W, is_bands 1 \n\t\t= Image_type.CMYK, type == Image_type.CMYK && is_bands 4\n\t\t= type, is_colorimetric && is_bands 3\n\t\t= Image_type.sRGB, !is_colorimetric && is_bands 3\n\t\t= Image_type.MULTIBAND, !is_colorimetric && !is_bands 3\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\n\t\t// is bands n, with an optional alpha (ie. can be n + 1 too)\n\t\tis_bands n = bands == n || bands == n + 1;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= oo_unary_function get_format_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_format\")\n{\n\tget_format_op = Operator \"get_format\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= oo_unary_function get_bits_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bits\")\n{\n\tget_bits_op = Operator \"get_bits\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= oo_unary_function get_bands_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bands\")\n{\n\tget_bands_op = Operator \"get_bands\" get_bands \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= oo_unary_function get_coding_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_coding\")\n{\n\tget_coding_op = Operator \"get_coding\" get_coding \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= oo_unary_function get_xres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xres\")\n{\n\tget_xres_op = Operator \"get_xres\" get_xres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= oo_unary_function get_yres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yres\")\n{\n\tget_yres_op = Operator \"get_yres\" get_yres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= oo_unary_function get_xoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xoffset\")\n{\n\tget_xoffset_op = Operator \"get_xoffset\" get_xoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= oo_unary_function get_yoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yoffset\")\n{\n\tget_yoffset_op = Operator \"get_yoffset\" get_yoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= oo_unary_function get_image_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_image\")\n{\n\tget_image_op = Operator \"get_image\" get_image \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= oo_unary_function get_number_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_number\")\n{\n\tget_number_op = Operator \"get_number\" get_number \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= oo_unary_function get_real_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_real\")\n{\n\tget_real_op = Operator \"get_real\" get_real \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= oo_unary_function get_width_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_width\")\n{\n\tget_width_op = Operator \"get_width\" get_width \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= oo_unary_function get_height_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_height\")\n{\n\tget_height_op = Operator \"get_height\" get_height \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= oo_unary_function get_left_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_left\")\n{\n\tget_left_op = Operator \"get_left\" get_left \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= oo_unary_function get_top_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_top\")\n{\n\tget_top_op = Operator \"get_top\" get_top \n\t\tOperator_type.COMPOUND false;\n}\n\n// like has/get member, but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.38/_stdenv.def",
    "content": "/* optional args to functions\n */\n\nget_option options defaults f\n\t= error (_ \"unknown parameter \" ++ f), hits == []\n\t= hits?0\n{\n\thits = [v :: [n, v] <- options ++ defaults; n == f];\n}\n\n/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\nidivide a b = (int) ((int) a / (int) b);\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\n// 'difference' is defined in _list\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the function we call for \"a -> v\" expressions\nmksvpair s v\n\t= [s, v], is_string s\n\t= error \"not str on lhs of ->\";\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error (\"unimplemented vector operation: \" ++ op_name)\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n// make a name value pair\nmknvpair n v\n\t= [n, v], is_string n\n\t= error \"not [char] on LHS of =>\";\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined, has_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nbandand x\n\t= oo_unary_function bandand_op x, is_class x\n\t= foldr1 bitwise_and (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandand\")\n{\n\tbandand_op = Operator \"bandand\" bandand Operator_type.COMPOUND_REWRAP false;\n}\n\nbandor x\n\t= oo_unary_function bandor_op x, is_class x\n\t= foldr1 bitwise_or (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandor\")\n{\n\tbandor_op = Operator \"bandor\" bandor Operator_type.COMPOUND_REWRAP false;\n}\n\nsum x\n\t= oo_unary_function sum_op x, is_class x\n\t= im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x\n\t= sum_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"sum\")\n{\n\tsum_op = Operator \"sum\" sum Operator_type.COMPOUND false;\n\n\t// add elements in a nested-list thing\n\tsum_list l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nproduct x\n\t= oo_unary_function product_op x, is_class x\n\t= product_list x, is_list x \n\t// (product image) doesn't make much sense :(\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"product\")\n{\n\tproduct_op = Operator \"product\" product Operator_type.COMPOUND false;\n\n\tproduct_list l\n\t\t= foldr prod 1 l\n\t{\n\t\tprod x total\n\t\t\t= total * product x, is_list x\n\t\t\t= total * x;\n\t}\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\nskew x\n\t= oo_unary_function skew_op x, is_class x\n\t= sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x \n\t= sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"skew\")\n{\n\tskew_op = Operator \"skew\" skew Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN \n\t\t= w * h * b, is_image x'\n\t\t= len x';\n}\n\nkurtosis x\n\t= oo_unary_function kurtosis_op x, is_class x\n\t= sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x \n\t= sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"kurtosis\")\n{\n\tkurtosis_op = Operator \"kurtosis\" kurtosis Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN\n\t\t= len x', is_list x';\n\t\t= w * h * b;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image_hist x, is_image x && \n\t\t(fmt == Image_format.UCHAR || fmt == Image_format.USHORT)\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tfmt = get_format x;\n\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean, for any image type\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n\n\t// image mean for 8 and 16-bit unsigned images\n\t// we can use a histogram, yay, and save a pass through the image\n\tmeanze_image_hist i\n\t\t= sum / N\n\t{\n\t\t// histogram, knock out zeros\n\t\thist = hist_find i;\n\t\tblack = image_new 1 1 (get_bands hist) \n\t\t\t(get_format hist) (get_coding hist) (get_type hist) 0 0 0;\n\t\thistze = insert 0 0 black hist;\n\n\t\t// matching identity\n\t\tiden\n\t\t\t= im_identity_ushort (get_bands hist) (get_width hist),\n\t\t\t\t(get_width hist) > 256\n\t\t\t= im_identity (get_bands hist);\n\n\t\t// number of non-zero pixels\n\t\tN = mean histze * 256;\n\n\t\t// sum of pixels\n\t\tsum = mean (hist * iden) * 256;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_cache x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (\\row [row?x']) obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\" ++ \": \" ++\n\t\tjoin_sep \", \" (map print [cond, in1, in2]))\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x \n\t\t\t= to_image_size target_width target_height \n\t\t\t\ttarget_bands target_format x;\n\n\t\t[then_image, else_image] = map to_image [then_part, else_part];\n\n\t\tblend_result_image = image_set_type target_type \n\t\t\t(im_blend cond then_image else_image);\n\t}\n}\n\n// do big first: we want to keep big's class, if possible\n// eg. big is a Plot, small is a 1x1 Image\ninsert x y small big\n\t= oo_binary'_function insert_op small big, is_class big\n\t= oo_binary_function insert_op small big, is_class small\n\t= im_insert big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n}\n\nmeasure_draw across down measure image\n    = mark\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n\n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::  \n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n    x = map (extract 0) cods;\n    y = map (extract 1) cods;\n\n    outer = mkim [$pixel => 255] sample_width sample_height 1;\n    inner = mkim [] (sample_width - 4) (sample_height - 4) 1;\n    patch = insert 2 2 inner outer;\n\n    bg = mkim [] image.width image.height 1;\n\n    mask = Image (im_insertset bg.value patch.value x y);\n\n    image' = colour_transform_to Image_type.sRGB image;\n\n    mark = if mask then Vector [0, 255, 0] else image';\n}\n\nmeasure_sample across down measure image\n    = measures\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n                \n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::\n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n        \n    patches = map (\\p extract_area p?0 p?1 sample_width sample_height image) \n\t\tcods;\n    measures = Matrix (map (map mean) (map bandsplit patches));\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ninvert x\n\t= oo_unary_function invert_op x, is_class x\n\t= im_invert x, is_image x\n\t= 255 - x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"invert\")\n{\n\tinvert_op = Operator \"invert\" invert Operator_type.COMPOUND false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate interp angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_affinei_all image interp.value a (-b) b a 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\t(rotate interp) Operator_type.COMPOUND_REWRAP false;\n\ta = cos angle;\n\tb = sin angle;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_lr\")\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin_lr Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert (get_width a) 0 b a;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_tb\")\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin_tb Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert 0 (get_height a) b a;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\t// The [[real]] can contain 128 values ... squeeze them out!\n\timage = im_mask2vips (Matrix m2) == 255;\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\" ++ \": \" ++ \n\t\t\"conv (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvf mask image\n\t= oo_unary_function convf_op image, is_class image\n\t= im_conv_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convf\" ++ \": \" ++ \n\t\t\"convf (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconvf_op = Operator \"convf\" \n\t\t(convf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\naconvsep layers mask image \n\t= oo_unary_function aconvsep_op image, is_class image\n\t= im_aconvsep image (to_matrix mask) (to_real layers), is_image image\n\t= error (_ \"bad arguments to \" ++ \"aconvsep\")\n{\n\taconvsep_op = Operator \"aconvsep\" \n\t\t(aconvsep layers mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsep_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\ngreyc iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx x\n\t= oo_unary_function greyc_op x, is_class x\n\t= greyc_im x, is_image x\n\t= error (_ \"bad argument\" ++ \" (\" ++ print x ++ \") to \" ++ \"greyc\")\n{\n\tgreyc_op = Operator \"greyc\" (greyc\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im x = im_greyc x\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\ngreyc_mask iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx mask x\n\t= oo_binary_function greyc_mask_op mask x, is_class mask\n\t= oo_binary'_function greyc_mask_op mask x, is_class x\n\t= greyc_im mask x, is_image mask && is_image x\n\t= error (_ \"bad arguments\" ++ \n\t\t\" (\" ++ print mask ++ \", \" ++ print x ++ \") \" ++\n\t\t\"to \" ++ \"greyc\")\n{\n\tgreyc_mask_op = Operator \"greyc_mask\" (greyc_mask\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im mask x = im_greyc_mask x mask\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_indexed index value\n\t= oo_binary_function hist_find_indexed_op index value, is_class index\n\t= oo_binary'_function hist_find_indexed_op index value, is_class value\n\t= im_hist_indexed index value, is_image index && is_image value\n\t= error (_ \"bad arguments to \" ++ \"hist_find_indexed\")\n{\n\thist_find_indexed_op = Operator \"hist_find_indexed\" \n\t\t(compose (compose Plot_histogram) hist_find_indexed) \n\t\t\tOperator_type.COMPOUND false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h \n\t\t= (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h\n\t{\n\t\t// up the format so it can represent the whole range of\n\t\t// possible values from this mask\n\t\tfmt x\n\t\t\t= Image_format.SHORT, \n\t\t\t\tx == Image_format.UCHAR || x == Image_format.CHAR\n\t\t\t= Image_format.INT, \n\t\t\t\tx == Image_format.USHORT || x == Image_format.SHORT ||\n\t\t\t\tx == Image_format.UINT \n\t\t\t= x;\n\t}\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_inv hist \n\t= oo_unary_function hist_inv_op hist, is_class hist\n\t= inv hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_inv\")\n{\n\thist_inv_op = Operator \"hist_inv\" \n\t\thist_inv Operator_type.COMPOUND_REWRAP false;\n\n\tinv im\n\t\t= im_invertlut (to_matrix im''') len\n\t{\n\t\t// need a vertical doublemask\n\t\tim' \n\t\t\t= rot90 im, get_width im > 1 && get_height im == 1 \n\t\t\t= im, get_width im == 1 && get_height im > 1\n\t\t\t= error (_ \"not a hist\");\n\t\tlen = get_height im';\n\n\t\t// values must be scaled to 0 - 1\n\t\tim'' = im' / (max im');\n\t\t\n\t\t// add an index column on the left\n\t\t// again, must be in 0-1\n\t\ty = ((make_xy 1 len)?1) / len;\n\t\tim''' = y ++ im'';\n\t}\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= lhisteq image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n\n\t// loop over bands, if necessary\n\tlhisteq im\n\t\t= im_lhisteq im (to_real w) (to_real h), get_bands im == 1\n\t\t= (foldl1 join @ map lhisteq @ bandsplit) im;\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nresize interp xfac yfac image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\t// is this interpolation nearest-neighbour?\n\tis_nn x = x.type == Interpolate_type.NEAREST_NEIGHBOUR;\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// upscale by any factor, nearest neighbour \n\t\t// upscale by integer part, then affine to exact size\n\t\t= scale xg?1 yg?1 (im_zoom im xg?0 yg?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// downscale by any factor, nearest neighbour \n\t\t// downscale by integer part, then affine to exact size\n\t\t= scale xs?1 ys?1 (im_subsample im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// upscale by any factor with affine\n\t\t= scale xfac' yfac' im,\n\t\t\txfac' >= 1 && yfac' >= 1 \n\n\t\t// downscale by any factor, bilinear\n\t\t// block shrink by integer factor, then resample to \n\t\t// exact with affine\n\t\t= scale xs?1 ys?1 (im_shrink im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 \n\n\t\t= error (\"resize: unimplemented argument combination:\\n\" ++ \n\t\t\t\"  xfac = \" ++ print xfac' ++ \"\\n\" ++\n\t\t\t\"  yfac = \" ++ print yfac' ++ \"\\n\" ++\n\t\t\t\"  interp = \" ++ print interp ++ \" (\" ++\n\t\t\t\tInterpolate_type.descriptions?interp.type ++ \")\")\n\t{\n\t\t// convert a float scale to integer plus fraction\n\t\t// eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25)\n\t\tbreak f = [floor f, f / floor f];\n\n\t\t// same, but for downsizing ... turn a float scale which is less than\n\t\t// 1 into an int shrink and a float scale\n\n\t\t// complicated: the int shrink may round the size down (eg. imagine\n\t\t// subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide\n\t\t// image, not a 3.666 pixel wide image), so pass in the size of image\n\t\t// we are operating on and adjust for any rounding\n\t\t\n\t\t// so ... x is (eg.) 467, f is (eg. 128/467, about 0.274)\n\t\trbreak x f \n\t\t\t= [int_shrink, float_resample]\n\t\t{\n\t\t\t// the size of image we are aiming for after the combined int and\n\t\t\t// float resample\n\t\t\tx' = x * f;\n\n\t\t\t// int part\n\t\t\tint_shrink = floor (1 / f);\n\n\t\t\t// size after int shrink\n\t\t\tx'' = floor (x / int_shrink);\n\n\t\t\t// therefore what we need for the float part\n\t\t\tfloat_resample = x' / x'';\n\t\t}\n\n\t\twidth = get_width im;\n\t\theight = get_height im;\n\n\t\t// grow and shrink factors\n\t\txg = break xfac';\n\t\tyg = break yfac';\n\t\txs = rbreak width xfac';\n\t\tys = rbreak height yfac';\n\n\t\t// resize\n\t\tscale xfac yfac im\n\t\t\t= im_affinei_all im interp.value xfac 0 0 yfac 0 0;\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\n\n// Given a xywh rect, flip it around so wh are always positive\nrect_normalise x y w h \n\t= [x', y', w', h']\n{\n\tx'\n\t\t= x + w, w < 0\n\t\t= x;\n\ty'\n\t\t= y + h, h < 0\n\t\t= y;\n\tw' = abs w;\n\th' = abs h;\n}\n\ndraw_flood_blob x y ink image\n\t= oo_unary_function draw_flood_blob_op image, is_class image\n\t= im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood_blob\")\n{\n\tdraw_flood_blob_op = Operator \"draw_flood_blob\" \n\t\t(draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_flood x y ink image\n\t= oo_unary_function draw_flood_op image, is_class image\n\t= im_draw_flood image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood\")\n{\n\tdraw_flood_op = Operator \"draw_flood\" \n\t\t(draw_flood x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* This version of draw_rect uses insert_noexpand and will be fast, even for\n * huge images.\n */\ndraw_rect_width x y w h f t ink image\n\t= oo_unary_function draw_rect_width_op image, is_class image\n\t= my_draw_rect_width image (to_int x) (to_int y) \n\t\t(to_int w) (to_int h) (to_int f) (to_int t) ink, \n\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_width\")\n{\n\tdraw_rect_width_op = Operator \"draw_rect_width\" \n\t\t(draw_rect_width x y w h f t ink) \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\tmy_draw_rect_width image x y w h f t ink\n\t\t= insert x' y' (block w' h') image, f == 1\n\t\t= (insert x' y' (block w' t) @ \n\t\t\tinsert (x' + w' - t) y' (block t h') @ \n\t\t\tinsert x' (y' + h' - t) (block w' t) @ \n\t\t\tinsert x' y' (block t h')) image\n\t{\n\t\tinsert = insert_noexpand;\n\t\tblock w h = image_new w h (get_bands image) (get_format image)\n\t\t\t(get_coding image) (get_type image) ink' 0 0;\n\t\tink' \n\t\t\t= Vector ink, is_list ink\n\t\t\t= ink;\n\t\t[x', y', w', h'] = rect_normalise x y w h;\n\t}\n}\n\n/* Default to 1 pixel wide edges.\n */\ndraw_rect x y w h f ink image\n\t= draw_rect_width x y w h f 1 ink image;\n\n/* This version of draw_rect uses the paintbox rect draw operation. It is an\n * inplace operation and will use bucketloads of memory.\n */\ndraw_rect_paintbox x y w h f ink image\n\t= oo_unary_function draw_rect_op image, is_class image\n\t= im_draw_rect image (to_real x) (to_real y) \n\t\t(to_real w) (to_real h) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_paintbox\")\n{\n\tdraw_rect_op = Operator \"draw_rect\" \n\t\t(draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_circle x y r f ink image\n\t= oo_unary_function draw_circle_op image, is_class image\n\t= im_draw_circle image (to_real x) (to_real y) \n\t\t(to_real r) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_circle\")\n{\n\tdraw_circle_op = Operator \"draw_circle\" \n\t\t(draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_line x1 y1 x2 y2 ink image\n\t= oo_unary_function draw_line_op image, is_class image\n\t= im_draw_line image (to_real x1) (to_real y1) \n\t\t(to_real x2) (to_real y2) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_line\")\n{\n\tdraw_line_op = Operator \"draw_line\" \n\t\t(draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (\\x x % base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (\\x idivide x base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= NULL, any (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n/* Linear regression. Return a class with the stuff we need in.\n * from s15.2, p 665 NR in C\n */\nlinreg xes yes\n    = obj\n{\n    obj = class {\n        // in case we ever get shown in the workspace\n        _vislevel = 2;\n\n        slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2;\n        intercept = (sy - sx * slope) / ss;\n\n        chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes];\n\n        siga = (chi2 / (ss - 2)) ** 0.5 *\n            ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5;\n        sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5;\n\n        // for compat with linregw, see below\n        q = 1.0;\n    }\n\n    ss = len xes;\n    sx = sum xes;\n    sy = sum yes;\n    sxoss = sx / ss;\n\n    tes = [x - sxoss :: x <- xes];\n    st2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Weighted linear regression. Xes, yes and a list of deviations.\n */\nlinregw xes yes devs \n\t= obj\n{\n\tobj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: \n\t\t\t[x, y, sd] <- zip3 xes yes devs];\n\n\t\tsiga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (1 / st2) ** 0.5;\n\n\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\t}\n\n\twt = [sd ** -0.5 :: sd <- devs];\n\n\tss = sum wt;\n\tsx = sum [x * w :: [x, w] <- zip2 xes wt];\n\tsy = sum [y * w :: [y, w] <- zip2 yes wt];\n\tsxoss = sx / ss;\n\n\ttes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Clustering: pass in a list of points, repeatedly merge the\n * closest two points until no two points are closer than the threshold.\n * Return [merged-points, corresponding-weights]. A weight is a list of the\n * indexes we merged to make that point, ie. len weight == how significant\n * this point is.\n *\n * eg. \n *\tcluster 12 [152,154,155,42,159] == \n *\t\t[[155,42],[[1,2,0,4],[3]]]\n */\ncluster thresh points\n\t= oo_unary_function cluster_op points, is_class points\n\t// can't use [0..len points - 1], in case len points == 0\n\t= merge [points, map (converse cons []) (take (len points) [0 ..])],\n\t\tis_list points\n\t= error (_ \"bad arguments to \" ++ \"cluster\")\n{\n\tcluster_op = Operator \"cluster\" \n\t\t(cluster thresh) Operator_type.COMPOUND false;\n\n\tmerge x\n\t\t= x, m < 2 || d > thresh\n\t\t= merge [points', weights']\n\t{\n\t\t[points, weights] = x;\n\t\tm = len points;\n\n\t\t// generate indexes of all possible pairs, avoiding comparing a thing \n\t\t// to itself, and assuming that dist is reflexive\n\t\t// first index is always less than 2nd index\n\t\t// the +1,+2 makes sure we have an increasing generator, otherwise we\n\t\t// can get [3 .. 4] (for example), which will make a decreasing\n\t\t// sequence\n\t\tpairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]];\n\n\t\t// distance function\n\t\t// arg is eg. [3,1], meaning get distance from point 3 to point 1\n\t\tdist x \n\t\t\t= abs (points?i - points?j)\n\t\t{\n\t\t\t[i, j] = x;\n\t\t}\n\n\t\t// smallest distance, then the two points we merge\n\t\tp = minpos (map dist pairs);\n\t\td = dist pairs?p;\n\t\t[i, j] = pairs?p;\n\n\t\t// new point and new weight\n\t\tnw = weights?i ++ weights?j;\n\t\tnp = (points?i * len weights?i + points?j * len weights?j) / len nw;\n\n\t\t// remove element i from a list\n\t\tremove i l = take i l ++ drop (i + 1) l;\n\n\t\t// remove two old points, add the new merged one\n\t\t// i < j (see \"pairs\", above)\n\t\tpoints' = np : remove i (remove j points);\n\t\tweights' = nw : remove i (remove j weights);\n\t}\n}\n\n/* Extract the area of an image around an arrow.\n * Transform the image to make the arrow horizontal, then displace by hd and\n * vd pxels, then cut out a bit h pixels high centered on the arrow.\n */\nextract_arrow hd vd h arrow\n\t= extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im'\n{\n\t// the line as a polar vector\n\tpv = polar (arrow.width, arrow.height);\n\ta = im pv;\n\n\t// smallest rotation that will make the line horizontal\n\ta'\n\t\t= 360 - a, a > 270\n\t\t= 180 - a, a > 90\n\t\t= -a;\n\n\tim' = rotate Interpolate_bilinear a' arrow.image;\n\n\t// look at the start and end of the arrow, pick the leftmost\n\tp\n\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t= (arrow.right, arrow.bottom);\n\n\t// transform that point to im' space\n\tp' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset);\n}\n\n/* You'd think these would go in _convert, but they are not really colour ops,\n * so put them here.\n */\nrad2float image\n\t= oo_unary_function rad2float_op image, is_class image\n\t= im_rad2float image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"rad2float\")\n{\n\trad2float_op = Operator \"rad2float\" \n\t\trad2float Operator_type.COMPOUND_REWRAP false;\n}\n\nfloat2rad image\n\t= oo_unary_function float2rad_op image, is_class image\n\t= im_float2rad image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"float2rad\")\n{\n\tfloat2rad_op = Operator \"float2rad\" \n\t\tfloat2rad Operator_type.COMPOUND_REWRAP false;\n}\n\nsegment x\n\t= oo_unary_function segment_op x, is_class x\n\t= image', is_image x \n\t= error (_ \"bad arguments to \" ++ \"segment\")\n{\n\tsegment_op = Operator \"segment\" \n\t\tsegment Operator_type.COMPOUND_REWRAP false;\n\n\t[image, nsegs] = im_segment x;\n\timage' = im_copy_set_meta image \"n-segments\" nsegs;\n}\n\npoint a b\n\t= oo_binary_function point_op a b, is_class a\n\t= oo_binary'_function point_op a b, is_class b\n\t= im_read_point b x y, is_image b\n\t= [b?x?y], is_matrix b\n\t= [b?x], is_real_list b && y == 0\n\t= [b?y], is_real_list b && x == 0\n\t= error (_ \"bad arguments to \" ++ \"point\")\n{\n\tpoint_op = Operator \"point\" \n\t\t(\\a\\b Vector (point a b)) Operator_type.COMPOUND false;\n\n\t(x, y) \n\t\t= a, is_complex a;\n\t\t= (a?0, a?1), is_real_list a && is_list_len 2 a\n\t\t= error \"bad position format\";\n}\n\n/* Generate an ImageMagick (or GraphicsMagick) command suitable for \n * im_system_image. Use convert.exe in $VIPSHOME/bin, if it exists, otherwise\n * assume it's on the path somewhere.\n */\nmagick_command switch \n\t= join_sep \" \" [convert, \"\\\"%s\\\"\", switch, \"\\\"%s\\\"\"]\n{\n\tprefs = Workspaces.Preferences;\n\tuse_gm = prefs.USE_GRAPHICSMAGICK;\n\tname = if use_gm then \"gm\" else \"convert\";\n\texe = concat [name, expand \"$EXEEXT\"];\n\tvipsexe = path_absolute [expand \"$VIPSHOME\", \"bin\", exe];\n\tfinal_exe \n\t\t= vipsexe, search vipsexe != []\n\t\t= exe;\n\tconvert\t\n\t\t= join_sep \" \" [final_exe, \"convert\"], use_gm\n\t\t= final_exe;\n}\n\n/* Run a command on an image. See magick_command, for example.\n */\nsystem_image command x\n\t= oo_unary_function system_image_op x, is_class x\n\t= system x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"system_image\")\n{\n\tsystem_image_op = Operator \"system_image\" \n\t\t(system_image command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem im\n\t\t= image_out\n\t{\n\t\t[image_out, log] = \n\t\t\tim_system_image (get_image im) \"%s.tif\" \"%s.tif\" command;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.38/_types.def",
    "content": "/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary (\\a op.fn a x) this,\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// we can't call map_trinary directly, since it uses Group and we\n\t// don't support mutually recursive top-level functions :-(\n\t// copy-paste it here, keep in sync with the version in _stdenv\n\tmap_nary fn args\n\t\t= fn args, groups == []\n\t\t= Group (map process [0, 1 .. shortest - 1])\n\t{\n\t\tgroups = filter is_Group args;\n\t\n\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\tprocess n\n\t\t\t= NULL, any (map (is_noval n) args)\n\t\t\t= map_nary fn (map (extract n) args)\n\t\t{\n\t\t\textract n arg\n\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t= arg;\n\t\n\t\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t\t}\n\t}\n\n\t// need ite as a true trinary\n\tite a b c = if a then b else c;\n\n\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t];\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\n\t\t[op.fn this.value x,\n\t\t\top.type == Operator_type.COMPOUND]\n\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[is_list_len 3 value, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.item colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum \"Colour space\" Image_type.colour_spaces default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\n/* An option whose value is a string rather than a number.\n */\nOption_string caption labels item = class\n\tOption caption labels (index (equal item) labels) {\n\tOption_edit caption labels value \n\t\t= this.Option_string caption labels (labels?value);\n}\n\n/* Make an option from an enum.\n */\nOption_enum caption enum item = class\n\tOption_string caption enum.names item {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing item;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum caption enum (enum.names?value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNONE = 0;\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNONE = 0;\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n\tRAD = 6;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* Extract a column.\n\t */\n\tcolumn n = map (extract n) value;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (column col) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (column from);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = this.column 0; \n\tthings = this.column 1; \n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tHISTOGRAM = 10;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tARRAY = 27;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t$MULTIBAND => MULTIBAND,\n\t\t$B_W => B_W,\n\t\t$HISTOGRAM => HISTOGRAM,\n\t\t$XYZ => XYZ,\n\t\t$LAB => LAB,\n\t\t$CMYK => CMYK,\n\t\t$LABQ => LABQ,\n\t\t$RGB => RGB,\n\t\t$UCS => UCS,\n\t\t$LCH => LCH,\n\t\t$LABS => LABS,\n\t\t$sRGB => sRGB,\n\t\t$YXY => YXY,\n\t\t$FOURIER => FOURIER,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$ARRAY => ARRAY\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options generated from this, so match the order to the order in the\n\t * Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t$sRGB => sRGB,\n\t\t$Lab => LAB,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t$Mono => B_W,\n\t\t$sRGB => sRGB,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$Lab => LAB,\n\t\t$LabQ => LABQ,\n\t\t$LabS => LABS,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \n\t\t// \"Image v == 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\t// if one of then/else is an image, get the target format from that\n\t\t// otherwise, let the non-image objects set the target\n\t\ttarget_format \n\t\t\t= get_member_list has_format get_format x, \n\t\t\t\thas_member_list has_format x\n\t\t\t= NULL;\n\n\t\tto_image x = to_image_size width height target_bands target_format x;\n\n\t\t[then', else'] = map to_image x;\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if value then then' else else');\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nInterpolate_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\tLBB = 3;\n\tNOHALO = 4;\n\tVSQBS = 5;\n\n\t// Should introspect to get the list of interpolators :-(\n        // We can \"dir\" on VipsInterpolate to get a list of them, but we\n        // can't get i18n'd descriptions until we have more\n        // introspection stuff in nip2.\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Bilinear\", \n\t\t_ \"Bicubic\",\n\t\t_ \"Upsize: reduced halo bicubic (LBB)\",\n\t\t_ \"Upsharp: reduced halo bicubic with edge sharpening (Nohalo)\",\n\t\t_ \"Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)\"\n\t];\n\n\t/* And to vips type names.\n\t */\n\ttypes = [\n\t\t\"VipsInterpolateNearest\",\n\t\t\"VipsInterpolateBilinear\",\n\t\t\"VipsInterpolateBicubic\",\n\t\t\"VipsInterpolateLbb\",\n\t\t\"VipsInterpolateNohalo\",\n\t\t\"VipsInterpolateVsqbs\"\n\t];\n}\n\nInterpolate type options = class {\n\tvalue = vips_object_new Interpolate_type.types?type [] options;\n}\n\nInterpolate_bilinear = Interpolate Interpolate_type.BILINEAR [];\n\nInterpolate_picker default = class \n\tInterpolate interp.value [] {\n\t_vislevel = 2;\n\n\tinterp = Option \"Interpolation\" Interpolate_type.descriptions default;\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t_ \"Perceptual\" => PERCEPTUAL,\n\t\t_ \"Relative\" => RELATIVE,\n\t\t_ \"Saturation\" => SATURATION,\n\t\t_ \"Absolute\" => ABSOLUTE\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t_ \"Point\" => POINT,\n\t\t_ \"Line\" => LINE,\n\t\t_ \"Spline\" => SPLINE,\n\t\t_ \"Bar\" => BAR\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t_ \"YYYY\" => YYYY,\n\t\t_ \"XYYY\" => XYXY,\n\t\t_ \"XYXY\" => XYXY\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [$format => Plot_format.XYYY] value {\n}\n\n/* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate\n * empty slots, for example.\n */\nNULL = class \n\t_Object {\n\too_binary_table op x = [\n\t\t// the only operation we allow is equality .. use pointer equality,\n\t\t// this lets us test a == NULL and a != NULL\n\t\t[this === x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"equal\"],\n\t\t[this !== x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"not_equal\"]\n\t] ++ super.oo_binary_table op x;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.40/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t[_L, _a, _b] = default_value;\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n\n\tCCT_colour = class\n\t\tMenuaction (_ \"Colour from CCT\") (_ \"pick colour by CCT\") {\n\t\taction = widget 6500;\n\n\t\twidget x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tT = Scale \"CCT\" 1800 25000 x;\n\n\t\t\t_result = colour_from_temp (to_real T);\n\n\t\t\tColour_edit space value \n\t\t\t\t= widget (temp_from_colour (Colour space value));\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Convert to\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Tag as\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum (_ \"Old whitepoint\") Whitepoints \"D65\";\n\t\t\tnew_white = Option_enum (_ \"New whitepoint\") Whitepoints \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCCT_item = class\n\t\tMenuaction (_ \"Calculate temperature\")\n\t\t\t(_ \"estimate CCT using the McCamy approximation\") {\n\t\taction z = map_unary temp_from_colour z;\n\t}\n\n\tColour_item = Colour_new_item.CCT_colour;\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= monitor_profile, has_bands image && get_bands image == 3\n\t\t= print_profile;\n\trender_intents = Option_enum (_ \"Render intent\") Render_intent.names\n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_rad_item = class\n\tMenupullright (_ \"_Radiance\") (_ \"convert to and from Radiance packed format\") {\n\tUnpack_item = class\n\t\tMenuaction (_ \"Unpack\") \n\t\t\t(_ \"unpack Radiance format to float\") {\n\t\taction x = map_unary rad2float x;\n\t}\n\n\tPack_item = class\n\t\tMenuaction (_ \"Pack\") \n\t\t\t(_ \"pack 3-band float to Radiance format\") {\n\t\taction x = map_unary float2rad x;\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n        // get a representative image from an arg\n        get_image x\n            = get_image x.value?0, is_Group x\n            = x;\n\n        _im = get_image x; \n\t\tsample = measure_draw (to_real pacross) (to_real pdown) \n\t\t\t\t(to_real measure) _im;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure_sample (to_real pacross) (to_real pdown) \n\t\t\t\t\t(to_real measure) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.40/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 1.5;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 50;\n\t\t\tfs = Scale \"Sharpen flat areas by\" (-2) 5 1;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" (-2) 5 2;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tlayers = Scale \"Layers\" 1 100 10;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\", \"Approximate\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf, aconvsep layers]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\t\t\trotate = Option \"Rotate\" [\n\t\t\t\t\"Don't rotate\", \n\t\t\t\t\"4 x 45 degrees\", \n\t\t\t\t\"8 x 45 degrees\", \n\t\t\t\t\"2 x 90 degrees\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_lindetect, !separable && type == 0 && rotate == 1\n\t\t\t\t\t\t= im_compass, !separable && type == 0 && rotate == 2\n\t\t\t\t\t\t= im_gradient, !separable && type == 0 && rotate == 3\n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_conv_f, !separable && type == 1\n\t\t\t\t\t\t= im_convsep_f, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 4) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width.expr window_height.expr in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\nFilter_hough_item = class\n\tMenupullright \"_Hough Transform\" \"transform to parameter space\" {\n\tLine_item = class\n\t\tMenuaction \"_Line\" \"find straight line Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpspace_width = Expression \"Parameter space width\" 64;\n\t\t\tpspace_height = Expression \"Parameter space height\" 64;\n\n\t\t\t_result \n\t\t\t\t= map_unary line a \n\t\t\t{\n\t\t\t\tline a \n\t\t\t\t\t= hough_line \n\t\t\t\t\t\t(to_real pspace_width) (to_real pspace_height) a;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class\n\t\tMenuaction \"_Circle\" \"find circle Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Expression \"Scale down parameter space by\" 10;\n\t\t\tmin_radius = Expression \"Minimum radius\" 10;\n\t\t\tmax_radius = Expression \"Maximum radius\" 30;\n\n\t\t\t_result \n\t\t\t\t= map_unary circle a \n\t\t\t{\n\t\t\t\tcircle a \n\t\t\t\t\t= hough_circle (to_real scale) (to_real min_radius)\n\t\t\t\t\t\t(to_real max_radius) a;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_greyc_item = class \n\tMenupullright \"_GREYCstoration\" \"noise-removing filter\" {\n\tDenoise_item = class \n\t\tMenuaction \"Denoise\" \"Noise-removing filter\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\titerations = Scale \"Iterations\" 1 5 1;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 40;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.9;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.15;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.6;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.1;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) x;\n\t\t}\n\t}\n\n\tEnlarge_item = class\n\t\tMenuaction \"Enlarge\" \"Enlarge image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Enlarge\" 1 10 3;\n\t\t\titerations = Scale \"Iterations\" 1 5 3;\n\t\t\tamplitude = Scale \"Amplitude\" 1 100 20;\n\t\t\tsharpness = Scale \"Sharpness\" 0 3 0.2;\n\t\t\tanisotropy = Scale \"Anisotropy\" 0 1 0.9;\n\t\t\talpha = Scale \"Noise scale\" 0 5 0.1;\n\t\t\tsigma = Scale \"Geometry regularity\" 0 2 1.5;\n\t\t\tdl = Scale \"Spatial integration step\" 0 1 0.8;\n\t\t\tda = Scale \"Angular integration step\" 0 90 30;\n\t\t\tgauss_prec = Scale \"Precision\" 1 10 2;\n\t\t\tinterpolation = Option \"Interpolation\" \n\t\t\t\t[\"Nearest-neighbour\", \"Bilinear\", \"Runge-Kutta\"] 0;\n\t\t\tfast_approx = Toggle \"Fast approximation\" true;\n\n\t\t\t_result = greyc \n\t\t\t\t(to_real iterations) (to_real amplitude) (to_real sharpness)\n\t\t\t\t(to_real anisotropy) (to_real alpha) (to_real sigma) \n\t\t\t\t(to_real dl) (to_real da) \n\t\t\t\t(to_real gauss_prec) (to_real interpolation) \n\t\t\t\t(to_real fast_approx) \n\t\t\t\t\t(resize Interpolate_bilinear\n\t\t\t\t\t\t(to_real scale) (to_real scale) x);\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image\" \"use an image to blend two objects\" {\n\t\taction a b c = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ti = Toggle \"Invert mask\" false;\n\n\t\t\t_result \n\t\t\t\t= map_trinary process a b c\n\t\t\t{\n\t\t\t\tprocess a b c \n\t\t\t\t\t= blend condition in1 in2, !i\n\t\t\t\t\t= blend (invert condition) in1 in2\n\t\t\t\t{\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t\t= false,\n\t\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t\t= true;\n\t\t\t\t\t[condition, in1, in2] = sortc compare [a, b, c];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"_Alpha\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t_ \"Normal\" => NORMAL,\n\t\t\t_ \"If Lighter\" => IFLIGHTER,\n\t\t\t_ \"If Darker\" => IFDARKER,\n\t\t\t_ \"Multiply\" => MULTIPLY,\n\t\t\t_ \"Add\" => ADD,\n\t\t\t_ \"Subtract\" => SUBTRACT,\n\t\t\t_ \"Screen\" => SCREEN,\n\t\t\t_ \"Burn\" => BURN,\n\t\t\t_ \"Soft Light\" => SOFTLIGHT,\n\t\t\t_ \"Hard Light\" => HARDLIGHT,\n\t\t\t_ \"Lighten\" => LIGHTEN,\n\t\t\t_ \"Darken\" => DARKEN,\n\t\t\t_ \"Dodge\" => DODGE,\n\t\t\t_ \"Reflect\" => REFLECT,\n\t\t\t_ \"Freeze\" => FREEZE,\n\t\t\t_ \"Bitwise OR\" => OR,\n\t\t\t_ \"Bitwise AND\" => AND\n\t\t];\n\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum \"Blend mode\" names \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\t[mono, colour] = \n\t\t\t\t\tsortc (const (is_colour_type @ get_type)) [a, b];\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t_ \"Grey\",\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t_ \"North-west\",\n\t\t\t\t_ \"North\",\n\t\t\t\t_ \"North-east\",\n\t\t\t\t_ \"West\",\n\t\t\t\t_ \"Centre\",\n\t\t\t\t_ \"East\",\n\t\t\t\t_ \"South-west\",\n\t\t\t\t_ \"South\",\n\t\t\t\t_ \"South-east\",\n\t\t\t\t_ \"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.40/Histogram.def",
    "content": "Hist_new_item = class\n\tMenupullright \"_New\" \"new histogram\" {\n\tHist_item = class\n\t\tMenuaction \"_Identity\" \"make an identity histogram\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\t_result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d);\n\t\t}\n\t}\n\n\tHist_new_from_matrix = Matrix_buildlut_item; \n\n\tHist_from_image_item = class\n\t\tMenuaction \"Ta_g Image As Histogram\" \"set image Type to Histogram\" {\n\t\taction x = hist_tag x;\n\t}\n\n\tTone_item = class \n\t\tMenuaction \"_Tone Curve\" \"make a new tone mapping curve\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\t_result \n\t\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t\t{\n\t\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_convert_to_hist_item = class \n\tMenuaction \"Con_vert to Histogram\" \"convert anything to a histogram\" {\n\taction x = hist_tag (to_image x);\n}\n\nHist_find_item = class \n\tMenupullright \"_Find\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n\n\tIndexed_item = class\n\t\tMenuaction \"_Indexed\" \n\t\t\t\"use a 1-band index image to pick bins for an n-band image\" {\n\t\taction x y \n\t\t\t= map_binary map x y\n\t\t{\n\t\t\tmap a b\n\t\t\t\t= hist_find_indexed index im\n\t\t\t{\n\t\t\t\t[im, index] = sortc (const is_index) [a, b];\n\n\t\t\t\tis_index x\n\t\t\t\t\t= has_image x && b == 1 && \n\t\t\t\t\t\t(f == Image_format.UCHAR || f == Image_format.USHORT)\n\t\t\t\t{\n\t\t\t\t\tim = get_image x;\n\t\t\t\t\tb = get_bands x;\n\t\t\t\t\tf = get_format x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\t[im, hist] = sortc (const is_hist) [a, b];\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Integrate\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate\" \n\t\t\"find point-to-point differences (inverse of Integrate)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_inv_item = class \n\tMenuaction \"In_vert\" \"invert a histogram\" {\n\taction x = map_unary hist_inv x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\tarea = extract_arrow \n\t\t\t\t\tdisplace.value vdisplace.value width.value arrow;\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize Interpolate_bilinear 1 (1 / width.value) area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary (extract_arrow \n\t\t\t\tdisplace.value vdisplace.value width.value) x;\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcaption = Expression \"Chart caption\" \"none\";\n\t\tformat = Option_enum \"Format\" Plot_format.names \"YYYY\";\n\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\t\txcaption = Expression \"X axis caption\" \"none\";\n\t\tycaption = Expression \"Y axis caption\" \"none\";\n\t\tseries_captions = Expression \"Series captions\" [\"Band 0\"];\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => style.value, $format => format.value] ++ \n\t\t\t\t\trange ++ captions;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\tcaptions \n\t\t\t\t= concat (map test caption_options) ++ \n\t\t\t\t  [$series_captions => series_captions.expr]\n\t\t\t{\n\t\t\t\tcaption_options = [\n\t\t\t\t\t$caption => caption.expr,\n\t\t\t\t\t$xcaption => xcaption.expr,\n\t\t\t\t\t$ycaption => ycaption.expr\n\t\t\t\t];\n\t\t\t\ttest x\n\t\t\t\t\t= [], value == \"none\"\n\t\t\t\t\t= [option_name => value]\n\t\t\t\t{\n\t\t\t\t\t[option_name, value] = x;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow 0 0 1 x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.40/Image.def",
    "content": "Image_new_item = class Menupullright \"_New\" \"make new things\" {\n\tImage_black_item = class Menuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \"Image type\"\n\t\t\t\tImage_type.type_names \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region on image using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\t[target, x] = sortc compare [a, b];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\nImage_number_format_item = class\n\tMenupullright \"_Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_header_item = class \n\tMenupullright \"_Header\" \"do stuff to the image header\" {\n\n\tImage_get_item = class\n\t\tMenupullright \"_Get\" \"get header fields\" {\n\n\t\t// the header fields we can get\n\t\tfields = class {\n\t\t\ttype = 0;\n\t\t\twidth = 1;\n\t\t\theight = 2;\n\t\t\tformat = 3;\n\t\t\tbands = 4;\n\t\t\txres = 5;\n\t\t\tyres = 6;\n\t\t\txoffset = 7;\n\t\t\tyoffset = 8;\n\t\t\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t$width => width,\n\t\t\t\t$height => height,\n\t\t\t\t$bands => bands,\n\t\t\t\t$format => format,\n\t\t\t\t$type => type,\n\t\t\t\t$xres => xres,\n\t\t\t\t$yres => yres,\n\t\t\t\t$xoffset => xoffset,\n\t\t\t\t$yoffset => yoffset,\n\t\t\t\t$coding => coding\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum (_ \"Field\") field_names name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tCustom_item = class\n\t\t\tMenuaction \"C_ustom\" \"get any header field\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tfield = String \"Field\" \"Xsize\";\n\t\t\t\tparse = Option \"Parse\" [\n\t\t\t\t\t\"No parsing\",\n\t\t\t\t\t\"Parse string as integer\",\n\t\t\t\t\t\"Parse string as real\",\n\t\t\t\t\t\"Parse string as hh:mm:ss\"\n\t\t\t\t] 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary (wrap @ process @ get_header field.value) x\n\t\t\t\t{\n\t\t\t\t\tparse_str parse str = parse (split is_space str)?0;\n\n\t\t\t\t\tparse_field name cast parse x\n\t\t\t\t\t\t= cast x, is_number x\n\t\t\t\t\t\t= parse_str parse x, is_string x\n\t\t\t\t\t\t= error (\"not \" ++ name);\n\n\t\t\t\t\tget_int = parse_field \"int\" \n\t\t\t\t\t\tcast_signed_int parse_int;\n\t\t\t\t\tget_float = parse_field \"float\" \n\t\t\t\t\t\tcast_float parse_float;\n\t\t\t\t\tget_time = parse_field \"hh:mm:ss\" \n\t\t\t\t\t\tcast_signed_int parse_time;\n\n\t\t\t\t\twrap x\n\t\t\t\t\t\t= Real x, is_real x\n\t\t\t\t\t\t= Vector x, is_real_list x\n\t\t\t\t\t\t= Image x, is_image x\n\t\t\t\t\t\t= Bool x, is_bool x\n\t\t\t\t\t\t= Matrix x, is_matrix x\n\t\t\t\t\t\t= String \"String\" x, is_string x\n\t\t\t\t\t\t= List x, is_list x\n\t\t\t\t\t\t= x;\n\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tget_int, \n\t\t\t\t\t\tget_float,\n\t\t\t\t\t\tget_time\n\t\t\t\t\t]?parse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum \"Image type\" Image_type.type_names \n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_cache_item = class\n\tMenuaction \"C_ache\" \"cache calculated image pixels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttile_width = Number \"Tile width\" 128;\n\t\ttile_height = Number \"Tile height\" 128;\n\t\tmax_tiles = Number \"Maximum number of tiles to cache\" (-1);\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= cache (to_real tile_width) (to_real tile_height) \n\t\t\t\t\t(to_real max_tiles) image;\n\t\t}\n\t}\n}\n\n#separator\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\t// we can't use id here since we want to \"declass\"\n\t\t\t\t\t\t// the members of x ... consider if x is a crop class,\n\t\t\t\t\t\t// for example, we don't want to inherit from crop, we\n\t\t\t\t\t\t// want to make a new image class\n\t\t\t\t\t\trot180 @ rot180,\n\t\t\t\t\t\trot90,\n\t\t\t\t\t\trot180,\n\t\t\t\t\t\trot270\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate interp angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary straighten x\n\t\t\t\t{\n\t\t\t\t\tstraighten arrow\n\t\t\t\t\t\t= rotate interp angle'' arrow.image\n\t\t\t\t\t{\n\t\t\t\t\t\tx = arrow.width;\n\t\t\t\t\t\ty = arrow.height;\n\t\t\n\t\t\t\t\t\tangle = im (polar (x, y));\n\t\t\n\t\t\t\t\t\tangle'\n\t\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t\t= angle;\n\t\t\n\t\t\t\t\t\tangle''\n\t\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize interp xfactor yfactor image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\taspect = Toggle \"Break aspect ratio\" false;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize interp h v image, aspect\n\t\t\t\t\t\t= resize interp fac fac image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac > yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\tmin_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac < yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\t[h, v] = [\n\t\t\t\t\t\t\tmax_factor, \n\t\t\t\t\t\t\tmin_factor, \n\t\t\t\t\t\t\t[xfac, 1], \n\t\t\t\t\t\t\t[1, yfac]]?which;\n\n\t\t\t\t\t\tfac \n\t\t\t\t\t\t\t= h, v == 1\n\t\t\t\t\t\t\t= v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_within_item = class\n\t\t\tMenuaction \"Size _Within\" \"size to fit within a rectangle\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\t// the rects we size to fit within\n\t\t\t\t_rects = [\n\t\t\t\t\t[2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], \n\t\t\t\t\t[1280, 1024], [1024, 768], [800, 600], [640, 480] \n\t\t\t\t];\n\n\t\t\t\twithin = Option \"Fit within (pixels)\" (\n\t\t\t\t\t[print w ++ \" x \" ++ print h :: [w, h] <- _rects] ++\n\t\t\t\t\t[\"Custom\"]\n\t\t\t\t) 4;\n\t\t\t\tcustom_width = Expression \"Custom width\" 1000;\n\t\t\t\tcustom_height = Expression \"Custom height\" 1000;\n\t\t\t    size = Option \"Page size\" [\n\t\t\t\t\t\"Full page\", \"Half page\", \"Quarter page\" \n\t\t\t\t] 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t \t_result\n\t\t\t\t \t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\txdiv = [1, 2, 2]?size;\n\t\t\t\t\tydiv = [1, 1, 2]?size;\n\t\t\t\t\tallrect = _rects ++ [\n\t\t\t\t\t\t[custom_width.expr, custom_height.expr]\n\t\t\t\t\t];\n\t\t\t\t\t[width, height] = allrect?within;\n\n\t\t\t\t\tprocess x\n\t\t\t\t\t\t= resize interp fac fac x, fac < 1\n\t\t\t\t\t\t= x\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = (width / xdiv) / x.width;\n\t\t\t\t\t\tyfac = (height / ydiv) / x.height;\n\t\t\t\t\t\tfac = min_pair xfac yfac;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\" [\"Nearest\", \"Bilinear\"] 1;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_trn {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t[sample', trn, err] = transform_search \n\t\t\t\t\tmax_err max_iter order interp wrap\n\t\t\t\t\tsample reference;\n\t\t\t\ttransformed_image = Image sample';\n\t\t\t\t_trn = Transform trn reference.width reference.height;\n\t\t\t\tfinal_error = err;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\t[i, t] = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tBandwise_item = Image_join_item.Bandwise_item;\n\n    sep1 = Menuseparator;\n\n\tBandand_item = class\n\t\tMenuaction \"Bitwise Band AND\" \"bitwise AND of image bands\" {\n\t\taction x = bandand x;\n\t}\n\n\tBandor_item = class\n\t\tMenuaction \"Bitwise Band OR\" \"bitwise OR of image bands\" {\n\t\taction x = bandor x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldl1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x \n\t\t= crop x [l, t, w, h]\n\t{\n\t\tfields = [\n\t\t\t[has_left, get_left, 0],\n\t\t\t[has_top, get_top, 0],\n\t\t\t[has_width, get_width, 100],\n\t\t\t[has_height, get_height, 100]\n\t\t];\n\n\t\t[l, t, w, h] \n\t\t\t= map get_default fields\n\t\t{\n\t\t\tget_default line\n\t\t\t\t= get x, has x\n\t\t\t\t= default\n\t\t\t{\n\t\t\t\t[has, get, default] = line;\n\t\t\t}\n\t\t}\n\t}\n\n\tcrop x geo = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tl = Expression \"Crop left\" ((int) (geo?0 + geo?2 / 4));\n\t\tt = Expression \"Crop top\" ((int) (geo?1 + geo?3 / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (geo?2 / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (geo?3 / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t[_a', _b'] = sortc _pred [a, b];\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_draw_item = class \n\tMenupullright \"_Draw\" \"draw lines, circles, rectangles, floods\" {\n\tLine_item = class Menuaction \"_Line\" \"draw line on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tx1 = Expression \"Start x\" 0;\n\t\t\ty1 = Expression \"Start y\" 0;\n\t\t\tx2 = Expression \"End x\" 100;\n\t\t\ty2 = Expression \"End y\" 100;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary line x\n\t\t\t{\n\t\t\t\tline im \n\t\t\t\t\t= draw_line x1 y1 x2 y2 i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tRect_item = class Menuaction \"_Rectangle\" \"draw rectangle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\trx = Expression \"Left\" 50;\n\t\t\try = Expression \"Top\" 50;\n\t\t\trw = Expression \"Width\" 100;\n\t\t\trh = Expression \"Height\" 100;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\tt = Scale \"Line thickness\" 1 50 3;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary rect x\n\t\t\t{\n\t\t\t\trect im \n\t\t\t\t\t= draw_rect_width rx ry rw rh f t i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class Menuaction \"_Circle\" \"draw circle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcx = Expression \"Centre x\" 100;\n\t\t\tcy = Expression \"Centre y\" 100;\n\t\t\tr = Expression \"Radius\" 50;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary circle x\n\t\t\t{\n\t\t\t\tcircle im \n\t\t\t\t\t= draw_circle cx cy r f i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tFlood_item = class Menuaction \"_Flood\" \"flood bounded area of image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsx = Expression \"Start x\" 100;\n\t\t\tsy = Expression \"Start y\" 100;\n\n\t\t\te = Option \"Flood while\" [\n\t\t\t\t\"Not equal to ink\",\n\t\t\t\t\"Equal to start point\"\n\t\t\t] 0;\n\n\t\t\t// pick a default ink that won't flood, if we can\n\t\t\ti \n\t\t\t\t= Expression \"Ink\" default_ink\n\t\t\t{\n\t\t\t\tdefault_ink\n\t\t\t\t\t= [0], ! has_image x\n\t\t\t\t\t= pixel;\n\t\t\t\tpixel = map mean (bandsplit (extract_area sx sy 1 1 im));\n\t\t\t\tim = get_image x;\n\t\t\t}\n\n\t\t\t_result \n\t\t\t\t= map_unary flood x\n\t\t\t{\n\t\t\t\tflood im \n\t\t\t\t\t= draw_flood sx sy i.expr im, e == 0\n\t\t\t\t\t= draw_flood_blob sx sy i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tDraw_scalebar_item = class Menuaction \"_Scale\" \"draw scale bar\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpx = Expression \"Left\" 50;\n\t\t\tpy = Expression \"Top\" 50;\n\t\t\twid = Expression \"Width\" 100;\n\t\t\tthick = Scale \"Line thickness\" 1 50 3;\n\t\t\ttext = String \"Dimension text\" \"50μm\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\tpos = Option \"Position Text\" [\"Above\", \"Below\"] 1;\n\t\t\tvp = Option \"Dimension by\" [\n\t\t\t\t\"Inner Vertical Edge\", \n\t\t\t\t\"Centre of Vertical\", \n\t\t\t\t\"Outer Vertical Edge\"\n\t\t\t] 1;\n            dpi = Expression \"DPI\" 100;\n            ink = Colour \"Lab\" [50,0,0];\n      \n            _result\n                = map_unary process x\n            {\n                process im\n                    = blend (Image scale) ink' im\n                {\n                    // make an ink compatible with the image\n                    ink' = colour_transform_to (get_type im) ink;\n\n                    x = to_real px;\n                    y = to_real py;\n                    w = to_real wid;\n                    d = to_real dpi;\n\n                    t = floor thick;\n\n                    bg = image_new (get_width im) (get_height im) (get_bands im)\n                        (get_format im) (get_coding im) (get_type im) 0 0 0;\n                    draw_block x y w t im =\n                        draw_rect_width x y w t true 1 [255] im;\n                    label = im_text text.value font.value w 1 d;\n                    lw = get_width label;\n                    lh = get_height label;\n                    ly = [y - lh - t, y + 2 * t]?pos;\n                    vx = [\n\t\t\t\t\t\t[x - t, x + w],\n\t\t\t\t\t\t[x - t / 2, x + w - t / 2],\n\t\t\t\t\t\t[x, x + w - t]\n\t\t\t\t\t]?vp;\n\n\t\t\t\t\tscale = (draw_block x y w t @\n\t\t\t\t\t\tdraw_block vx?0 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tdraw_block vx?1 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tinsert_noexpand (x + w / 2 - lw / 2) ly label)\n\t\t\t\t\t\tbg;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise Join\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t// we can't use map_unary since chop-into-tiles returns a group of\n\t\t\t// groups and we want to be able to reassemble that\n\t\t\t// TODO: chop-into-tiles should return an array class which\n\t\t\t// displays as group but does not have the looping behaviour?\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n\n\tArrayFL_item = class\n\t\tMenuaction \"_Array from List\"\n\t\t\t\"join a list of images into a single image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tncol = Number \"Max. Number of Columns\" 1;\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t_l \n\t\t\t\t= split_lines ncol.value x.value, is_Group x\n\t\t\t\t= split_lines ncol.value x;\n\n\t\t\t_result\n\t\t\t\t= (image_set_origin 0 0 @\n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value\n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list _l));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tGaussian_item = class \n\t\tMenuaction \"Gaussian _Noise\" \"make an image of gaussian noise\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t_result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) \n\t\t\t\tmean.value deviation.value);\n\t\t}\n\t}\n\n\tFractal_item = class \n\t\tMenuaction \"_Fractal\" \"make a fractal image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t}\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n\tColour_atlas_item = class\n\tMenuaction \"_Colour Atlas\"\n\t\t\"make a grid of patches grouped around a colour\" {\n\t\taction = class \n\t\t\t_result {   \n\t\t\t_vislevel = 3;\n       \n\t\t\tstart = Colour_picker \"Lab\" [50,0,0];\n\t\t\tnstep = Expression \"Number of steps\" 9;\n\t\t\tssize = Expression \"Step size\" 10; \n\t\t\tpsize = Expression \"Patch size\" 32;\n\t\t\tsepsize = Expression \"Separator size\" 4;\n\t\n\t\t\t_result\n\t\t\t\t= colour_transform_to (get_type start) blocks'''\n\t\t\t{\n\t\t\t\tsize = (to_real nstep * 2 + 1) * to_real psize - \n\t\t\t\t\tto_real sepsize;\n\t\t\t\txy = make_xy size size; \n\n\t\t\t\txy_grid = (xy % to_real psize) < \n\t\t\t\t\t(to_real psize - to_real sepsize);\n\t\t\t\tgrid = xy_grid?0 & xy_grid?1;\n\n\t\t\t\tblocks = (int) (to_real ssize * ((int) (xy / to_real psize)));\n\t\t\t\tlab_start = colour_transform_to Image_type.LAB start;\n\t\t\t\tblocks' = blocks - to_real nstep * to_real ssize + \n\t\t\t\t\tVector (tl lab_start.value);\n\t\t\t\tblocks'' = hd lab_start.value ++ Image blocks';\n\t\t\t\tblocks''' \n\t\t\t\t\t= image_set_type Image_type.LAB blocks'', Image grid\n\t\t\t\t\t= 0;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.40/Magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate Magick.def\n   13-Apr-2014 snibgo\n     Put \"new image\" items into sub-menu.\n     New class VirtualPixlBack.\n   17-Apr-2014 snibgo\n     Many small changes.\n     A few new menu options.\n     Created sub-menu for multi-input operations.\n   3-May-2014 jcupitt\n     Put quotes around ( in shadow to help unix\n\n   Last update: 17-Apr-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n*/\n\n// We don't need Noop.\n/*===\nMagick_noop_item = class\n\tMenuaction \"_Noop\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_testPar_item = class\n\tMenuaction \"_TestPar\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"( +clone ) +append \",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/* Removed Read_item and Write_item, much better to use nip2 load/save image.\n * Plus they can load all libMagick formats anyway.\n */\n\n\n// Put \"new image\" items into sub-menu\nMagick_NewImageMenu_item = class\n\tMenupullright \"_New image\" \"make a new image\" {\n\n\tMagick_newcanvas_item = class\n\t\tMenuaction \"_Solid colour\" \"make image of solid colour\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tcolour = Magick.generalcol_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"\\\"canvas:\" ++ colour._flag ++ \"\\\"\", \n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_builtin_item = class\n\t\tMenuaction \"_Built-in image\" \"create a built-in image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbuiltin = Magick.builtin_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tbuiltin._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_gradient_item = class\n\t\tMenuaction \"_Gradient\" \"make a linear gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\ttopColour = Magick.generalcol_widget;\n\t\t\tbottomColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"gradient:\", \n\t\t\t\t\ttopColour._flag, \"-\", bottomColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_hald_item = class\n\t\tMenuaction \"_Hald-clut image\" \"create an identity hald-clut image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torder = Expression \"order\" 8;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"hald:\" ++ print order.expr,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_pattern_item = class\n\t\tMenuaction \"_Pattern\" \"create pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tpattern = Magick.pattern_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tpattern._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_plasma_item = class\n\t\tMenuaction \"_Plasma image\" \"create plasma image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\t// FIXME? ColourA-ColourB.\n\t\t\t// FIXME? Allow plasma:fractal?\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"plasma:\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_radialgradient_item = class\n\t\tMenuaction \"_Radial gradient\" \n\t\t\t\"make a radial gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tinnerColour = Magick.generalcol_widget;\n\t\t\touterColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"radial-gradient:\", \n\t\t\t\t\tinnerColour._flag, \"-\", outerColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n}  // end Magick_NewImageMenu_item\n\n\nMagick_MultiMenu_item = class\n\tMenupullright \"_Multiple inputs\" \"make an image from multiple images\" {\n\n\tMagick_composite_item = class\n\t\tMenuaction \"_Composite\" \"composite two images (without mask)\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag,\n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_compositeMask_item = class\n\t\tMenuaction \"_Composite masked\" \"composite two images (with mask)\" {\n\t\taction x y z = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag, \n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system3 command x y z; \n\t\t}\n\t}\n\n\t// FIXME: other operations like remap that take another image as arguments are:\n\t// mask (pointless?), texture, tile (pointless?)\n\n\t// FIXME: operations that take a filename that isn't an image:\n\t// cdl, profile\n\n\tMagick_clut_item = class\n\t\tMenuaction \"_Clut\" \"replace values using second image as colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// FIXME: uses -intensity \"when mapping greyscale CLUT image to alpha channel if set by -channels\"\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_haldclut_item = class\n\t\tMenuaction \"_Hald clut\" \"replace values using second image as Hald colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-hald-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\n\t// Encipher and decipher: key files can be text or image files.\n\n\tMagick_encipher_item = class\n\t\tMenuaction \"_Encipher/Decipher\" \"encipher or decipher an image image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname = Pathname \"Read key file\" \"\";\n\t\t\tisDecipher = Toggle \"Decipher\" false;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname.value == \"\" then \"\" else (\n\t\t\t\t\t( if isDecipher then \"-decipher \" else \"-encipher \") ++\n\t\t\t\t\t( \"\\\"\" ++ pathname.value ++ \"\\\"\" )\n\t\t\t\t),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_profile_item = class\n\t\tMenuaction \"_Profile\" \"assigns/applies an ICC profile\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname1 = Pathname \"Read profile file\" \"\";\n\t\t\tpathname2 = Pathname \"Read profile file\" \"\";\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname1.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname1.value ++ \"\\\"\"),\n\t\t\t\tif pathname2.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname2.value ++ \"\\\"\"),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_remap_item = class\n\t\tMenuaction \"_Remap\" \"reduce colours to those in another image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-remap\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n}  // end Magick_MultiMenu_item\n\n\nMagick_image_type_item = class\n\tMenuaction \"_Image Type\" \"change image type\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\timagetype = Magick.imagetype_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\timagetype._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nsep2 = Menuseparator;\n\nMagick_alpha_item = class\n\tMenuaction \"_Alpha\" \"add/remove alpha channel\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\talpha = Magick.alpha_widget; \n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\talpha._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_annotate_item = class\n\tMenuaction \"_Annotate\" \"add text annotation\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttext = Magick.text_widget;\n\t\tfont = Magick.Font_widget;\n\t\tgeometry = Magick.AnnotGeometry_widget; \n\t\tgravity = Magick.gravity_widget; \n\t\tforeground = Magick.foreground_widget;\n\t\tundercol = Magick.undercol_widget;\n\t\tantialias = Magick.antialias_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfont._flag,\n\t\t\tantialias._flag,\n\t\t\tgravity._flag,\n\t\t\tforeground._flag,\n\t\t\tundercol._flag,\n\t\t\t\"-annotate\", \n\t\t\tgeometry._flag, \n\t\t\t\"\\\"\" ++ text.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoGamma_item = class\n\tMenuaction \"_AutoGamma\" \"automatic gamma\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-gamma\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoLevel_item = class\n\tMenuaction \"_AutoLevel\" \"automatic level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-level\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_blurSharpMenu_item = class\n\tMenupullright \"_Blur/Sharpen\" \"blur and sharpen\" {\n\n\tMagick_adaptive_blur_item = class\n\t\tMenuaction \"_Adaptive Blur\" \"blur less near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\t// note: adaptive-blur doesn't regard VP.\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-adaptive-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blur_item = class\n\t\tMenuaction \"_Blur\" \"blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_gaussianBlur_item = class\n\t\tMenuaction \"_Gaussian Blur\" \"blur with a Gaussian operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-gaussian-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_motionBlur_item = class\n\t\tMenuaction \"_Motion Blur\" \"simulate motion blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tangle = Scale \"angle\" (-360) 360 0;\n\t\t\tchannels = Magick.ch_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-motion-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_rotationalBlur_item = class\n\t\tMenuaction \"_RotationalBlur\" \"blur around the centre\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-radial-blur\", \n\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_selectiveBlur_item = class\n\t\tMenuaction \"_Selective Blur\" \"blur where contrast is less than or equal to threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-selective-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++  \"+\" ++\n\t\t\t\t\tprint threshold.value ++ \"%%\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMagick_adaptive_sharpen_item = class\n\t\tMenuaction \"_Adaptive Sharpen\" \"sharpen more near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\t\"-adaptive-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_sharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"sharpen\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_unsharpen_item = class\n\t\tMenuaction \"_Unsharp\" \"sharpen with unsharp mask\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tgain = Scale \"Gain\" (-10) 10 1;\n\t\t\tthreshold = Scale \"Threshold\" 0 1 0.05;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-unsharp\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint gain.value ++ \"+\" ++\n\t\t\t\t\tprint threshold.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end BlurSharpMenu_item\n\n\nMagick_border_item = class\n\tMenuaction \"_Border\" \"add border of given colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcompose = Magick.compose_widget;\n\t\twidth = Expression \"Width\" 3;\n\t\tbordercol = Magick.bordercol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag,\n\t\t\tbordercol._flag,\n\t\t\t\"-border\", \n\t\t\tprint width.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_brightCont_item = class\n\tMenuaction \"_Brightness-contrast\" \"adjust the brightness and/or contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbri = Scale \"brightness\" (-100) 100 0;\n\t\tcon = Scale \"contrast\" (-100) 100 0;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-brightness-contrast\", \n\t\t\tprint bri.value ++ \"x\" ++ print con.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// Note: canny requires ImageMagick 6.8.9-0 or later.\n\nMagick_canny_item = class\n\tMenuaction \"_Canny\" \"detect a wide range of edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tlowPc = Scale \"lower percent\" 0 100 10;\n\t\thighPc = Scale \"lower percent\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-canny\", \n\t\t\tconcat [\"\\\"\",\n\t\t\t\tprint radius.value ++ \"x\" ++ \n\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\tprint lowPc.value ++ \"%%+\" ++\n\t\t\t\tprint highPc.value ++ \"%%\" ++ \"\\\"\"\n\t\t\t],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_charcoal_item = class\n\tMenuaction \"_Charcoal\" \"simulate a charcoal drawing\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tfactor = Scale \"factor\" 0 50 1;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-charcoal\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_chop_item = class\n\tMenuaction \"_Chop\" \"remove pixels from the interior\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-chop\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorize_item = class\n\tMenuaction \"_Colorize\" \"colorize by given amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tval = Scale \"value\" 0 100 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-colorize\", \n\t\t\tprint val.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colors_item = class\n\tMenuaction \"_Colors\" \"reduce number of colors\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\t\tquantize = Magick.colorspace_widget;\n\t\tcolors = Expression \"Colours\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-quantize\", quantize._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\tdither._flag,\n\t\t\t\"-colors\", \n\t\t\tprint colors.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: color-matrix?\n\nMagick_colorspace_item = class\n\tMenuaction \"_Colourspace\" \"convert to arbitrary colourspace\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolsp = Magick.colorspace_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-colorspace\",\n\t\t\tcolsp._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorspaceGray_item = class\n\tMenuaction \"_Colourspace gray\" \"convert to gray using given intensity method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-colorspace gray\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrast_item = class\n\tMenuaction \"_Contrast\" \"increase or reduce the contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tisReduce = Toggle \"reduce contrast\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t(if isReduce then \"+\" else \"-\") ++ \"contrast\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrastStretch_item = class\n\tMenuaction \"_Contrast stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-contrast-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: convolve (bias, kernel)\n\nMagick_crop_item = class\n\tMenuaction \"_Crop\" \"cut out a rectangular region\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-crop\",\n\t\t\tgeometry._flag,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_deskew_item = class\n\tMenuaction \"_Deskew\" \"straighten the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\t// FIXME: toggle auto-crop?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-deskew\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_despeckle_item = class\n\tMenuaction \"_Despeckle\" \"reduce the speckles\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-despeckle\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_distort_item = class\n\tMenuaction \"_Distort\" \"distort using a method and arguments\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tdistort = Magick.distort_widget;\n\t\targs = String \"Arguments\" \"1,0\";\n\t\tisPlus = Toggle \"Extend to show entire image\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t(if isPlus then \"+\" else \"-\") ++ \"distort\",\n\t\t\tdistort._flag,\n\t\t\targs.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_draw_item = class\n\tMenuaction \"_Draw\" \"annotate with one or more graphic primitives\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\targs = String \"Arguments\" \"line 0,0 9,9 rectangle 10,10 20,20\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-draw\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_edge_item = class\n\tMenuaction \"_Edge\" \"detect edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-edge\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_emboss_item = class\n\tMenuaction \"_Emboss\" \"emboss\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-emboss\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_enhance_item = class\n\tMenuaction \"_Enhance\" \"enhance a noisy image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-enhance\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_equalize_item = class\n\tMenuaction \"_Equalize\" \"equalize the histogram\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-equalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_evaluate_item = class\n\tMenuaction \"_Evaluate\" \"evaluate an expression on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\toperation = Magick.evaluate_widget;\n\t\tval = Expression \"value\" 5;\n\t\tisPc = Toggle \"Value is percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag, \n\t\t\toperation._flag, \n\t\t\tprint val.expr ++ if isPc then \"%%\" else \"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_extent_item = class\n\tMenuaction \"_Extent\" \"set the image size and offset\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-extent\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_FlipFlopMenu_item = class\n\tMenupullright \"_Flip/flop\" \"flip/flop/transverse/transpose\" {\n\n\tMagick_flip_item = class\n\t\tMenuaction \"_Flip vertically\" \"mirror upside-down\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flip\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_flop_item = class\n\t\tMenuaction \"_Flop horizontally\" \"mirror left-right\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flop\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transpose_item = class\n\t\tMenuaction \"_Transpose\" \"mirror along the top-left to bottom-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transpose +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transverse_item = class\n\t\tMenuaction \"_Transverse\" \"mirror along the bottom-left to top-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transverse +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end Magick_FlipFlopMenu_item\n\n\nMagick_floodfill_item = class\n\tMenuaction \"_Floodfill\" \"recolour neighbours that match\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tfuzz = Magick.fuzz_widget;\n\t\tcoordinate = Magick.coordinate_widget;\n\n\t\t// -draw \"color x,y floodfill\"\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-draw \\\" color\",\n\t\t\tcoordinate._flag,\n\t\t\t\"floodfill \\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_frame_item = class\n\tMenuaction \"_Frame\" \"surround with border or beveled frame\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tborder = Magick.bordercol_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tmatte = Magick.mattecol_widget;\n\t\tgeometry = Magick.FrameGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tborder._flag, \n\t\t\tmatte._flag, \n\t\t\t\"-frame\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_function_item = class\n\tMenuaction \"_Function\" \"evaluate a function on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfunction = Magick.function_widget;\n\t\t// FIXME: explain values; use sensible defaults.\n\t\tvalues = String \"values\" \"0,0,0,0\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-function\", \n\t\t\tfunction._flag, \n\t\t\tvalues.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_fx_item = class\n\tMenuaction \"_Fx\" \"apply a mathematical expression\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\targs = String \"Expression\" \"u*1/2\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\tinterpolate._flag,\n\t\t\tvirtpixback._flag,\n\t\t\t\"-fx\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gamma_item = class\n\tMenuaction \"_Gamma\" \"apply a gamma correction\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tgamma = Magick.gamma_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-gamma\",\n\t\t\tprint gamma.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradient_item = class\n\tMenuaction \"_Gradient\" \"apply a linear gradient\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolourA = Magick.generalcol_widget;\n\t\tcolourB = Magick.generalcol_widget;\n\n\t\tposition = Option \"colourA is at\" [\n\t\t\t\t\"top\", \"bottom\", \n\t\t\t\t\"left\", \"right\", \n\t\t\t\t\"top-left\", \"top-right\", \n\t\t\t\t\"bottom-left\", \"bottom-right\"] 0;\n\t\t_baryArg\n\t\t\t= concat [\"0,0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 0\n\t\t\t= concat [\"0,0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 1\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],0,\", colourB._flag], position.value == 2\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],0,\", colourA._flag], position.value == 3\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourB._flag], position.value == 4\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 5\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 6\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourA._flag], position.value == 7\n\t\t\t= \"dunno\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color barycentric \\\"\" ++ _baryArg ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradientCorn_item = class\n\tMenuaction \"_Gradient corners\" \n\t\t\"apply a bilinear gradient between the corners\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour_top_left = Magick.generalcol_widget;\n\t\tcolour_top_right = Magick.generalcol_widget;\n\t\tcolour_bottom_left = Magick.generalcol_widget;\n\t\tcolour_bottom_right = Magick.generalcol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color bilinear \\\"\" ++\n\t\t\t\t\"0,0,\" ++ colour_top_left._flag ++\n\t\t\t\t\",%%[fx:w-1],0\" ++ colour_top_right._flag ++\n\t\t\t\t\",0,%%[fx:h-1]\" ++ colour_bottom_left._flag ++\n\t\t\t\t\",%%[fx:w-1],%%[fx:h-1]\" ++ colour_bottom_right._flag ++ \"\\\"\",\n\t\t\t\"+depth\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_histogram_item = class\n\tMenuaction \"_Histogram\" \"make a histogram image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-define histogram:unique-colors=false histogram:\" ++\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_implode_item = class\n\tMenuaction \"_Implode\" \"implode pixels about the center\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfactor = Scale \"factor\" 0 20 1;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\t// FIXME: virtual-pixel?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tinterpolate._flag,\n\t\t\t\"-implode\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_level_item = class\n\tMenuaction \"_Level\" \"adjust the level of channels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"black point\" (-100) 200 0;\n\t\twht = Scale \"white point\" (-100) 200 100;\n\t\tgam = Scale \"gamma\" 0 30 1;\n\t\tisPc = Toggle \"Levels are percent\" true;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \",\" ++ \n\t\t\t\tprint wht.value ++ (if isPc then \"%%\" else \"\") ++ \",\" ++ \n\t\t\t\tprint gam.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_levelCols_item = class\n\tMenuaction \"_Level colors\" \"adjust levels to given colours\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcolour_black = Magick.generalcol_widget;\n\t\tcolour_white = Magick.generalcol_widget;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level-colors\",\n\t\t\t\"\\\"\" ++ colour_black._flag ++ \",\" ++ colour_white._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_linearStretch_item = class\n\tMenuaction \"_Linear stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-linear-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_magnify_item = class\n\tMenuaction \"_Magnify\" \"double the size of the image with pixel art scaling\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-magnify\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_modulate_item = class\n\tMenuaction \"_Modulate\" \"modulate brightness, saturation and hue\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmodcolsp = Magick.ModColSp_widget;\n\t\tbright = Scale \"brightness\" 0 200 100;\n\t\tsat = Scale \"saturation\" 0 200 100;\n\t\thue = Scale \"hue\" 0 200 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tmodcolsp._flag,\n\t\t\t\"-modulate\",\n\t\t\tprint bright.value ++ \",\" ++ print sat.value ++ \",\" ++ \n\t\t\t\tprint hue.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_monochrome_item = class\n\tMenuaction \"_Monochrome\" \"transform to black and white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// FIXME: also intensity?\n\n\t\tintensity = Magick.intensity_widget;\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tdither._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\t\"-monochrome\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_morphology_item = class\n\t// See http://www.imagemagick.org/Usage/morphology/\n\tMenuaction \"_Morphology\" \"apply a morphological method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmethod = Magick.morphmeth_widget;\n\t\titer = Expression \"Iterations (-1=repeat until done)\" 1;\n\n\t\tkernel = Magick.kernel_widget;\n\t\t// FIXME: custom kernel eg \"3x1+2+0:1,0,0\"\n\t\t//   width x height + offsx + offsy : {w*h values}\n\t\t//   each value is 0.0 to 1.0 or \"NaN\" or \"-\"\n\n\t\t// kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0\n\t\t// but\n\t\t//   ring takes: radius1, radius2, scale\n\t\t//   rectangle and comet take: width x height + offsx + offsy\n\t\t//   blur takes: radius x sigma\n\t\t// FIXME: for now, simply allow any string input.\n\t\tkernel_arg = String \"Kernel arguments\" \"\";\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-morphology\",\n\t\t\tmethod._flag ++ \":\" ++ print iter.expr, \n\t\t\tkernel._flag ++\n\t\t\t(if kernel_arg.value == \"\" then \"\" else \":\") ++ kernel_arg.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_negate_item = class\n\tMenuaction \"_Negate\" \"negate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-negate\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_addNoise_item = class\n\tMenuaction \"_add Noise\" \"add noise\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tattenuate = Scale \"attenuate\" 0 1.0 1.0;\n\t\tnoise = Magick.noise_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-attenuate\", \n\t\t\tprint attenuate.value,\n\t\t\tnoise._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_normalize_item = class\n\tMenuaction \"_Normalize\" \"normalize\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-normalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_opaque_item = class\n\tMenuaction \"_Opaque\" \"change this colour to the fill colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfill = Magick.foreground_widget;\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfill._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"opaque\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_paint_item = class\n\tMenuaction \"_Paint\" \"simulate an oil painting\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"radius\" 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-paint\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/*=== FIXME Bug; remove for now.\nPolaroid_item = class\n\tMenuaction \"_Polaroid\" \"simulate a polaroid picture\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle\" (-90) 90 20;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-polaroid\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_posterize_item = class\n\tMenuaction \"_Posterize\" \"reduce to (n) levels per channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tlevels = Expression \"levels\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-posterize\",\n\t\t\tprint levels.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_raise_item = class\n\tMenuaction \"_Raise\" \"lighten or darken image edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthk = Expression \"Thickness\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-raise\",\n\t\t\tprint thk.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_resize_item = class\n\tMenuaction \"_Resize\" \"resize to given width and height\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfilter = Magick.filter_widget;\n\t\ttype = Magick.ResizeType_widget;\n\t\twidth = Scale \"Width\" 1 100 10;\n\t\theight = Scale \"Height\" 1 100 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfilter._flag,\n\t\t\t\"-\" ++ type._flag,\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"!\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_roll_item = class\n\tMenuaction \"_Roll\" \"roll an image horizontally or vertically\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trollx = Expression \"X\" 3;\n\t\trolly = Expression \"Y\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-roll\",\n\t\t\t(if rollx.expr >= 0 then \"+\" else \"\") ++ print rollx.expr ++\n\t\t\t(if rolly.expr >= 0 then \"+\" else \"\") ++ print rolly.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_rotate_item = class\n\tMenuaction \"_Rotate\" \"rotate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"+distort\",\n\t\t\t\"SRT\",\n\t\t\tprint angle.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -segment, but cluster-threshold should be percentage of image area.\n\nMagick_sepia_item = class\n\tMenuaction \"_Sepia tone\" \"simulate a sepia-toned photo\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sepia-tone\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shade_item = class\n\tMenuaction \"_Shade\" \"shade with a distant light source\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tazimuth = Scale \"Azimuth (degrees)\" (-360) 360 0;\n\t\televation = Scale \"Elevation (degrees)\" 0 90 45;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shade\",\n\t\t\tprint azimuth.value ++ \"x\" ++ print elevation.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shadow_item = class\n\tMenuaction \"_Shadow\" \"simulate a shadow\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshadowCol = Magick.generalcol_widget;\n\t\topacity = Scale \"Opacity (percent)\" 0 100 75;\n\t\tsigma = Scale \"Sigma\" 0 30 2;\n\t\t// FIXME: make offsets a single widget?\n\t\toffsx = Scale \"X-offset\" (-20) 20 4;\n\t\toffsy = Scale \"Y-offset\" (-20) 20 4;\n\t\tarePc = Toggle \"offsets are percentages\" false;\n\n\t\t// FIXME: raw operation creates page offset, which vips dislikes.\n\t\t// So we take this futher, compositing with source.\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"(\\\" +clone\",\n\t\t\t\"-background\", \"\\\"\" ++ shadowCol._flag ++ \"\\\"\",\n\t\t\t\"-shadow\",\n\t\t\tconcat [\n\t\t\t\t\"\\\"\",\n\t\t\t\tprint opacity.value, \"x\", print sigma.value,\n\t\t\t\t(if offsx.value >= 0 then \"+\" else \"\"), print offsx.value,\n\t\t\t\t(if offsy.value >= 0 then \"+\" else \"\"), print offsy.value,\n\t\t\t\t(if arePc then \"%%\" else \"\"),\n\t\t\t\t\"\\\"\"\n\t\t\t],\n\t\t\t\"\\\")\\\" +swap -background None -layers merge\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shave_item = class\n\tMenuaction \"_Shave\" \"shave pixels from the edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 0 50 10;\n\t\theight = Scale \"Height\" 0 50 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shave\",\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shear_item = class\n\tMenuaction \"_Shear\" \"shear along the x-axis and/or y-axis\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-shear\",\n\t\t\tprint shearX.expr ++ \"x\" ++ print shearY.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sigmoid_item = class\n\tMenuaction \"_Sigmoid\" \"increase or decrease mid-tone contrast sigmoidally\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcontrast = Scale \"contrast\" 0 30 3;\n\t\tmidpoint = Scale \"mid-point (percent)\" 0 100 50;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"sigmoidal-contrast\",\n\t\t\t\"\\\"\" ++ print contrast.value ++ \"x\" ++ \n\t\t\t\tprint midpoint.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sketch_item = class\n\tMenuaction \"_Sketch\" \"simulate a pencil sketch\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tangle = Scale \"angle\" (-360) 360 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sketch\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if angle >= 0 then (\"+\" ++ print angle.value) else \"\"),\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_solarize_item = class\n\tMenuaction \"_Solarize\" \"negate all pixels above a threshold level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-solarize\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -sparse-color needs abitrary list of {x,y,colour}.\n\nMagick_splice_item = class\n\tMenuaction \"_Splice\" \"splice a colour into the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-splice\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_spread_item = class\n\tMenuaction \"_Spread\" \"displace pixels by random amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tamount = Expression \"Amount (pixels)\" 5;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"-spread\",\n\t\t\tprint amount.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_statistic_item = class\n\tMenuaction \"_Statistic\" \"replace each pixel with statistic from neighbourhood\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width\" 5;\n\t\theight = Expression \"Height\" 5;\n\t\tstatisticType = Magick.StatType_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-statistic\", \n\t\t\tstatisticType._flag, \n\t\t\tprint width.expr ++ \"x\" ++ print height.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_swirl_item = class\n\tMenuaction \"_Swirl\" \"swirl around the centre\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Magick.angle_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-swirl\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_thresholdMenu_item = class\n\tMenupullright \"_Threshold\" \"make black or white\" {\n\n\tMagick_threshold_item = class\n\t\tMenuaction \"_Threshold\" \"apply black/white threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-threshold\", \n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blackThreshold_item = class\n\t\tMenuaction \"_Black threshold\" \"where below threshold set to black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-black-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_whiteThreshold_item = class\n\t\tMenuaction \"_White threshold\" \"where above threshold set to white\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-white-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_latThreshold_item = class\n\t\tMenuaction \"_Local Adaptive Threshold\" \"where above average plus offset set to white, otherwise black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twidth = Expression \"Width\" 10;\n\t\t\theight = Expression \"Height\" 10;\n\t\t\toffset = Scale \"Offset (percent)\" (-100) 100 0;\n\t\t\t// note: \"-lat\" doesn't respond to channels\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-lat\",\n\t\t\t\tconcat [\"\\\"\", print width.expr, \"x\", print height.expr, \n\t\t\t\t\t(if offset.value >= 0 then \"+\" else \"\"), print offset.value,\n\t\t\t\t\t\"%%\\\"\"\n\t\t\t\t],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_randThreshold_item = class\n\t\tMenuaction \"_Random Threshold\" \"between specified limits, apply random threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tlow = Scale \"Low threshold\" 0 100 10;\n\t\t\thigh = Scale \"High threshold\" 0 100 90;\n\t\t\tisPc = Toggle \"Thresholds are percent\" true;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-random-threshold\", \n\t\t\t\t\"\\\"\" ++ print low.value ++ \"x\" ++ print high.value ++\n\t\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end ThresholdMenu_item\n\n\n// Note: alternatives include:\n// convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif\n\nMagick_tile_item = class\n\tMenuaction \"_Tile\" \"fill given size with tiled image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tsize = Magick.Size_widget;\n\n\t\tcommand = Magick.command [\n\t\t\tsize._flag,\n\t\t\t\"tile:\" ++ \"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_tint_item = class\n\tMenuaction \"_Tint\" \"apply a tint\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tamount = Scale \"amount (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-tint\",\n\t\t\t// snibgo note: although the amount is a percentage, it doesn't need \"%\" character.\n\t\t\tprint amount.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_transparent_item = class\n\tMenuaction \"_Transparent\" \"make this colour transparent\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"transparent\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_trim_item = class\n\tMenuaction \"_Trim\" \"trims away border\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfuzz = Magick.fuzz_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-trim +repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_uniqueCols_item = class\n\tMenuaction \"_Unique colours\" \"discard all but one of any pixel color\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-unique-colors\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_vignette_item = class\n\tMenuaction \"_Vignette\" \"soften the edges in vignette style\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\trx = Scale \"Rolloff x (percent)\" 0 100 10;\n\t\try = Scale \"Rolloff y (percent)\" 0 100 10;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-vignette\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if rx.value >= 0 then \"+\" else \"\") ++ print rx.value ++\n\t\t\t\t(if ry.value >= 0 then \"+\" else \"\") ++ print ry.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_wave_item = class\n\tMenuaction \"_Wave\" \"shear the columns into a sine wave\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tamplitude = Scale \"Amplitude (pixels)\" 0 100 10;\n\t\twavelength = Scale \"Wavelength (pixels)\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-wave\",\n\t\t\tprint amplitude.value ++ \"x\" ++ print wavelength.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\n"
  },
  {
    "path": "share/nip2/compat/7.40/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/7.40\n\nstart_DATA = \\\n\tMath.def \\\n\tImage.def \\\n\tMagick.def \\\n\tColour.def \\\n\tTasks.def \\\n\tObject.def \\\n\tFilter.def \\\n\tMatrix.def \\\n\tWidgets.def \\\n\tHistogram.def \\\n\tPreferences.ws \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_convert.def \\\n\t_generate.def \\\n\t_list.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\t_Object.def \\\n\t_magick.def \\\n\t_types.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/7.40/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_AND\" \"bitwise AND of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_OR\" \"bitwise OR of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"_XOR\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_NOT\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBandand_item = Image_band_item.Bandand_item; \n\n\tBandor_item = Image_band_item.Bandor_item; \n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tDifference_item = class \n\t\tMenuaction \"_Difference\" \"difference of two lists\" {\n\t\taction a b = map_binary difference a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tValue_item = class \n\t\tMenuaction \"_Value\" \"value of point in object\" {\n\t\taction a = class _result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tposition = Expression \"Coordinate\" (0, 0);\n\t\n\t\t\t_result = map_binary point position.expr a;\n\t\t}\n\t}\n\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tSkew_item = class \n\t\tMenuaction \"S_kew\" \"skew of image or list or vector\" {\n\t\taction a = map_unary skew a;\n\t}\n\n\tKurtosis_item = class \n\t\tMenuaction \"Kurtosis\" \"kurtosis of image or list or vector\" {\n\t\taction a = map_unary kurtosis a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \n\t\t\t\"position of centre of gravity of histogram\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = linreg xes yes;\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = linregw xes yes devs;\n\t}\n\n\tCluster_item = class \n\t\tMenuaction \"_Cluster\" \"cluster a list of numbers\" {\n\t\taction l = class {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tthresh = Expression \"Threshold\" 10;\n\t\n\t\t\t[_r, _w] = cluster thresh.expr l;\n\t\n\t\t\tresult = _r;\n\t\t\tweights = _w;\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.40/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_identity_item = class \n\t\tMenuaction \"_Identity\" \"make an identity matrix\" {\n\t\taction = identity (identity_matrix 5);\n\t\t\n\t\tidentity v = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix (identity_matrix (to_real s)), to_real s != len v;\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = identity value;\n\t\t}\n\t}\n\n\tMatrix_series_item = class \n\t\tMenuaction \"_Series\" \"make a series\" {\n\t\taction = series (mkseries 0 1 5);\n\n\t\tmkseries s t e \n\t\t\t= transpose [[to_real s, to_real s + to_real t .. to_real e]];\n\n\t\tseries v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t_s = v?0?0;\n\t\t\t_t = v?1?0 - v?0?0;\n\t\t\t_e = (last v)?0;\n\n\t\t\ts = Expression \"Start value\" _s;\n\t\t\tt = Expression \"Step by\" _t;\n\t\t\te = Expression \"End value\" _e;\n\n\t\t\t_result \n\t\t\t\t= Matrix (mkseries s t e), \n\t\t\t\t\t\tto_real s != _s || to_real t != _t || to_real e != _e\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = series value;\n\t\t}\n\t}\n\n\tMatrix_square_item = class \n\t\tMenuaction \"_Square\" \"make a square matrix\" {\n\t\taction = square (mksquare 5);\n\n\t\tmksquare s = replicate s (take s [1, 1 ..]);\n\n\t\tsquare v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == to_real s\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mksquare (to_real s); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = square value;\n\t\t}\n\t}\n\n\tMatrix_circular_item = class \n\t\tMenuaction \"_Circular\" \"make a circular matrix\" {\n\t\taction = circle (mkcircle 3);\n\n\t\tmkcircle r\n\t\t\t\t= map2 (map2 pyth) xes yes\n\t\t{\n\t\t\tline = [-r .. r];\n\t\t\txes = replicate (2 * r + 1) line;\n\t\t\tyes = transpose xes;\n\t\t\tpyth a b \n\t\t\t\t\t= 1, (a**2 + b**2) ** 0.5 <= r\n\t\t\t\t\t= 0;\n\t\t}\n\n\t\tcircle v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tr = Expression \"Radius\" ((len v - 1) / 2);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mkcircle (to_real r); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = circle value;\n\t\t}\n\t}\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\nMatrix_sort_item = class \n\tMenuaction \"_Sort\" \"sort by column or row\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\to = Option (_ \"Orientation\") [\n\t\t\t_ \"Sort by column\",\n\t\t\t_ \"Sort by row\"\n\t\t] 0;\n\t\ti = Expression (_ \"Sort on index\") 0;\n\t\td = Option (_ \"Direction\") [\n\t\t\t_ \"Ascending\",\n\t\t\t_ \"Descending\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary sort x\n\t\t{\n\t\t\tidx = to_real i;\n\t\t\tpred a b \n\t\t\t\t= a?idx <= b?idx, d == 0\n\t\t\t\t= a?idx >= b?idx;\n\t\t\tsort x\n\t\t\t\t= (x.Matrix_base @ sortc pred) x.value,\n\t\t\t\t\to == 0\n\t\t\t\t= (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value;\n\t\t}\n\t}\n}\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ \n\t\t\t\t\trange;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.40/Object.def",
    "content": "Object_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nObject_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nObject_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nObject_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nObject_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.40/Preferences.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/7.39.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"680\" window_height=\"800\" filename=\"$VIPSHOME/share/$PACKAGE/start/Preferences.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"100\" lpane_open=\"false\" rpane_position=\"400\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"Preferences\">\n    <Column x=\"0\" y=\"3067\" open=\"false\" selected=\"false\" sform=\"false\" next=\"99\" name=\"B\" caption=\"Interface column -- don't touch this!\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"CSV_SEPARATOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"O1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PRINT_CARTIESIAN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F10.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"USE_GRAPHICSMAGICK\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D45.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_PANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"237\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"788\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"700\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"100\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RELOAD\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D42.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_STATUSBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR_STYLE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MATRIX_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_RECOMP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"N2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_MAX_UNDO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[-1,0,1,5,10]?N1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_FONT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"N4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_INTERLACE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_LINELENGTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D41.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A6.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE_FILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PPM_MODE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"G1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_LAYOUT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C16.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C18.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_MULTI_RES\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_FORMAT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_PREDICTOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_BIGTIFF\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_START\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D25.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_SEARCH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D2.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_TMP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_SLIDER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D28.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_REGION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D29.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_AUTO_WS_SAVE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D30.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_DISPLAY_LED\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLKITBROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_MAX_HEAP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D38.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PIN_FILESEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_STATUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CONVERSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_RULERS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CROSSHAIR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL_HQ\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E21.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_TRACE_FUNCTIONS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"H1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_DEVICE\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CHANNEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_BRIGHTNESS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_COLOUR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CONTRAST\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_HUE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_FRAMES\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J13.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_MONO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J14.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_LEFT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_TOP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_ASPECT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_MAX_BLEND_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_REFINE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_WINDOW_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_OBJECT_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_BALANCE_GAMMA\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"680\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER_REMOTE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"POPUP_NEW_ROWS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_HISTORY_MAX\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D43.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_CPUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D44.value\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2831\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"I\" caption=\"Mosaic defaults\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Maximum blend width&quot; 0 100 10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Refine tie-points&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search windows this size&quot; 30\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search for objects this size&quot; 10\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Image gamma for mosaic balance&quot; 1 3 1.6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2495\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"J\" caption=\"Video for linux\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"J2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;Device&quot; &quot;/dev/video&quot;\"/>\n            <Pathname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Channel&quot; [&quot;TV&quot;, &quot;Composite 1&quot;, &quot;Composite 2&quot;, &quot;Composite 3&quot;] 1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Brightness&quot; 0 32767 23000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Colour&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Contrast&quot; 0 32767 27000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Hue&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Number of frames to average&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Grab monochrome&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2208\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"K\" caption=\"General video capture\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"K1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Crop video: \" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Crop video&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop left&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop top&quot; 6\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number  &quot;Crop width&quot; 747\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop height&quot; 570\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Aspect ratio (stretch vertically\\nby this much)&quot; 1.202\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2072\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"M\" caption=\"PNG save options\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"M1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Compression&quot; (map print [0..9]) 6\"/>\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Interlace&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1970\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"G\" caption=\"PPM/PGM/PBM save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"PPM mode\" labelsn=\"2\" labels0=\"Binary\" labels1=\"ASCII\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Mode&quot; [&quot;Binary&quot;, &quot;ASCII&quot;] 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1620\" open=\"true\" selected=\"true\" sform=\"false\" next=\"27\" name=\"C\" caption=\"TIFF save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Compression&quot; [&quot;None&quot;, &quot;LZW&quot;, &quot;Zip (deflate)&quot;, &quot;PACKBITS&quot;, &quot;JPEG&quot;, &quot;CCITTFAX4&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;JPEG quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Deflate/LZW predictor&quot; [&quot;None&quot;,&quot;Horizontal difference&quot;,&quot;Floating-point&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Layout\" labelsn=\"2\" labels0=\"Strip\" labels1=\"Tile\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Layout&quot; [&quot;Strip&quot;, &quot;Tile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile width&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile height&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Multi-res&quot; [&quot;Single image&quot;, &quot;Image pyramid&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Format&quot; [&quot;No truncation&quot;,&quot;Save 1 band 8 bit images as 1 bit&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Save as BigTIFF&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1518\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"O\" caption=\"CSV save\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"String &quot;Separator character&quot; &quot;\\t&quot;\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1348\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"A\" caption=\"JPEG save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;ICC profile&quot; [&quot;Use image profile, if any&quot;, &quot;Embed profile from file&quot;, &quot;Don't attach a profile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Pathname/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;ICC profile file&quot; &quot;$VIPSHOME/share/nip2/data/sRGB.icm&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1144\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"F\" caption=\"Widgets\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Pin up file requestors&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Main window toolbar&quot; [&quot;Default style&quot;, &quot;Icon only&quot;, &quot;Text only&quot;, &quot;Icon and text&quot;, &quot;Icon and text to right&quot;] 0\"/>\n            <Option caption=\"Main window toolbar\" labelsn=\"5\" labels0=\"Default style\" labels1=\"Icon only\" labels2=\"Text only\" labels3=\"Icon and text\" labels4=\"Icon and text to right\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display LEDs in workspace&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display complex numbers as coordinates&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1044\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"H\" caption=\"Debug options\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Disassemble functions\" value=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;untitled&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"906\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"L\" caption=\"Help browser\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"L2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Command to start browser&quot; &quot;firefox&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Go-to-page argument&quot; &quot;-remote 'openURL(%s)'&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"734\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"N\" caption=\"Paintbox \">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Max undo steps\" labelsn=\"5\" labels0=\"Unlimited\" labels1=\"None\" labels2=\"1\" labels3=\"5\" labels4=\"10\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Max undo steps&quot; [&quot;Unlimited&quot;, &quot;None&quot;, &quot;1&quot;, &quot;5&quot;, &quot;10&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Fontname &quot;Default paintbox font&quot; &quot;Sans 12&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Fontname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update during paint&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"458\" open=\"true\" selected=\"false\" sform=\"false\" next=\"27\" name=\"E\" caption=\"Image display\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"E20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use crosshair cursor in image windows&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Thumbnail size&quot; 64\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;High-quality thumbnails&quot; false\"/>\n            <Toggle/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window width&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window height&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto image window pop up&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"46\" name=\"D\" caption=\"Calculation\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Data path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;data&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;data&quot;], &quot;.&quot;]\"/>\n            <Expression caption=\"Data path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Temporary files&quot; (path_relative [&quot;$SAVEDIR&quot;, &quot;tmp&quot;])\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Start path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;start&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;start&quot;]]\"/>\n            <Expression caption=\"Start path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D28\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update sliders during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update sliders during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D29\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update regions during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update regions during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D30\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto workspace save&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D42\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto-reload on file change&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D41\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Text display length (characters)&quot; 80\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D38\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Heap size (per workspace)&quot; 600000\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D43\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of VIPS functions to memoise&quot; 20000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D44\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of CPUs to use (0 for autodetect)&quot; 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D45\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use GraphicsMagick for Magick menu&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/compat/7.40/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\n\tCsv_import_item = class\n\t\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tstart_line = Expression \"Start at line\" 1;\n\t\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_csv2vips filename)\n\t\t\t{\n\t\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\t\tescape x \n\t\t\t\t\t= foldr prefix [] x\n\t\t\t\t{\n\t\t\t\t\tprefix x l\n\t\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t\t= x : l;\n\t\t\t\t}\n\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tRaw_import_item = class\n\t\tMenuaction \"_Raw Import\" \"read a file of binary values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tacross = Expression \"Pixels across\" 100;\n\t\t\tdown = Expression \"Pixels down\" 100;\n\t\t\tbytes = Expression \"Bytes per pixel\" 3;\n\t\t\tskip = Expression \"Skip over initial bytes\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_binfile path.value \n\t\t\t\t\tacross.expr down.expr bytes.expr skip.expr)\n\t\t\t{\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// interpret Analyze header for layout and calibration\n\tAnalyze7_header_item = class\n\t\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\t\"examine the Analyze header and set layout and value\" {\n\t\taction x \n\t\t\t= x'''\n\t\t{\n\t\t\t// read bits of header\n\t\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\t\tdim0 = dim 0 x;\n\t\t\tdim1 = dim 1 x;\n\t\t\tdim2 = dim 2 x;\n\t\t\tdim3 = dim 3 x;\n\t\t\tdim4 = dim 4 x;\n\t\t\tdim5 = dim 5 x;\n\t\t\tdim6 = dim 6 x;\n\t\t\tdim7 = dim 7 x;\n\t\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\t\n\t\t\t// oops, now a nop\n\t\t\tx' = x;\n\t\n\t\t\t// lay out higher dimensions width-ways\n\t\t\tx'' \n\t\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\t\tdim0 == 7\n\t\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\t\n\t\t\t// multiply by scale factor to get kBeq\n\t\t\tx''' = x'' * (cal_max / glmax);\n\t\t}\n\t}\n\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\t[image, patch] = sortc larger [a, b];\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n\t\t\tsample = measure_draw 6 4 (to_real measure) image;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\tmode = Option \"Input LUT\" [\n\t\t\t\t\"Linearize from chart greyscale\",\n\t\t\t\t\"Fit intercept from chart greyscale\",\n\t\t\t\t\"Linear input, set brightness from chart\",\n\t\t\t\t\"Linear input\"\n\t\t\t] 0;\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = measure_sample 6 4 (to_real measure) image;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb \n\t\t\t\t= Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0\n\t\t\t\t= Matrix [0: intercepts, replicate (_camera.width + 1) 1], \n\t\t\t\t\tmode == 1\n\t\t\t\t= Matrix [[0, 0], [1, 1]]\n\t\t\t{\n\t\t\t\tintercepts = [(linreg _true_grey_Y' cam).intercept :: \n\t\t\t\t\tcam <- transpose _camera_grey'];\n\t\t\t}\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\t// plot from 0 explicitly so we see the effect of mode1 (intercept\n\t\t\t// from greyscale)\n\t\t\tlinearising_lut = Plot [$ymin => 0] _linear_lut;\n\n\t\t\t// map an image though the lineariser\n\t\t\tlinear x\n\t\t\t\t= hist_map linearising_lut.value x, mode == 0 || mode == 1\n\t\t\t\t= x;\n\n\t\t\t// map the chart measurements though the lineariser\n\t\t\t_camera' = (to_matrix @ linear @ to_image) _camera;\n\n\t\t\t// solve for RGB -> XYZ\n\t\t\t// normalise: the 2nd row is what makes Y, so divide by that to\n\t\t\t// get Y in 0-1.\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\t_full_M = transpose (_pinv * (transpose _camera' * _true_XYZ));\n\t\t\tM = _full_M / scale;\n\t\t\tscale = sum _full_M.value?1;\n\n\t\t\t// now turn the camera to LAB and calculate dE76\n\t\t\t_camera'' = (to_matrix @ \n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @ \n\t\t\t\trecomb M @ \n\t\t\t\tmultiply scale @\n\t\t\t\tto_image) _camera';\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tavg_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0 && i < len macbeth_names\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\n\t\t\t// normalise brightness ... in linear mode, we optionally don't\n\t\t\t// set the brightness from the Macbeth chart\n\t\t\tnorm x \n\t\t\t\t= x * scale, mode != 3\n\t\t\t\t= x;\n\n\t\t\t// convert RGB camera to Lab\n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tnorm @\n\t\t\t\trecomb M @\n\t\t\t\tcast_float @\n\t\t\t\tlinear) image.value;\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b = class\n\t\t\t(map_binary process a b) {\n\t\t\tprocess a b\n\t\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t\t{\n\t\t\t\t// the name of the calib object we need\n\t\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t\t// get the Calibrate_chart arg first\n\t\t\t\t[image, calib] = sortc (const (is_instanceof calib_name)) \n\t\t\t\t\t[a, b];\n\n\t\t\t\tresult = (Image @\n\t\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\t\tcalib.norm @\n\t\t\t\t\trecomb calib.M @\n\t\t\t\t\tcast_float @\n\t\t\t\t\tcalib.linear) image.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [$style => style.value] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\t!is_list_len 2 images\n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = all (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize Interpolate_bilinear xfactor yfactor scale_im;\n\t\t\t_offset_im = resize Interpolate_bilinear xfactor yfactor offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.40/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.40/_Object.def",
    "content": "/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0|1|2|3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \n\tjoin_sep \"|\" Image_type.colour_spaces.names];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide|VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad properties for \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"where\" ++ \"\\n\" ++ arg_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make arg type notes\n\targ_types = join_sep \"\\n\" (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"\\n\" ++ _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = join_sep \"\\n\" all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if those fail as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if that fails as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary'_function op a b\n\t= matches1?0, matches1 != []\n\t= matches2?0, op.symmetric && matches2 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0, matches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t// these should always be defined\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x = oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x = oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op = oo_unary_function (oo_unary_lookup op) this;\n\n\too_binary_table op x = [];\n\too_unary_table op = [];\n}\n"
  },
  {
    "path": "share/nip2/compat/7.40/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= Image x.value, is_Plot x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n// like to_image, but we do 1x1 pixel + x, then embed it up\n// always make an unwrapped image for speed ... this gets used by ifthenelse\n// and stuff like that\n// format can be NULL, meaning set format from x\nto_image_size width height bands format x\n\t= x, is_image x\n\t= x.value, is_Image x\n\t= im''\n{\n\t// we want x to set the target format if we don't have one, so we\n\t// can't use image_new\n\tim = im_black 1 1 bands + x;\n\tim'\n\t\t= clip2fmt format im, format != NULL\n\t\t= im;\n\tim'' = embed 1 0 0 width height im';\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && is_list_len 3 x\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\nto_int x = (int) (to_real x);\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The outermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x \n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), !is_list_len 2 parts \n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, !is_list_len 4 parts \n\t= sign * (abs ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", \n\t\tmember \".0123456789\",\n\t\tmember \"eE\", \n\t\tmember \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tsign \n\t\t= 1, ipart > 0\n\t\t= -1;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), !is_list_len 5 parts \n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t$D93 => D93_whitepoint,\n\t$D75 => D75_whitepoint,\n\t$D65 => D65_whitepoint,\n\t$D55 => D55_whitepoint,\n\t$D50 => D50_whitepoint,\n\t$A => A_whitepoint,\n\t$B => B_whitepoint,\n\t$C => C_whitepoint,\n\t$E => E_whitepoint,\n\t$D3250 => D3250_whitepoint\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, image_set_type GREY16 @ im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l = join_sep path_separator l;\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 > 1 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n"
  },
  {
    "path": "share/nip2/compat/7.40/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= embed 1 0 0 w h im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black 1 1 (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\nmkim options x y b\n    = Image (image_new x y b\n        (opt $format) (opt $coding) (opt $type)\n        (opt $pixel)\n        (opt $xoffset) (opt $yoffset))\n{\n    opt = get_option options [\n        $format => Image_format.UCHAR,\n        $coding => Image_coding.NOCODING,\n        $type => Image_type.sRGB,\n        $pixel => 0,\n        $xoffset => 0,\n        $yoffset => 0\n    ];\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = im_gauss_imask_sep (radius / 3) 0.2;\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n/* Make a colour from a temperature.\n */\ncolour_from_temp T\n\t= error (_ \"T out of range\"), T < 1667 || T > 25000\n\t= Colour \"Yxy\" [50, x, y]\n{\n\t// Kim et all approximation\n\t// see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation\n\tx\n\t\t= -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 +\n\t\t\t0.8776956 * 10 ** 3 / T + 0.179910, T < 4000\n\t\t= -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 +\n\t\t\t0.2226347 * 10 ** 3 / T + 0.240390;\n\n\ty \n\t\t= -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + \n\t\t\t2.18555832 * x - 0.20219638, T < 2222\n\t\t= -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + \n\t\t\t2.09137015 * x - 0.16748867, T < 4000\n\t\t=  3.0817580 * x ** 3 - 5.87338670 * x ** 2 +\n\t\t\t3.75112997 * x - 0.37001483;\n}\n\ntemp_from_colour z\n\t= T\n{\n\tc = colour_transform_to Image_type.YXY (to_colour z);\n\tx = c.value?1;\n\ty = c.value?2;\n\n\t// McCamy's approximation, see eg. \n\t// http://en.wikipedia.org/wiki/Color_temperature#Approximation\n\n\txe = 0.332;\n\tye = 0.1858;\n\tn = (x - xe) / (y - ye);\n\tT = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33;\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.40/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 1;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" \n\t] 4;\n\n\tcontrol_selection mask im no\n\t\t= [\n\t\t\tif mask then im * 1.2 else im * 1,\n\t\t\tif mask then im * 0.8 else im * 1,\n\t\t\tif mask then 0 else im,\n\t\t\tif mask then 255 else im,\n\t\t\tif mask then im else 0,\n\t\t\tif mask then im else 255,\n\t\t\tmask\n\t\t]?no;\n\n\tRectangle = class\n        Menuaction \"_Rectangle\"\n            \"use an Arrow or Region x to define a rectangle\"\n        {\n        action x = class\n            _result {\n            _vislevel = 3;\n\n            control = _control;   \n\n            _result = control_selection mask im control\n                  {\n                \tim = x.image;\n                \tmask = Image m\n                    {\n\t\t\t\t\t\trx     \n\t\t\t\t\t\t\t= x.region_rect, is_Region x\n\t\t\t\t\t\t\t= x;\n\t\t\t\t\t\tb     = image_new im.width im.height 1 0 0 1 0 0 0;\n\t\t\t\t\t\tw     = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0;\n\t\t\t\t\t\tm     = insert_noexpand rx.nleft rx.ntop w b; \n                     }\n                   }\n            }\n        }\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = get_image a;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = get_image ((pt_list.value)?0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tSegment_item = class\n\t\tMenuaction \"_Segment\" \"break image into disjoint regions\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsegments\n\t\t\t\t= Expression \"Number of disjoint regions\" \n\t\t\t\t\t(map_unary (get_header \"n-segments\") _result);\n\n\t\t\t_result = map_unary segment x;\n\t\t}\n\t}\n\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize Interpolate_bilinear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize Interpolate_bilinear f1 1 b1\n\t\t\t\t\t{b1 = resize Interpolate_bilinear 1 f2 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/7.40/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = Image (get_image line);\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = Image (get_image (pt_l?0));\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t};\n\nMount_options _ctype _ppcm = class \n  {\n  _vislevel = 3;\n  apply = Toggle \"Apply mount options\" false;\n  ls = Expression \"Lower mount section bigger by (cm)\" 0;\n  mount_colour = Colour _ctype [0, 0, 0];\n  _los = ls.expr * _ppcm;\n  };\n\nFrame_variables comp = class\n  {\n  _vislevel = 3;\n\n  scale_factor = Expression \"scale the size of the frame by\" 1;\n\n  /* These sliders define the fraction of the frames width or height is extracted\n   * to produce each of the particular regions.\n   */\n  corner_section = Scale \"Corner section\" 0.1 1 0.5;\n  edge_section = Scale \"Edge section\" 0.1 1 0.2, comp > 0\n\t\t\t\t  = \"Only required for complex frames\";\n  middle_section = Scale \"Middle section\" 0.1 1 0.2;\n  blend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n  option = Toggle \"Use mirror of left-side to make right\" true;\n  };\n\n"
  },
  {
    "path": "share/nip2/compat/7.40/_list.def",
    "content": "/* any l: or all the elements of list l together\n *\n * any (map (equal 0) list) == true, if any element of list is zero.\n * any :: [bool] -> bool\n */\nany = foldr logical_or false;\n\n/* all l: and all the elements of list l together\n *\n * all (map (==0) list) == true, if every element of list is zero.\n * all :: [bool] -> bool\n */\nall = foldr logical_and true;\n\n/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* delete eq x l: delete the first x from l\n *\n * delete equal 'b' \"abcdb\" == \"acdb\"\n * delete :: (* -> bool) -> * -> [*] -> [*]\n */\ndelete eq a l\n\t= [], l == []\n\t= y, eq a b\n\t= b : delete eq a y\n{\n\tb:y = l;\n}\n\n/* difference eq a b: delete b from a\n *\n * difference equal \"asdf\" \"ad\" == \"sf\"\n * difference :: (* -> bool) -> [*] -> [*] -> [*]\n */\ndifference = foldl @ converse @ delete;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn x, fn a\n\t= l\n{\n\ta:x = l;\n}\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* flatten x: flatten a list of lists of things into a simple list\n *\n * flatten :: [[*]] -> [*]\n */\nflatten x\n\t= foldr flat [] x, is_list x\n\t= x\n{\n\tflat x sofar\n\t\t= foldr flat sofar x, is_list x\n\t\t= x : sofar;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st x) xs\n{\n\tx:xs = l;\n}\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn x xs\n{\n\tx:xs = l;\n}\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn x (foldr fn st xs)\n{\n\tx:xs = l;\n}\n\n/* foldr1 fn l: like foldr, but use the last element as the start value\n *\n * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= x, xs == []\n\t= fn x (foldr1 fn xs)\n{\n\tx:xs = l;\n}\n\n/* Search a list for an element, returning its index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn x\n\t\t= search xs (n + 1)\n\t\t{\n\t\t\tx:xs = l;\n\t\t}\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= x : init xs\n{\n\tx:xs = l;\n}\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* join_sep sep l: join a list with a separator\n *\n * join_sep \", \" (map print [1 .. 4]) == \"1, 2, 3, 4\"\n * join_sep :: [*] -> [[*]] -> [*]\n */\njoin_sep sep l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ sep ++ b;\n}\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= x, xs == []\n\t= last xs\n{\n\tx:xs = l;\n}\n\n/* len l: length of list l\n * (see also is_list_len and friends in predicate.def)\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta:b:x = l;\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = any (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge p l r\n\t= [], p == [] || l == [] || r == []\n\t= a : merge z x y, c\n\t= b : merge z x y\n{\n\ta:x = l;\n\tb:y = r;\n\tc:z = p;\n}\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta:x = l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scanl fn st l: apply (foldl fn r) to every initial segment of a list\n *\n * scanl add 0 [1,2,3] == [1,3,6]\n * scanl :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscanl fn st l\n\t= st, l == []\n\t= st' : scanl fn st' xs\n{\n\tx:xs = l;\n\tst' = fn st x;\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta:x = l1;\n\t\tb:y = l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/7.40/_magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate _magick.def\n\t Add 0-ary and 2-ary system\n\t Put utility funcs into a Magick class\n   11-Apr-2014 snibgo\n     Added VirtualPixelBack for cases where background is only relevant when VP=Background\n   17-Apr-2014 snibgo\n     Many small changes.\n   2-May-2014 jcupitt\n     Added Magick.version\n   30-June-2014\n   \t Put single-quotes around command exe to help win\n   1-July-2014\n     Automatically fall back to gm if we can't find convert\n   17-July-2014\n     better GM support\n\n\n   Last update: 17-July-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n\n*/\n\n/* Put these in a class to avoid filling the main namespace with IM stuff.\n */\n\nMagick = class {\n\n\t// turn $PATH into [[\"comp1\", \"comp2\"], [\"comp1\", \"comp2\"] ..]\n\tsystem_search_path\n\t\t= map path_parse (split (equal path_sep) (expand \"$PATH\"))\n\t{\n\t\tpath_sep\n\t\t\t= ':', expand \"$SEP\" == \"/\"\n\t\t\t= ';';\n\t}\n\n\t// the first name[.exe] on $PATH, or \"\"\n\tsearch_for name\n\t\t= hits?0, hits != []\n\t\t= \"\"\n\t{\n\t\texe_name = name ++ expand \"$EXEEXT\";\n\t\tform_path p = path_absolute (p ++ [exe_name]);\n\t\tpaths = map form_path system_search_path;\n\t\thits = dropwhile (equal []) (map search paths);\n\t}\n\n\t// first gm on path, or \"\"\n\tgm_path = search_for \"gm\";\n\n\t// first convert on $PATH, or \"\"\n\t// we check for the convert we ship first\n\tconvert_path \n\t\t= vips_convert, vips_convert != \"\"\n\t\t= search_for \"convert\"\n\t{\n\t\t// the convert we ship with the vips binary on some platforms, or \"\"\n\t\tvips_convert \n\t\t\t= search (path_absolute convert)\n\t\t{\n\t\t\tvipshome = path_parse (expand \"$VIPSHOME\");\n\t\t\tconvert = vipshome ++ [\"bin\", \"convert\" ++ expand \"$EXEEXT\"];\n\t\t}\n\t}\n\n\tuse_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK;\n\n\t// Are we in GM or IM mode? \n\tuse_gm \n\t\t= true, use_gm_pref && gm_path != \"\"\n\t\t= false, !use_gm_pref && convert_path != \"\"\n\t\t= false, convert_path != \"\"\n\t\t= true, gm_path != \"\"\n\t\t= error \"neither IM nor GM executable found\";\n\n\tcommand_path\n\t\t= gm_path, use_gm\n\t\t= convert_path;\n\n\t// try to get the version as eg. [6, 7, 7, 10]\n\t// GM versions are smaller, typically [1, 3, 18]\n\tversion\n\t\t= map parse_int (split (member \".-\") version_string)\n\t{\n\t\t[output] = vips_call \"system\" \n\t\t\t[\"'\" ++ command_path ++ \"' -version\"] [$log=>true];\n\t\tversion_string \n\t\t\t= (split (equal ' ') output)?1, use_gm\n\t\t\t= (split (equal ' ') output)?2;\n\t}\n\n\t// make a command-line ... args is a [str] we join with spaces\n\tcommand args \n\t\t= \"'\" ++ command_path ++ \"' \" ++ join_sep \" \" args'\n\t{\n\t\targs'\n\t\t\t= [\"convert\"] ++ args, use_gm\n\t\t\t= args;\n\t}\n\n\t// capabilities ... different versions support different features, we \n\t// turn features on and off based on these\n\n\t// would probably be better to test for caps somehow\n\thas_intensity\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\thas_channel\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\n\tsystem0 cmd = system_image0 cmd;\n\tsystem cmd x = map_unary (system_image cmd) x;\n\tsystem2 cmd x y = map_binary (system_image2 cmd) x y;\n\tsystem3 cmd x y z = map_trinary (system_image3 cmd) x y z;\n\n\tradius_widget = Scale \"Radius\" 0 100 10;\n\tsigma_widget = Scale \"Sigma\" 0.1 10 1;\n\tangle_widget = Scale \"Angle (degrees)\" (-360) 360 0;\n\ttext_widget = String \"Text to draw\" \"AaBbCcDdEe\";\n\n\tgamma_widget = Scale \"Gamma\" 0 10 1;\n\tcolors_widget = Scale \"Colors\" 1 10 3;\n\tresize_widget = Scale \"Resize (percent)\" 0 500 100;\n\tfuzz_widget = Scale \"Fuzz (percent)\" 0 100 0;\n\tblur_rad_widget = Scale \"Radius (0=auto)\" 0 100 0;\n\n\t// a colour with no enclosing quotes ... use this if we know there are\n\t// some quotes at an outer level\n\tprint_colour_nq triple\n\t\t= concat [\"#\", concat (map fmt triple)]\n\t{\n\t\tfmt x = reverse (take 2 (reverse (print_base 16 (x + 256))));\n\t}\n\n\t// we need the quotes because # is the comment character in *nix\n\tprint_colour triple = \"\\\"\" ++ print_colour_nq triple ++ \"\\\"\";\n\n\tForeground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-fill \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Foreground triple;\n\t}\n\tforeground_widget = Foreground [0, 0, 0];\n\n\tGeneralCol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = print_colour_nq triple;\n\n\t\tColour_edit space triple = this.GeneralCol triple;\n\t}\n\tgeneralcol_widget = GeneralCol [0, 0, 0];\n\n\tBackground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" false;\n\n\t\t_flag = \"-background \" ++ if isNone then \"None\" else print_colour triple;\n\n\t\tColour_edit space triple = this.Background triple;\n\t}\n\tbackground_widget = Background [255, 255, 255];\n\n\tBordercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-bordercolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Bordercol triple;\n\t}\n\tbordercol_widget = Bordercol [0, 0, 0];\n\n\tMattecol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-mattecolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Mattecol triple;\n\t}\n\tmattecol_widget = Mattecol [189, 189, 189];\n\n\t// FIXME: Undercolour, like many others, can have alpha channel.\n\t// How does user input this? With a slider?\n\tUndercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" true;\n\n\t\t_flag = if isNone then \"\" else (\"-undercolor \" ++ print_colour triple);\n\n\t\tColour_edit space triple = this.Undercol triple;\n\t}\n\tundercol_widget = Undercol [0, 0, 0];\n\n\tchangeCol_widget = class {\n\t\t_vislevel = 3;\n\n\t\tcolour = GeneralCol [0, 0, 0];\n\t\tfuzz = fuzz_widget;\n\t\tnonMatch = Toggle \"change non-matching colours\" false;\n\t}\n\n\tAlpha alpha = class\n\t\tOption_string \"Alpha\" [\n\t\t\t\"On\", \n\t\t\t\"Off\", \n\t\t\t\"Set\", \n\t\t\t\"Opaque\", \n\t\t\t\"Transparent\", \n\t\t\t\"Extract\", \n\t\t\t\"Copy\", \n\t\t\t\"Shape\", \n\t\t\t\"Remove\", \n\t\t\t\"Background\"\n\t\t] alpha {\n\n\t\t_flag = \"-alpha \" ++ alpha;\n\n\t\tOption_edit caption labels value = this.Alpha labels?value;\n\t}\n\talpha_widget = Alpha \"On\";\n\n\tAntialias value = class\n\t\tToggle \"Antialias\" value {\n\n\t\t_flag\n\t\t\t= \"-antialias\", value\n\t\t\t= \"+antialias\";\n\n\t\tToggle_edit caption value = this.Antialias value;\n\t}\n\tantialias_widget = Antialias true;\n\n\tBuiltin builtin = class\n\t\tOption_string \"Builtin\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"rose:\",\n\t\t\t\"logo:\",\n\t\t\t\"wizard:\",\n\t\t\t\"granite:\",\n\t\t\t\"netscape:\"\n\t\t] builtin {\n\n\t\t_flag = builtin;\n\n\t\tOption_edit caption labels value = this.Builtin labels?value;\n\t}\n\tbuiltin_widget = Builtin \"rose:\";\n\n\n\tchannels_widget = class {\n\t\t// FIXME? Can we grey-out alpha when we have no alpha channel,\n\t\t//        show CMY(K) instead of RGB(K) etc?\n\t\t// Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA.\n\t\tChanR valueR = class\n\t\t\tToggle \"Red\" valueR {\n\n\t\t\t_flag\n\t\t\t\t= \"R\", valueR\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueR = this.ChanR valueR;\n\t\t}\n\t\tchannelR = ChanR true;\n\n\t\tChanG valueG = class\n\t\t\tToggle \"Green\" valueG {\n\n\t\t\t_flag\n\t\t\t\t= \"G\", valueG\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueG = this.ChanG valueG;\n\t\t}\n\t\tchannelG = ChanG true;\n\n\t\tChanB valueB = class\n\t\t\tToggle \"Blue\" valueB {\n\n\t\t\t_flag\n\t\t\t\t= \"B\", valueB\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueB = this.ChanB valueB;\n\t\t}\n\t\tchannelB = ChanB true;\n\n\t\tChanK valueK = class\n\t\t\tToggle \"Black\" valueK {\n\n\t\t\t_flag\n\t\t\t\t= \"K\", valueK\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueK = this.ChanK valueK;\n\t\t}\n\t\tchannelK = ChanK true;\n\n\t\tChanA valueA = class\n\t\t\tToggle \"Alpha\" valueA {\n\n\t\t\t_flag\n\t\t\t\t= \"A\", valueA\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueA = this.ChanA valueA;\n\t\t}\n\t\tchannelA = ChanA false;\n\n\t\tChanSy valueSy = class\n\t\t\tToggle \"Sync\" valueSy {\n\n\t\t\t_flag\n\t\t\t\t= \",sync\", valueSy\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueSy = this.ChanSy valueSy;\n\t\t}\n\t\tchannelSy = ChanSy true;\n\n\t\t_rgbka = concat [channelR._flag,\n\t\t\t\tchannelG._flag,\n\t\t\t\tchannelB._flag,\n\t\t\t\tchannelK._flag,\n\t\t\t\tchannelA._flag\n\t\t\t];\n\n\t\t_flag\n\t\t\t= \"\", _rgbka == \"\" || !has_channel\n\t\t\t= concat [ \"-channel \",\n\t\t\t\t_rgbka,\n\t\t\t\tchannelSy._flag \n\t\t\t\t];\n\t}\n\n\tch_widget = channels_widget;\n\n\tColorspace colsp = class\n\t\tOption_string \"Colorspace\" [\n\t\t\t\"CIELab\",\n\t\t\t\"CMY\",\n\t\t\t\"CMYK\",\n\t\t\t\"Gray\",\n\t\t\t\"HCL\",\n\t\t\t\"HCLp\",\n\t\t\t\"HSB\",\n\t\t\t\"HSI\",\n\t\t\t\"HSL\",\n\t\t\t\"HSV\",\n\t\t\t\"HWB\",\n\t\t\t\"Lab\",\n\t\t\t\"LCH\",\n\t\t\t\"LCHab\",\n\t\t\t\"LCHuv\",\n\t\t\t\"LMS\",\n\t\t\t\"Log\",\n\t\t\t\"Luv\",\n\t\t\t\"OHTA\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601YCbCr\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709YCbCr\",\n\t\t\t\"RGB\",\n\t\t\t\"scRGB\",\n\t\t\t\"sRGB\",\n\t\t\t\"Transparent\",\n\t\t\t\"XYZ\",\n\t\t\t\"YCbCr\",\n\t\t\t\"YDbDr\",\n\t\t\t\"YCC\",\n\t\t\t\"YIQ\",\n\t\t\t\"YPbPr\",\n\t\t\t\"YUV\"\n\t\t] colsp {\n\n\t\t_flag = colsp;\n\n\t\tOption_edit caption labels value = this.Colorspace labels?value;\n\t}\n\tcolorspace_widget = Colorspace \"sRGB\";\n\n\tCompose comp = class\n\t\tOption_string \"Compose method\" [\n\t\t\t\"Atop\", \n\t\t\t\"Blend\", \n\t\t\t\"Blur\", \n\t\t\t\"Bumpmap\", \n\t\t\t\"ChangeMask\", \n\t\t\t\"Clear\", \n\t\t\t\"ColorBurn\", \n\t\t\t\"ColorDodge\", \n\t\t\t\"Colorize\", \n\t\t\t\"CopyBlack\", \n\t\t\t\"CopyBlue\", \n\t\t\t\"CopyCyan\", \n\t\t\t\"CopyGreen\", \n\t\t\t\"Copy\", \n\t\t\t\"CopyMagenta\", \n\t\t\t\"CopyOpacity\", \n\t\t\t\"CopyRed\", \n\t\t\t\"CopyYellow\", \n\t\t\t\"Darken\", \n\t\t\t\"DarkenIntensity\", \n\t\t\t\"DivideDst\", \n\t\t\t\"DivideSrc\", \n\t\t\t\"Dst\", \n\t\t\t\"Difference\", \n\t\t\t\"Displace\", \n\t\t\t\"Dissolve\", \n\t\t\t\"Distort\", \n\t\t\t\"DstAtop\", \n\t\t\t\"DstIn\", \n\t\t\t\"DstOut\", \n\t\t\t\"DstOver\", \n\t\t\t\"Exclusion\", \n\t\t\t\"HardLight\", \n\t\t\t\"Hue\", \n\t\t\t\"In\", \n\t\t\t\"Lighten\", \n\t\t\t\"LightenIntensity\", \n\t\t\t\"LinearBurn\", \n\t\t\t\"LinearDodge\", \n\t\t\t\"LinearLight\", \n\t\t\t\"Luminize\", \n\t\t\t\"Mathematics\", \n\t\t\t\"MinusDst\", \n\t\t\t\"MinusSrc\", \n\t\t\t\"Modulate\", \n\t\t\t\"ModulusAdd\", \n\t\t\t\"ModulusSubtract\", \n\t\t\t\"Multiply\", \n\t\t\t\"None\", \n\t\t\t\"Out\", \n\t\t\t\"Overlay\", \n\t\t\t\"Over\", \n\t\t\t\"PegtopLight\", \n\t\t\t\"PinLight\", \n\t\t\t\"Plus\", \n\t\t\t\"Replace\", \n\t\t\t\"Saturate\", \n\t\t\t\"Screen\", \n\t\t\t\"SoftLight\", \n\t\t\t\"Src\", \n\t\t\t\"SrcAtop\", \n\t\t\t\"SrcIn\", \n\t\t\t\"SrcOut\", \n\t\t\t\"SrcOver\", \n\t\t\t\"VividLight\", \n\t\t\t\"Xor\"\n\t\t] comp {\n\n\t\t_flag = \"-compose \" ++ comp;\n\n\t\tOption_edit caption labels value = this.Compose labels?value;\n\t}\n\tcompose_widget = Compose \"Over\";\n\t// FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string.\n\n\t// FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack\n\n\tcoordinate_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\n\t\t_flag = concat [print x.expr, \",\", print y.expr];\n\t};\n\n\tDistort distort = class\n\t\tOption_string \"Distort\" [\n\t\t\t\"Affine\",\n\t\t\t\"AffineProjection\",\n\t\t\t\"ScaleRotateTranslate\",\n\t\t\t\"SRT\",\n\t\t\t\"Perspective\",\n\t\t\t\"PerspectiveProjection\",\n\t\t\t\"BilinearForward\",\n\t\t\t\"BilinearReverse\",\n\t\t\t\"Polynomial\",\n\t\t\t\"Arc\",\n\t\t\t\"Polar\",\n\t\t\t\"DePolar\",\n\t\t\t\"Barrel\",\n\t\t\t\"BarrelInverse\",\n\t\t\t\"Shepards\",\n\t\t\t\"Resize\"\n\t\t] distort {\n\n\t\t_flag = distort;\n\n\t\tOption_edit caption labels value = this.Distort labels?value;\n\t}\n\tdistort_widget = Distort \"SRT\";\n\n\tDither dither = class\n\t\tOption_string \"Dither\" [\n\t\t\t\"None\",\n\t\t\t\"FloydSteinberg\",\n\t\t\t\"Riemersma\"\n\t\t] dither {\n\n\t\t_flag = \"-dither \" ++ dither;\n\n\t\tOption_edit caption labels value = this.Dither labels?value;\n\t}\n\tdither_widget = Dither \"FloydSteinberg\";\n\n\tEvaluate eval = class\n\t\tOption_string \"Evaluate operation\" [\n\t\t\t\"Abs\",\n\t\t\t\"Add\",\n\t\t\t\"AddModulus\",\n\t\t\t\"And\",\n\t\t\t\"Cos\",\n\t\t\t\"Cosine\",\n\t\t\t\"Divide\",\n\t\t\t\"Exp\",\n\t\t\t\"Exponential\",\n\t\t\t\"GaussianNoise\",\n\t\t\t\"ImpulseNoise\",\n\t\t\t\"LaplacianNoise\",\n\t\t\t\"LeftShift\",\n\t\t\t\"Log\",\n\t\t\t\"Max\",\n\t\t\t\"Mean\",\n\t\t\t\"Median\",\n\t\t\t\"Min\",\n\t\t\t\"MultiplicativeNoise\",\n\t\t\t\"Multiply\",\n\t\t\t\"Or\",\n\t\t\t\"PoissonNoise\",\n\t\t\t\"Pow\",\n\t\t\t\"RightShift\",\n\t\t\t\"Set\",\n\t\t\t\"Sin\",\n\t\t\t\"Sine\",\n\t\t\t\"Subtract\",\n\t\t\t\"Sum\",\n\t\t\t\"Threshold\",\n\t\t\t\"ThresholdBlack\",\n\t\t\t\"ThresholdWhite\",\n\t\t\t\"UniformNoise\",\n\t\t\t\"Xor\"\n\t\t] eval {\n\n\t\t_flag = \"-evaluate \" ++ eval;\n\n\t\tOption_edit caption labels value = this.Evaluate labels?value;\n\t}\n\tevaluate_widget = Evaluate \"Add\";\n\n\tFilter filt = class\n\t\tOption_string \"Filter\" [\n\t\t\t\"default\",\n\t\t\t\"Bartlett\",\n\t\t\t\"Blackman\",\n\t\t\t\"Bohman\",\n\t\t\t\"Box\",\n\t\t\t\"Catrom\",\n\t\t\t\"Cosine\",\n\t\t\t\"Cubic\",\n\t\t\t\"Gaussian\",\n\t\t\t\"Hamming\",\n\t\t\t\"Hann\",\n\t\t\t\"Hermite\",\n\t\t\t\"Jinc\",\n\t\t\t\"Kaiser\",\n\t\t\t\"Lagrange\",\n\t\t\t\"Lanczos\",\n\t\t\t\"Lanczos2\",\n\t\t\t\"Lanczos2Sharp\",\n\t\t\t\"LanczosRadius\",\n\t\t\t\"LanczosSharp\",\n\t\t\t\"Mitchell\",\n\t\t\t\"Parzen\",\n\t\t\t\"Point\",\n\t\t\t\"Quadratic\",\n\t\t\t\"Robidoux\",\n\t\t\t\"RobidouxSharp\",\n\t\t\t\"Sinc\",\n\t\t\t\"SincFast\",\n\t\t\t\"Spline\",\n\t\t\t\"Triangle\",\n\t\t\t\"Welch\"\n\t\t] filt {\n\n\t\t_flag = if filt == \"default\" then \"\" else \"-filter \" ++ filt;\n\n\t\tOption_edit caption labels value = this.Filter labels?value;\n\t}\n\tfilter_widget = Filter \"default\";\n\n\tFunction func = class\n\t\tOption_string \"Function\" [\n\t\t\t\"Polynomial\",\n\t\t\t\"Sinusoid\",\n\t\t\t\"Arcsin\",\n\t\t\t\"Arctan\"\n\t\t] func {\n\n\t\t_flag = func;\n\n\t\tOption_edit caption labels value = this.Function labels?value;\n\t}\n\tfunction_widget = Function \"Polynomial\";\n\n//  \"Polynomial (a[n], a[n-1], ... a[1], a[0])\",\n//  \"Sinusoid (freq, phase, amp, bias)\",\n//  \"Arcsin (width, centre, range, bias)\",\n//  \"Arctan (slope, centre, range, bias)\"\n\n\tGravity gravity = class\n\t\tOption_string \"Gravity\" [\n\t\t\t\"None\",\n\t\t\t\"Center\",\n\t\t\t\"East\",\n\t\t\t\"Forget\",\n\t\t\t\"NorthEast\",\n\t\t\t\"North\",\n\t\t\t\"NorthWest\",\n\t\t\t\"SouthEast\",\n\t\t\t\"South\",\n\t\t\t\"SouthWest\",\n\t\t\t\"West\",\n\t\t\t\"Static\"\n\t\t] gravity {\n\n\t\t_flag = \"-gravity \" ++ gravity;\n\n\t\tOption_edit caption labels value = this.Gravity labels?value;\n\t}\n\tgravity_widget = Gravity \"Center\";\n\n\tImageType imagetype = class\n\t\tOption_string \"Image type\" [\n\t\t\t\"Bilevel\",\n\t\t\t\"ColorSeparation\",\n\t\t\t\"ColorSeparationAlpha\",\n\t\t\t\"ColorSeparationMatte\",\n\t\t\t\"Grayscale\",\n\t\t\t\"GrayscaleAlpha\",\n\t\t\t\"GrayscaleMatte\",\n\t\t\t\"Optimize\",\n\t\t\t\"Palette\",\n\t\t\t\"PaletteBilevelAlpha\",\n\t\t\t\"PaletteBilevelMatte\",\n\t\t\t\"PaletteAlpha\",\n\t\t\t\"PaletteMatte\",\n\t\t\t\"TrueColorAlpha\",\n\t\t\t\"TrueColorMatte\",\n\t\t\t\"TrueColor\"\n\t\t] imagetype {\n\n\t\t_flag = \"-type \" ++ imagetype;\n\n\t\tOption_edit caption labels value = this.ImageType labels?value;\n\t}\n\timagetype_widget = ImageType \"TrueColor\";\n\n\tIntensity intensity = class\n\t\tOption_string \"Intensity (gray conversion)\" [\n\t\t\t\"Average\",\n\t\t\t\"Brightness\",\n\t\t\t\"Lightness\",\n\t\t\t\"MS\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601Luminance\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709Luminance\",\n\t\t\t\"RMS\"\n\t\t] intensity {\n\n\t\t_flag \n\t\t\t= \"-intensity \" ++ intensity, has_intensity\n\t\t\t= \"\";\n\n\t\tOption_edit caption labels value = this.Intensity labels?value;\n\t}\n\tintensity_widget = Intensity \"Rec709Luminance\";\n\n\tInterpolate interp = class\n\t\tOption_string \"Interpolate\" [\n\t\t\t\"default\",\n\t\t\t\"Average\",\n\t\t\t\"Average4\",\n\t\t\t\"Average9\",\n\t\t\t\"Average16\",\n\t\t\t\"Background\",\n\t\t\t\"Bilinear\",\n\t\t\t\"Blend\",\n\t\t\t\"Integer\",\n\t\t\t\"Mesh\",\n\t\t\t\"Nearest\",\n\t\t\t\"NearestNeighbor\",\n\t\t\t\"Spline\"\n\t\t] interp {\n\n\t\t_flag = if interp == \"default\" then \"\" else \"-interpolate \" ++ interp;\n\n\t\tOption_edit caption labels value = this.Interpolate labels?value;\n\t}\n\tinterpolate_widget = Interpolate \"default\";\n\n\tKernel kernel = class\n\t\tOption_string \"Kernel\" [\n\t\t\t\"Unity\",\n\t\t\t\"Gaussian\",\n\t\t\t\"DoG\",\n\t\t\t\"LoG\",\n\t\t\t\"Blur\",\n\t\t\t\"Comet\",\n\t\t\t\"Binomial\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Sobel\",\n\t\t\t\"FreiChen\",\n\t\t\t\"Roberts\",\n\t\t\t\"Prewitt\",\n\t\t\t\"Compass\",\n\t\t\t\"Kirsch\",\n\t\t\t\"Diamond\",\n\t\t\t\"Square\",\n\t\t\t\"Rectangle\",\n\t\t\t\"Disk\",\n\t\t\t\"Octagon\",\n\t\t\t\"Plus\",\n\t\t\t\"Cross\",\n\t\t\t\"Ring\",\n\t\t\t\"Peaks\",\n\t\t\t\"Edges\",\n\t\t\t\"Corners\",\n\t\t\t\"Diagonals\",\n\t\t\t\"LineEnds\",\n\t\t\t\"LineJunctions\",\n\t\t\t\"Ridges\",\n\t\t\t\"ConvexHull\",\n\t\t\t\"ThinSe\",\n\t\t\t\"Skeleton\",\n\t\t\t\"Chebyshev\",\n\t\t\t\"Manhattan\",\n\t\t\t\"Octagonal\",\n\t\t\t\"Euclidean\"\n\t\t\t// FIXME: custom kernel\n\t\t] kernel {\n\n\t\t_flag = kernel;\n\n\t\tOption_edit caption labels value = this.Kernel labels?value;\n\t}\n\tkernel_widget = Kernel \"Unity\";\n\n\tModColSp msp = class\n\t\tOption_string \"modulate colorspace\" [\n\t\t\t\"HCL\", \n\t\t\t\"HCLp\", \n\t\t\t\"HSB\", \n\t\t\t\"HSI\", \n\t\t\t\"HSL\", \n\t\t\t\"HSV\", \n\t\t\t\"HWB\", \n\t\t\t\"LCH\"\n\t\t] msp {\n\n\t\t_flag = \"-set option:modulate:colorspace \" ++ msp;\n\n\t\tOption_edit caption labels value = this.ModColSp labels?value;\n\t}\n\tModColSp_widget = ModColSp \"HSL\";\n\n\tMorphMeth morph = class\n\t\tOption_string \"Method\" [\n\t\t\t\"Correlate\",\n\t\t\t\"Convolve\",\n\t\t\t\"Dilate\",\n\t\t\t\"Erode\",\n\t\t\t\"Close\",\n\t\t\t\"Open\",\n\t\t\t\"DilateIntensity\",\n\t\t\t\"ErodeIntensity\",\n\t\t\t\"CloseIntensity\",\n\t\t\t\"OpenIntensity\",\n\t\t\t\"Smooth\",\n\t\t\t\"EdgeOut\",\n\t\t\t\"EdgeIn\",\n\t\t\t\"Edge\",\n\t\t\t\"TopHat\",\n\t\t\t\"BottomHat\",\n\t\t\t\"HitAndMiss\",\n\t\t\t\"Thinning\",\n\t\t\t\"Thicken\",\n\t\t\t\"Distance\",\n\t\t\t\"IterativeDistance\"\n\t\t] morph {\n\n\t\t_flag = morph;\n\n\t\tOption_edit caption labels value = this.MorphMeth labels?value;\n\t}\n\tmorphmeth_widget = MorphMeth \"Dilate\";\n\n\tNoise noise = class\n\t\tOption_string \"Noise\" [\n\t\t\t\"Gaussian\",\n\t\t\t\"Impulse\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Multiplicative\",\n\t\t\t\"Poisson\",\n\t\t\t\"Random\",\n\t\t\t\"Uniform\"\n\t\t] noise {\n\n\t\t_flag = \"+noise \" ++ noise;\n\n\t\tOption_edit caption labels value = this.Noise labels?value;\n\t}\n\tnoise_widget = Noise \"Gaussian\";\n\n\tPattern pattern = class\n\t\tOption_string \"Noise\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"bricks\",\n\t\t\t\"checkerboard\",\n\t\t\t\"circles\",\n\t\t\t\"crosshatch\",\n\t\t\t\"crosshatch30\",\n\t\t\t\"crosshatch45\",\n\t\t\t\"gray0\",\n\t\t\t\"gray5\",\n\t\t\t\"gray10\",\n\t\t\t\"gray15\",\n\t\t\t\"gray20\",\n\t\t\t\"gray25\",\n\t\t\t\"gray30\",\n\t\t\t\"gray35\",\n\t\t\t\"gray40\",\n\t\t\t\"gray45\",\n\t\t\t\"gray50\",\n\t\t\t\"gray55\",\n\t\t\t\"gray60\",\n\t\t\t\"gray65\",\n\t\t\t\"gray70\",\n\t\t\t\"gray75\",\n\t\t\t\"gray80\",\n\t\t\t\"gray85\",\n\t\t\t\"gray90\",\n\t\t\t\"gray95\",\n\t\t\t\"gray100\",\n\t\t\t\"hexagons\",\n\t\t\t\"horizontal\",\n\t\t\t\"horizontal2\",\n\t\t\t\"horizontal3\",\n\t\t\t\"horizontalsaw\",\n\t\t\t\"hs_bdiagonal\",\n\t\t\t\"hs_cross\",\n\t\t\t\"hs_diagcross\",\n\t\t\t\"hs_fdiagonal\",\n\t\t\t\"hs_horizontal\",\n\t\t\t\"hs_vertical\",\n\t\t\t\"left30\",\n\t\t\t\"left45\",\n\t\t\t\"leftshingle\",\n\t\t\t\"octagons\",\n\t\t\t\"right30\",\n\t\t\t\"right45\",\n\t\t\t\"rightshingle\",\n\t\t\t\"smallfishscales\",\n\t\t\t\"vertical\",\n\t\t\t\"vertical2\",\n\t\t\t\"vertical3\",\n\t\t\t\"verticalbricks\",\n\t\t\t\"verticalleftshingle\",\n\t\t\t\"verticalrightshingle\",\n\t\t\t\"verticalsaw\"\n\t\t] pattern {\n\n\t\t_flag = \"pattern:\" ++ pattern;\n\n\t\tOption_edit caption labels value = this.Pattern labels?value;\n\t}\n\tpattern_widget = Pattern \"bricks\";\n\n\tResizeType resizet = class\n\t\tOption_string \"Resize type\" [\n\t\t\t\"resize\", \n\t\t\t\"scale\",\n\t\t\t\"sample\",\n\t\t\t\"adaptive-resize\"\n\t\t] resizet {\n\n\t\t_flag = resizet;\n\n\t\tOption_edit caption labels value = this.ResizeType labels?value;\n\t}\n\tResizeType_widget = ResizeType \"resize\";\n\n\tSize_widget = class {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width (pixels)\" 64;\n\t\theight = Expression \"Height (pixels)\" 64;\n\n\t\t_flag = \"-size \" ++\n\t\t\tprint width.expr ++ \"x\" ++ print height.expr;\n\n\t};\n\n\tStatType statt = class\n\t\tOption_string \"Statistic type\" [\n\t\t\t\"Gradient\", \n\t\t\t\"Maximum\", \n\t\t\t\"Mean\", \n\t\t\t\"Median\", \n\t\t\t\"Minimum\", \n\t\t\t\"Mode\", \n\t\t\t\"Nonpeak\", \n\t\t\t\"StandardDeviation\"\n\t\t] statt {\n\n\t\t_flag = statt;\n\n\t\tOption_edit caption labels value = this.StatType labels?value;\n\t}\n\tStatType_widget = StatType \"Mean\";\n\n\tVirtualPixel vp = class\n\t\tOption_string \"Virtual pixel\" [\n\t\t\t\"Background\", \n\t\t\t\"Black\", \n\t\t\t\"CheckerTile\", \n\t\t\t\"Dither\", \n\t\t\t\"Edge\", \n\t\t\t\"Gray\", \n\t\t\t\"HorizontalTile\", \n\t\t\t\"HorizontalTileEdge\", \n\t\t\t\"Mirror\", \n\t\t\t\"None\",\n\t\t\t\"Random\",\n\t\t\t\"Tile\",\n\t\t\t\"Transparent\",\n\t\t\t\"VerticalTile\",\n\t\t\t\"VerticalTileEdge\",\n\t\t\t\"White\"\n\t\t] vp {\n\n\t\t_flag = \"-virtual-pixel \" ++ vp;\n\n\t\t_isBackground = (vp == \"Background\");\n\n\t\tOption_edit caption labels value = this.VirtualPixel labels?value;\n\t}\n\tVirtualPixel_widget = VirtualPixel \"Edge\";\n\n\tVirtualPixelBack_widget = class {\n\t\tvirtpix = Magick.VirtualPixel_widget;\n\t\tbackground = Magick.background_widget;\n\t\t_flag = (if virtpix._isBackground then (background._flag ++ \" \") else \"\")\n\t\t\t++ virtpix._flag;\n\t}\n\n\tGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tAnnotGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print shearX.expr, \"x\", print shearY.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tOffsetGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag = concat [format hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tWhxyGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFrameGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\toutbev = Expression \"Outer bevel thickness\" 0;\n\t\tinbev = Expression \"Inner bevel thickness\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat outbev, format inbev]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFont_widget = class {\n\t\t_vislevel = 3;\n\n\t\tfamily = Option_string \"Family\" [\n\t\t\t\"Arial\",\n\t\t\t\"ArialBlack\",\n\t\t\t\"AvantGarde\",\n\t\t\t\"BitstreamCharter\",\n\t\t\t\"Bookman\",\n\t\t\t\"CenturySchoolbook\",\n\t\t\t\"ComicSansMS\",\n\t\t\t\"Courier\",\n\t\t\t\"CourierNew\",\n\t\t\t\"DejaVuSans\",\n\t\t\t\"DejaVuSansMono\",\n\t\t\t\"DejaVuSerif\",\n\t\t\t\"Dingbats\",\n\t\t\t\"FreeMono\",\n\t\t\t\"FreeSans\",\n\t\t\t\"FreeSerif\",\n\t\t\t\"Garuda\",\n\t\t\t\"Georgia\",\n\t\t\t\"Helvetica\",\n\t\t\t\"HelveticaNarrow\",\n\t\t\t\"Impact\",\n\t\t\t\"LiberationMono\",\n\t\t\t\"LiberationSans\",\n\t\t\t\"LiberationSerif\",\n\t\t\t\"NewCenturySchlbk\",\n\t\t\t\"Palatino\",\n\t\t\t\"Purisa\",\n\t\t\t\"Symbol\",\n\t\t\t\"Times\",\n\t\t\t\"TimesNewRoman\",\n\t\t\t\"Ubuntu\",\n\t\t\t\"Verdana\",\n\t\t\t\"Webdings\"\n\t\t] \"Arial\";\n\t\tstyle = Option_string \"Style\" [\n\t\t\t\"Any\", \"Italic\", \"Normal\", \"Oblique\"\n\t\t] \"Normal\";\n\t\tweight = Scale \"Weight\" 1 800 400;\n\t\tsize = Scale \"Point size\" 1 100 12;\n\t\tstretch = Option_string \"Stretch\" [\n\t\t\t\"Any\", \"Condensed\", \"Expanded\", \"ExtraCondensed\", \"ExtraExpanded\", \n\t\t\t\"Normal\", \"SemiCondensed\", \"SemiExpanded\", \"UltraCondensed\", \n\t\t\t\"UltraExpanded\"\n\t\t] \"Normal\";\n\n\t\t_flag = join_sep \" \" [\n\t\t\t\t\"-family\", family.item,\n\t\t\t\t\"-weight\", print weight.value,\n\t\t\t\t\"-pointsize\", print size.value,\n\t\t\t\t\"-style\", style.item,\n\t\t\t\t\"-stretch\", stretch.item];\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.40/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = any (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && all (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* Test list length ... quicker than len x == n for large lists.\n */\nis_list_len n x\n\t= true, x == [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len (n - 1) (tl x);\n\nis_list_len_more n x\n\t= true, x != [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len_more (n - 1) (tl x);\n\nis_list_len_more_equal n x\n\t= true, n == 0\n\t= false, x == [] \n\t= is_list_len_more_equal (n - 1) (tl x);\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, all (map is_obj l)\n\t= true, all (map is_list l) &&\n\t\tall (map (not @ is_obj) l) &&\n\t\tall (map is_rectangular l) &&\n\t\tis_list_len_more 0 l &&\n\t\tall (map (is_list_len (len (hd l))) (tl l))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && is_list_len (len (hd l)) l;\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_NULL x = is_instanceof \"NULL\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Plot x = is_instanceof \"Plot\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && all (map xy l)\n{\n\txy l = is_real_list l && is_list_len 2 l;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && any (map is_Group l)\n\t= any (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= oo_unary_function get_type_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_type\")\n{\n\tget_type_op = Operator \"get_type\" get_type \n\t\tOperator_type.COMPOUND false;\n\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\t// can have alpha, hence we let bands be one more than you might think\n\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.GREY16, type == Image_type.GREY16 && is_bands 1\n\t\t= Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && \n\t\t\t(width == 1 || height == 1)\n\t\t= Image_type.B_W, is_bands 1 \n\t\t= Image_type.CMYK, type == Image_type.CMYK && is_bands 4\n\t\t= type, is_colorimetric && is_bands 3\n\t\t= Image_type.sRGB, !is_colorimetric && is_bands 3\n\t\t= Image_type.MULTIBAND, !is_colorimetric && !is_bands 3\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\n\t\t// is bands n, with an optional alpha (ie. can be n + 1 too)\n\t\tis_bands n = bands == n || bands == n + 1;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= oo_unary_function get_format_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_format\")\n{\n\tget_format_op = Operator \"get_format\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= oo_unary_function get_bits_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bits\")\n{\n\tget_bits_op = Operator \"get_bits\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= oo_unary_function get_bands_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bands\")\n{\n\tget_bands_op = Operator \"get_bands\" get_bands \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= oo_unary_function get_coding_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_coding\")\n{\n\tget_coding_op = Operator \"get_coding\" get_coding \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= oo_unary_function get_xres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xres\")\n{\n\tget_xres_op = Operator \"get_xres\" get_xres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= oo_unary_function get_yres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yres\")\n{\n\tget_yres_op = Operator \"get_yres\" get_yres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= oo_unary_function get_xoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xoffset\")\n{\n\tget_xoffset_op = Operator \"get_xoffset\" get_xoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= oo_unary_function get_yoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yoffset\")\n{\n\tget_yoffset_op = Operator \"get_yoffset\" get_yoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= oo_unary_function get_image_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_image\")\n{\n\tget_image_op = Operator \"get_image\" get_image \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= oo_unary_function get_number_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_number\")\n{\n\tget_number_op = Operator \"get_number\" get_number \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= oo_unary_function get_real_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_real\")\n{\n\tget_real_op = Operator \"get_real\" get_real \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= oo_unary_function get_width_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_width\")\n{\n\tget_width_op = Operator \"get_width\" get_width \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= oo_unary_function get_height_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_height\")\n{\n\tget_height_op = Operator \"get_height\" get_height \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= oo_unary_function get_left_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_left\")\n{\n\tget_left_op = Operator \"get_left\" get_left \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= oo_unary_function get_top_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_top\")\n{\n\tget_top_op = Operator \"get_top\" get_top \n\t\tOperator_type.COMPOUND false;\n}\n\n// like has/get member, but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.40/_stdenv.def",
    "content": "/* optional args to functions\n */\n\nget_option options defaults f\n\t= error (_ \"unknown parameter \" ++ f), hits == []\n\t= hits?0\n{\n\thits = [v :: [n, v] <- options ++ defaults; n == f];\n}\n\n/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\nidivide a b = (int) ((int) a / (int) b);\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\n// 'difference' is defined in _list\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the function we call for \"a -> v\" expressions\nmksvpair s v\n\t= [s, v], is_string s\n\t= error \"not str on lhs of ->\";\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error (\"unimplemented vector operation: \" ++ op_name)\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n// make a name value pair\nmknvpair n v\n\t= [n, v], is_string n\n\t= error \"not [char] on LHS of =>\";\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined, has_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nbandand x\n\t= oo_unary_function bandand_op x, is_class x\n\t= foldr1 bitwise_and (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandand\")\n{\n\tbandand_op = Operator \"bandand\" bandand Operator_type.COMPOUND_REWRAP false;\n}\n\nbandor x\n\t= oo_unary_function bandor_op x, is_class x\n\t= foldr1 bitwise_or (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandor\")\n{\n\tbandor_op = Operator \"bandor\" bandor Operator_type.COMPOUND_REWRAP false;\n}\n\nsum x\n\t= oo_unary_function sum_op x, is_class x\n\t= im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x\n\t= sum_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"sum\")\n{\n\tsum_op = Operator \"sum\" sum Operator_type.COMPOUND false;\n\n\t// add elements in a nested-list thing\n\tsum_list l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nproduct x\n\t= oo_unary_function product_op x, is_class x\n\t= product_list x, is_list x \n\t// (product image) doesn't make much sense :(\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"product\")\n{\n\tproduct_op = Operator \"product\" product Operator_type.COMPOUND false;\n\n\tproduct_list l\n\t\t= foldr prod 1 l\n\t{\n\t\tprod x total\n\t\t\t= total * product x, is_list x\n\t\t\t= total * x;\n\t}\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\nskew x\n\t= oo_unary_function skew_op x, is_class x\n\t= sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x \n\t= sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"skew\")\n{\n\tskew_op = Operator \"skew\" skew Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN \n\t\t= w * h * b, is_image x'\n\t\t= len x';\n}\n\nkurtosis x\n\t= oo_unary_function kurtosis_op x, is_class x\n\t= sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x \n\t= sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"kurtosis\")\n{\n\tkurtosis_op = Operator \"kurtosis\" kurtosis Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN\n\t\t= len x', is_list x';\n\t\t= w * h * b;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image_hist x, is_image x && \n\t\t(fmt == Image_format.UCHAR || fmt == Image_format.USHORT)\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tfmt = get_format x;\n\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean, for any image type\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n\n\t// image mean for 8 and 16-bit unsigned images\n\t// we can use a histogram, yay, and save a pass through the image\n\tmeanze_image_hist i\n\t\t= sum / N\n\t{\n\t\t// histogram, knock out zeros\n\t\thist = hist_find i;\n\t\tblack = image_new 1 1 (get_bands hist) \n\t\t\t(get_format hist) (get_coding hist) (get_type hist) 0 0 0;\n\t\thistze = insert 0 0 black hist;\n\n\t\t// matching identity\n\t\tiden\n\t\t\t= im_identity_ushort (get_bands hist) (get_width hist),\n\t\t\t\t(get_width hist) > 256\n\t\t\t= im_identity (get_bands hist);\n\n\t\t// number of non-zero pixels\n\t\tN = mean histze * 256;\n\n\t\t// sum of pixels\n\t\tsum = mean (hist * iden) * 256;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_tile_cache_random x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (\\row [row?x']) obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\" ++ \": \" ++\n\t\tjoin_sep \", \" (map print [cond, in1, in2]))\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x \n\t\t\t= to_image_size target_width target_height \n\t\t\t\ttarget_bands target_format x;\n\n\t\t[then_image, else_image] = map to_image [then_part, else_part];\n\n\t\tblend_result_image = image_set_type target_type \n\t\t\t(im_blend cond then_image else_image);\n\t}\n}\n\n// do big first: we want to keep big's class, if possible\n// eg. big is a Plot, small is a 1x1 Image\ninsert x y small big\n\t= oo_binary'_function insert_op small big, is_class big\n\t= oo_binary_function insert_op small big, is_class small\n\t= im_insert big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ndecode im\n\t= oo_unary_function decode_op im, is_class im\n\t= decode_im im, is_image im\n\t= error (_ \"bad arguments to \" ++ \"decode\")\n{\n\tdecode_op = Operator \"decode\" \n\t\tdecode Operator_type.COMPOUND_REWRAP false;\n\n\tdecode_im im\n\t\t= im_LabQ2Lab im, get_coding im == Image_coding.LABPACK\n\t\t= im_rad2float im, get_coding im == Image_coding.RAD\n\t\t= im;\n}\n\nmeasure_draw across down measure image\n    = mark\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n\n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::  \n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n    x = map (extract 0) cods;\n    y = map (extract 1) cods;\n\n    outer = mkim [$pixel => 255] sample_width sample_height 1;\n    inner = mkim [] (sample_width - 4) (sample_height - 4) 1;\n    patch = insert 2 2 inner outer;\n\n    bg = mkim [] image.width image.height 1;\n\n    mask = Image (im_insertset bg.value patch.value x y);\n\n    image' = colour_transform_to Image_type.sRGB image;\n\n    mark = if mask then Vector [0, 255, 0] else image';\n}\n\nmeasure_sample across down measure image\n    = measures\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n                \n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::\n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n\n\timage' = decode image;\n    patches = map (\\p extract_area p?0 p?1 sample_width sample_height image') \n\t\tcods;\n    measures = Matrix (map (map mean) (map bandsplit patches));\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ninvert x\n\t= oo_unary_function invert_op x, is_class x\n\t= im_invert x, is_image x\n\t= 255 - x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"invert\")\n{\n\tinvert_op = Operator \"invert\" invert Operator_type.COMPOUND false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate interp angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_affinei_all image interp.value a (-b) b a 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\t(rotate interp) Operator_type.COMPOUND_REWRAP false;\n\ta = cos angle;\n\tb = sin angle;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_lr\")\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin_lr Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert (get_width a) 0 b a;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_tb\")\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin_tb Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert 0 (get_height a) b a;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\t// The [[real]] can contain 128 values ... squeeze them out!\n\timage = im_mask2vips (Matrix m2) == 255;\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\" ++ \": \" ++ \n\t\t\"conv (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvf mask image\n\t= oo_unary_function convf_op image, is_class image\n\t= im_conv_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convf\" ++ \": \" ++ \n\t\t\"convf (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconvf_op = Operator \"convf\" \n\t\t(convf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\naconvsep layers mask image \n\t= oo_unary_function aconvsep_op image, is_class image\n\t= im_aconvsep image (to_matrix mask) (to_real layers), is_image image\n\t= error (_ \"bad arguments to \" ++ \"aconvsep\")\n{\n\taconvsep_op = Operator \"aconvsep\" \n\t\t(aconvsep layers mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsep_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\ngreyc iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx x\n\t= oo_unary_function greyc_op x, is_class x\n\t= greyc_im x, is_image x\n\t= error (_ \"bad argument\" ++ \" (\" ++ print x ++ \") to \" ++ \"greyc\")\n{\n\tgreyc_op = Operator \"greyc\" (greyc\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im x = im_greyc x\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\ngreyc_mask iterations amplitude sharpness anisotropy alpha\n\tsigma dl da gauss_prec interpolation fast_approx mask x\n\t= oo_binary_function greyc_mask_op mask x, is_class mask\n\t= oo_binary'_function greyc_mask_op mask x, is_class x\n\t= greyc_im mask x, is_image mask && is_image x\n\t= error (_ \"bad arguments\" ++ \n\t\t\" (\" ++ print mask ++ \", \" ++ print x ++ \") \" ++\n\t\t\"to \" ++ \"greyc\")\n{\n\tgreyc_mask_op = Operator \"greyc_mask\" (greyc_mask\n\t\t\titerations amplitude sharpness anisotropy alpha\n\t\t\tsigma dl da gauss_prec interpolation fast_approx)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\tgreyc_im mask x = im_greyc_mask x mask\n\t\titerations amplitude sharpness anisotropy alpha\n\t\tsigma dl da gauss_prec interpolation fast_approx;\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_indexed index value\n\t= oo_binary_function hist_find_indexed_op index value, is_class index\n\t= oo_binary'_function hist_find_indexed_op index value, is_class value\n\t= im_hist_indexed index value, is_image index && is_image value\n\t= error (_ \"bad arguments to \" ++ \"hist_find_indexed\")\n{\n\thist_find_indexed_op = Operator \"hist_find_indexed\" \n\t\t(compose (compose Plot_histogram) hist_find_indexed) \n\t\t\tOperator_type.COMPOUND false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h \n\t\t= (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h\n\t{\n\t\t// up the format so it can represent the whole range of\n\t\t// possible values from this mask\n\t\tfmt x\n\t\t\t= Image_format.SHORT, \n\t\t\t\tx == Image_format.UCHAR || x == Image_format.CHAR\n\t\t\t= Image_format.INT, \n\t\t\t\tx == Image_format.USHORT || x == Image_format.SHORT ||\n\t\t\t\tx == Image_format.UINT \n\t\t\t= x;\n\t}\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_inv hist \n\t= oo_unary_function hist_inv_op hist, is_class hist\n\t= inv hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_inv\")\n{\n\thist_inv_op = Operator \"hist_inv\" \n\t\thist_inv Operator_type.COMPOUND_REWRAP false;\n\n\tinv im\n\t\t= im_invertlut (to_matrix im''') len\n\t{\n\t\t// need a vertical doublemask\n\t\tim' \n\t\t\t= rot90 im, get_width im > 1 && get_height im == 1 \n\t\t\t= im, get_width im == 1 && get_height im > 1\n\t\t\t= error (_ \"not a hist\");\n\t\tlen = get_height im';\n\n\t\t// values must be scaled to 0 - 1\n\t\tim'' = im' / (max im');\n\t\t\n\t\t// add an index column on the left\n\t\t// again, must be in 0-1\n\t\ty = ((make_xy 1 len)?1) / len;\n\t\tim''' = y ++ im'';\n\t}\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= lhisteq image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n\n\t// loop over bands, if necessary\n\tlhisteq im\n\t\t= im_lhisteq im (to_real w) (to_real h), get_bands im == 1\n\t\t= (foldl1 join @ map lhisteq @ bandsplit) im;\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nresize interp xfac yfac image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\t// is this interpolation nearest-neighbour?\n\tis_nn x = x.type == Interpolate_type.NEAREST_NEIGHBOUR;\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// upscale by any factor, nearest neighbour \n\t\t// upscale by integer part, then affine to exact size\n\t\t= scale xg?1 yg?1 (im_zoom im xg?0 yg?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// downscale by any factor, nearest neighbour \n\t\t// downscale by integer part, then affine to exact size\n\t\t= scale xs?1 ys?1 (im_subsample im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// upscale by any factor with affine\n\t\t= scale xfac' yfac' im,\n\t\t\txfac' >= 1 && yfac' >= 1 \n\n\t\t// downscale by any factor, bilinear\n\t\t// block shrink by integer factor, then resample to \n\t\t// exact with affine\n\t\t= scale xs?1 ys?1 (im_shrink im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 \n\n\t\t= error (\"resize: unimplemented argument combination:\\n\" ++ \n\t\t\t\"  xfac = \" ++ print xfac' ++ \"\\n\" ++\n\t\t\t\"  yfac = \" ++ print yfac' ++ \"\\n\" ++\n\t\t\t\"  interp = \" ++ print interp ++ \" (\" ++\n\t\t\t\tInterpolate_type.descriptions?interp.type ++ \")\")\n\t{\n\t\t// convert a float scale to integer plus fraction\n\t\t// eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25)\n\t\tbreak f = [floor f, f / floor f];\n\n\t\t// same, but for downsizing ... turn a float scale which is less than\n\t\t// 1 into an int shrink and a float scale\n\n\t\t// complicated: the int shrink may round the size down (eg. imagine\n\t\t// subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide\n\t\t// image, not a 3.666 pixel wide image), so pass in the size of image\n\t\t// we are operating on and adjust for any rounding\n\t\t\n\t\t// so ... x is (eg.) 467, f is (eg. 128/467, about 0.274)\n\t\trbreak x f \n\t\t\t= [int_shrink, float_resample]\n\t\t{\n\t\t\t// the size of image we are aiming for after the combined int and\n\t\t\t// float resample\n\t\t\tx' = x * f;\n\n\t\t\t// int part\n\t\t\tint_shrink = floor (1 / f);\n\n\t\t\t// size after int shrink\n\t\t\tx'' = floor (x / int_shrink);\n\n\t\t\t// therefore what we need for the float part\n\t\t\tfloat_resample = x' / x'';\n\t\t}\n\n\t\twidth = get_width im;\n\t\theight = get_height im;\n\n\t\t// grow and shrink factors\n\t\txg = break xfac';\n\t\tyg = break yfac';\n\t\txs = rbreak width xfac';\n\t\tys = rbreak height yfac';\n\n\t\t// resize\n\t\tscale xfac yfac im\n\t\t\t= im_affinei_all im interp.value xfac 0 0 yfac 0 0;\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\n\n// Given a xywh rect, flip it around so wh are always positive\nrect_normalise x y w h \n\t= [x', y', w', h']\n{\n\tx'\n\t\t= x + w, w < 0\n\t\t= x;\n\ty'\n\t\t= y + h, h < 0\n\t\t= y;\n\tw' = abs w;\n\th' = abs h;\n}\n\ndraw_flood_blob x y ink image\n\t= oo_unary_function draw_flood_blob_op image, is_class image\n\t= im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood_blob\")\n{\n\tdraw_flood_blob_op = Operator \"draw_flood_blob\" \n\t\t(draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_flood x y ink image\n\t= oo_unary_function draw_flood_op image, is_class image\n\t= im_draw_flood image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood\")\n{\n\tdraw_flood_op = Operator \"draw_flood\" \n\t\t(draw_flood x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* This version of draw_rect uses insert_noexpand and will be fast, even for\n * huge images.\n */\ndraw_rect_width x y w h f t ink image\n\t= oo_unary_function draw_rect_width_op image, is_class image\n\t= my_draw_rect_width image (to_int x) (to_int y) \n\t\t(to_int w) (to_int h) (to_int f) (to_int t) ink, \n\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_width\")\n{\n\tdraw_rect_width_op = Operator \"draw_rect_width\" \n\t\t(draw_rect_width x y w h f t ink) \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\tmy_draw_rect_width image x y w h f t ink\n\t\t= insert x' y' (block w' h') image, f == 1\n\t\t= (insert x' y' (block w' t) @ \n\t\t\tinsert (x' + w' - t) y' (block t h') @ \n\t\t\tinsert x' (y' + h' - t) (block w' t) @ \n\t\t\tinsert x' y' (block t h')) image\n\t{\n\t\tinsert = insert_noexpand;\n\t\tblock w h = image_new w h (get_bands image) (get_format image)\n\t\t\t(get_coding image) (get_type image) ink' 0 0;\n\t\tink' \n\t\t\t= Vector ink, is_list ink\n\t\t\t= ink;\n\t\t[x', y', w', h'] = rect_normalise x y w h;\n\t}\n}\n\n/* Default to 1 pixel wide edges.\n */\ndraw_rect x y w h f ink image\n\t= draw_rect_width x y w h f 1 ink image;\n\n/* This version of draw_rect uses the paintbox rect draw operation. It is an\n * inplace operation and will use bucketloads of memory.\n */\ndraw_rect_paintbox x y w h f ink image\n\t= oo_unary_function draw_rect_op image, is_class image\n\t= im_draw_rect image (to_real x) (to_real y) \n\t\t(to_real w) (to_real h) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_paintbox\")\n{\n\tdraw_rect_op = Operator \"draw_rect\" \n\t\t(draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_circle x y r f ink image\n\t= oo_unary_function draw_circle_op image, is_class image\n\t= im_draw_circle image (to_real x) (to_real y) \n\t\t(to_real r) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_circle\")\n{\n\tdraw_circle_op = Operator \"draw_circle\" \n\t\t(draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_line x1 y1 x2 y2 ink image\n\t= oo_unary_function draw_line_op image, is_class image\n\t= im_draw_line image (to_real x1) (to_real y1) \n\t\t(to_real x2) (to_real y2) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_line\")\n{\n\tdraw_line_op = Operator \"draw_line\" \n\t\t(draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (\\x x % base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (\\x idivide x base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= NULL, any (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n/* Linear regression. Return a class with the stuff we need in.\n * from s15.2, p 665 NR in C\n */\nlinreg xes yes\n    = obj\n{\n    obj = class {\n        // in case we ever get shown in the workspace\n        _vislevel = 2;\n\n        slope = sum [t * y :: [t, y] <- zip2 tes yes] / st2;\n        intercept = (sy - sx * slope) / ss;\n\n        chi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes];\n\n        siga = (chi2 / (ss - 2)) ** 0.5 *\n            ((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5;\n        sigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5;\n\n        // for compat with linregw, see below\n        q = 1.0;\n    }\n\n    ss = len xes;\n    sx = sum xes;\n    sy = sum yes;\n    sxoss = sx / ss;\n\n    tes = [x - sxoss :: x <- xes];\n    st2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Weighted linear regression. Xes, yes and a list of deviations.\n */\nlinregw xes yes devs \n\t= obj\n{\n\tobj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: \n\t\t\t[x, y, sd] <- zip3 xes yes devs];\n\n\t\tsiga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (1 / st2) ** 0.5;\n\n\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\t}\n\n\twt = [sd ** -0.5 :: sd <- devs];\n\n\tss = sum wt;\n\tsx = sum [x * w :: [x, w] <- zip2 xes wt];\n\tsy = sum [y * w :: [y, w] <- zip2 yes wt];\n\tsxoss = sx / ss;\n\n\ttes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Clustering: pass in a list of points, repeatedly merge the\n * closest two points until no two points are closer than the threshold.\n * Return [merged-points, corresponding-weights]. A weight is a list of the\n * indexes we merged to make that point, ie. len weight == how significant\n * this point is.\n *\n * eg. \n *\tcluster 12 [152,154,155,42,159] == \n *\t\t[[155,42],[[1,2,0,4],[3]]]\n */\ncluster thresh points\n\t= oo_unary_function cluster_op points, is_class points\n\t// can't use [0..len points - 1], in case len points == 0\n\t= merge [points, map (converse cons []) (take (len points) [0 ..])],\n\t\tis_list points\n\t= error (_ \"bad arguments to \" ++ \"cluster\")\n{\n\tcluster_op = Operator \"cluster\" \n\t\t(cluster thresh) Operator_type.COMPOUND false;\n\n\tmerge x\n\t\t= x, m < 2 || d > thresh\n\t\t= merge [points', weights']\n\t{\n\t\t[points, weights] = x;\n\t\tm = len points;\n\n\t\t// generate indexes of all possible pairs, avoiding comparing a thing \n\t\t// to itself, and assuming that dist is reflexive\n\t\t// first index is always less than 2nd index\n\t\t// the +1,+2 makes sure we have an increasing generator, otherwise we\n\t\t// can get [3 .. 4] (for example), which will make a decreasing\n\t\t// sequence\n\t\tpairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]];\n\n\t\t// distance function\n\t\t// arg is eg. [3,1], meaning get distance from point 3 to point 1\n\t\tdist x \n\t\t\t= abs (points?i - points?j)\n\t\t{\n\t\t\t[i, j] = x;\n\t\t}\n\n\t\t// smallest distance, then the two points we merge\n\t\tp = minpos (map dist pairs);\n\t\td = dist pairs?p;\n\t\t[i, j] = pairs?p;\n\n\t\t// new point and new weight\n\t\tnw = weights?i ++ weights?j;\n\t\tnp = (points?i * len weights?i + points?j * len weights?j) / len nw;\n\n\t\t// remove element i from a list\n\t\tremove i l = take i l ++ drop (i + 1) l;\n\n\t\t// remove two old points, add the new merged one\n\t\t// i < j (see \"pairs\", above)\n\t\tpoints' = np : remove i (remove j points);\n\t\tweights' = nw : remove i (remove j weights);\n\t}\n}\n\n/* Extract the area of an image around an arrow.\n * Transform the image to make the arrow horizontal, then displace by hd and\n * vd pxels, then cut out a bit h pixels high centered on the arrow.\n */\nextract_arrow hd vd h arrow\n\t= extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im'\n{\n\t// the line as a polar vector\n\tpv = polar (arrow.width, arrow.height);\n\ta = im pv;\n\n\t// smallest rotation that will make the line horizontal\n\ta'\n\t\t= 360 - a, a > 270\n\t\t= 180 - a, a > 90\n\t\t= -a;\n\n\tim' = rotate Interpolate_bilinear a' arrow.image;\n\n\t// look at the start and end of the arrow, pick the leftmost\n\tp\n\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t= (arrow.right, arrow.bottom);\n\n\t// transform that point to im' space\n\tp' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset);\n}\n\n/* You'd think these would go in _convert, but they are not really colour ops,\n * so put them here.\n */\nrad2float image\n\t= oo_unary_function rad2float_op image, is_class image\n\t= im_rad2float image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"rad2float\")\n{\n\trad2float_op = Operator \"rad2float\" \n\t\trad2float Operator_type.COMPOUND_REWRAP false;\n}\n\nfloat2rad image\n\t= oo_unary_function float2rad_op image, is_class image\n\t= im_float2rad image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"float2rad\")\n{\n\tfloat2rad_op = Operator \"float2rad\" \n\t\tfloat2rad Operator_type.COMPOUND_REWRAP false;\n}\n\nsegment x\n\t= oo_unary_function segment_op x, is_class x\n\t= image', is_image x \n\t= error (_ \"bad arguments to \" ++ \"segment\")\n{\n\tsegment_op = Operator \"segment\" \n\t\tsegment Operator_type.COMPOUND_REWRAP false;\n\n\t[image, nsegs] = im_segment x;\n\timage' = im_copy_set_meta image \"n-segments\" nsegs;\n}\n\npoint a b\n\t= oo_binary_function point_op a b, is_class a\n\t= oo_binary'_function point_op a b, is_class b\n\t= im_read_point b x y, is_image b\n\t= [b?x?y], is_matrix b\n\t= [b?x], is_real_list b && y == 0\n\t= [b?y], is_real_list b && x == 0\n\t= error (_ \"bad arguments to \" ++ \"point\")\n{\n\tpoint_op = Operator \"point\" \n\t\t(\\a\\b Vector (point a b)) Operator_type.COMPOUND false;\n\n\t(x, y) \n\t\t= a, is_complex a;\n\t\t= (a?0, a?1), is_real_list a && is_list_len 2 a\n\t\t= error \"bad position format\";\n}\n\n/* One image in, one out. \n */\nsystem_image command x\n\t= oo_unary_function system_image_op x, is_class x\n\t= system x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"system_image\")\n{\n\tsystem_image_op = Operator \"system_image\" \n\t\t(system_image command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem im\n\t\t= image_out\n\t{\n\t\t[image_out, log] = \n\t\t\tim_system_image (get_image im) \"%s.tif\" \"%s.tif\" command;\n\t}\n}\n\n/* Two images in, one out. \n */\nsystem_image2 command x1 x2\n\t= oo_binary_function system_image2_op x1 x2, is_class x1\n\t= oo_binary'_function system_image2_op x1 x2, is_class x2\n\t= system x1 x2, is_image x1 && is_image x2\n\t= error (_ \"bad arguments to \" ++ \"system_image2\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image2 command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Three images in, one out. \n */\nsystem_image3 command x1 x2 x3\n\t= oo_binary_function system_image2_op x2 x3, is_class x2\n\t= oo_binary'_function system_image2_op x2 x3, is_class x3\n\t= system x1 x2 x3, is_image x1 && is_image x2 && is_image x3\n\t= error (_ \"bad arguments to \" ++ \"system_image3\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image3 command x1) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2 x3\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2, x3], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Zero images in, one out. \n */\nsystem_image0 command \n\t= Image image_out\n{\n\t[image_out] = vips_call \"system\" [command] [\n\t\t$out => true,\n\t\t$out_format => \"%s.tif\" \n\t];\n}\n\nhough_line w h x \n\t= oo_unary_function hough_line_op x, is_class x\n\t= hline (to_real w) (to_real h) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_line\")\n{\n\though_line_op = Operator \"hough_line\" \n\t\t(hough_line w h) Operator_type.COMPOUND_REWRAP false;\n\n\thline w h x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_line\" [x] [\n\t\t\t$width => w, \n\t\t\t$height => h\n\t\t];\n\t}\n}\n\nhough_circle s mn mx x \n\t= oo_unary_function hough_circle_op x, is_class x\n\t= hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_circle\")\n{\n\though_circle_op = Operator \"hough_circle\" \n\t\t(hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false;\n\n\thcircle s mn mx x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_circle\" [x] [\n\t\t\t$scale => s, \n\t\t\t$min_radius => mn, \n\t\t\t$max_radius => mx\n\t\t];\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.40/_types.def",
    "content": "/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary (\\a op.fn a x) this,\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// we can't call map_trinary directly, since it uses Group and we\n\t// don't support mutually recursive top-level functions :-(\n\t// copy-paste it here, keep in sync with the version in _stdenv\n\tmap_nary fn args\n\t\t= fn args, groups == []\n\t\t= Group (map process [0, 1 .. shortest - 1])\n\t{\n\t\tgroups = filter is_Group args;\n\t\n\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\tprocess n\n\t\t\t= NULL, any (map (is_noval n) args)\n\t\t\t= map_nary fn (map (extract n) args)\n\t\t{\n\t\t\textract n arg\n\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t= arg;\n\t\n\t\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t\t}\n\t}\n\n\t// need ite as a true trinary\n\tite a b c = if a then b else c;\n\n\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t];\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\n\t\t[op.fn this.value x,\n\t\t\top.type == Operator_type.COMPOUND]\n\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[is_list_len 3 value, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.item colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum \"Colour space\" Image_type.colour_spaces default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\n/* An option whose value is a string rather than a number.\n */\nOption_string caption labels item = class\n\tOption caption labels (index (equal item) labels) {\n\tOption_edit caption labels value \n\t\t= this.Option_string caption labels (labels?value);\n}\n\n/* Make an option from an enum.\n */\nOption_enum caption enum item = class\n\tOption_string caption enum.names item {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing item;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum caption enum (enum.names?value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNONE = 0;\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNONE = 0;\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n\tRAD = 6;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* Extract a column.\n\t */\n\tcolumn n = map (extract n) value;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (column col) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (column from);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = this.column 0; \n\tthings = this.column 1; \n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tHISTOGRAM = 10;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tARRAY = 27;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t$MULTIBAND => MULTIBAND,\n\t\t$B_W => B_W,\n\t\t$HISTOGRAM => HISTOGRAM,\n\t\t$XYZ => XYZ,\n\t\t$LAB => LAB,\n\t\t$CMYK => CMYK,\n\t\t$LABQ => LABQ,\n\t\t$RGB => RGB,\n\t\t$UCS => UCS,\n\t\t$LCH => LCH,\n\t\t$LABS => LABS,\n\t\t$sRGB => sRGB,\n\t\t$YXY => YXY,\n\t\t$FOURIER => FOURIER,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$ARRAY => ARRAY\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options generated from this, so match the order to the order in the\n\t * Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t$sRGB => sRGB,\n\t\t$Lab => LAB,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t$Mono => B_W,\n\t\t$sRGB => sRGB,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$Lab => LAB,\n\t\t$LabQ => LABQ,\n\t\t$LabS => LABS,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \n\t\t// \"Image v == 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\t// if one of then/else is an image, get the target format from that\n\t\t// otherwise, let the non-image objects set the target\n\t\ttarget_format \n\t\t\t= get_member_list has_format get_format x, \n\t\t\t\thas_member_list has_format x\n\t\t\t= NULL;\n\n\t\tto_image x = to_image_size width height target_bands target_format x;\n\n\t\t[then', else'] = map to_image x;\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if value then then' else else');\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nInterpolate_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\tLBB = 3;\n\tNOHALO = 4;\n\tVSQBS = 5;\n\n\t// Should introspect to get the list of interpolators :-(\n        // We can \"dir\" on VipsInterpolate to get a list of them, but we\n        // can't get i18n'd descriptions until we have more\n        // introspection stuff in nip2.\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Bilinear\", \n\t\t_ \"Bicubic\",\n\t\t_ \"Upsize: reduced halo bicubic (LBB)\",\n\t\t_ \"Upsharp: reduced halo bicubic with edge sharpening (Nohalo)\",\n\t\t_ \"Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)\"\n\t];\n\n\t/* And to vips type names.\n\t */\n\ttypes = [\n\t\t\"VipsInterpolateNearest\",\n\t\t\"VipsInterpolateBilinear\",\n\t\t\"VipsInterpolateBicubic\",\n\t\t\"VipsInterpolateLbb\",\n\t\t\"VipsInterpolateNohalo\",\n\t\t\"VipsInterpolateVsqbs\"\n\t];\n}\n\nInterpolate type options = class {\n\tvalue = vips_object_new Interpolate_type.types?type [] options;\n}\n\nInterpolate_bilinear = Interpolate Interpolate_type.BILINEAR [];\n\nInterpolate_picker default = class \n\tInterpolate interp.value [] {\n\t_vislevel = 2;\n\n\tinterp = Option \"Interpolation\" Interpolate_type.descriptions default;\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t_ \"Perceptual\" => PERCEPTUAL,\n\t\t_ \"Relative\" => RELATIVE,\n\t\t_ \"Saturation\" => SATURATION,\n\t\t_ \"Absolute\" => ABSOLUTE\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t_ \"Point\" => POINT,\n\t\t_ \"Line\" => LINE,\n\t\t_ \"Spline\" => SPLINE,\n\t\t_ \"Bar\" => BAR\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t_ \"YYYY\" => YYYY,\n\t\t_ \"XYYY\" => XYXY,\n\t\t_ \"XYXY\" => XYXY\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n\tto_image dpi = extract_bands 0 3 \n\t\t(graph_export_image (to_real dpi) this);\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [$format => Plot_format.XYYY] value {\n}\n\n/* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate\n * empty slots, for example.\n */\nNULL = class \n\t_Object {\n\too_binary_table op x = [\n\t\t// the only operation we allow is equality .. use pointer equality,\n\t\t// this lets us test a == NULL and a != NULL\n\t\t[this === x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"equal\"],\n\t\t[this !== x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"not_equal\"]\n\t] ++ super.oo_binary_table op x;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.8/Capture.def",
    "content": "/* make a new capture image\n */\nCapture_video = class\n\tImage value {\n\t// shortcut to prefs\n\t_prefs = Workspaces.Preferences;\n\n\tdevice = _prefs.VIDEO_DEVICE;\n\tchannel = Option \"Input channel\" [\n\t\t\"TV\",\n\t\t\"Composite 1\",\n\t\t\"Composite 2\",\n\t\t\"Composite 3\"\n\t] _prefs.VIDEO_CHANNEL;\n\tbrightness = Slider 0 32767 _prefs.VIDEO_BRIGHTNESS;\n\tcolour = Slider 0 32767 _prefs.VIDEO_COLOUR;\n\tcontrast = Slider 0 32767 _prefs.VIDEO_CONTRAST;\n\thue = Slider 0 32767 _prefs.VIDEO_HUE;\n\tframes_hint = \"Average this many frames:\";\n\tframes = Slider 0 100 _prefs.VIDEO_FRAMES;\n\tmono = Toggle \"Monochrome grab\" _prefs.VIDEO_MONO;\n\tcrop = Toggle \"Crop image\" _prefs.VIDEO_CROP;\n\n\t// grab, but hide it ... if we let the crop edit\n\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\tbrightness.value colour.value contrast.value hue.value\n\t\tframes.value);\n\n\tedit_crop\n\t\t= Region _raw_grab left top width height\n\t{\n\t\tleft = _prefs.VIDEO_CROP_LEFT;\n\t\ttop = _prefs.VIDEO_CROP_TOP;\n\t\twidth = min_pair\n\t\t\t_prefs.VIDEO_CROP_WIDTH\n\t\t\t(_raw_grab.width + left);\n\t\theight = min_pair\n\t\t\t_prefs.VIDEO_CROP_HEIGHT\n\t\t\t(_raw_grab.height + top);\n\t}\n\n\taspect_hint = \"Stretch vertically by this factor:\";\n\taspect_ratio = _prefs.VIDEO_ASPECT;\n\n\tvalue \n\t\t= frame'\n\t{\n\t\tframe \n\t\t\t= edit_crop.value, crop\n\t\t\t= _raw_grab.value;\n\n\t\tframe' \n\t\t\t= colour_transform Image_type.sRGB Image_type.B_W frame,\n\t\t\t\tmono\n\t\t\t= frame;\n\t}\n}\n\n#separator\n\n/* use white image w to correct image i \n */\nLight_correct w i\n\t= map_binary wc w i\n{\n\twc w i\n\t\t= clip2fmt i.format (w' * i)\n\t{\n\t\tfac = mean w / max w;\n\t\tw' = fac * (max w / w);\n\t}\n}\n\n/* equalize bands in region r\n */\nWhite_balance r\n\t= map_unary wb r\n{\n\twb region\n\t\t= clip2fmt region.format (region.image * Vector facs)\n\t{\n\t\ttarget = mean region; \n\t\tfacs = map (divide target) (map mean (bandsplit region));\n\t}\n}\n\n/* remove features larger than a certain size from image x\n */\nSmooth_image x\n      = map_unary smooth x\n{\n\tsmooth image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfeature = Slider 1 50 20;\n\n\t\tvalue = im_resize_linear \n\t\t\t(im_shrink image.value feature.value feature.value)\n\t\t\timage.width image.height;\n\t}\n}\n\n#separator\n\n/* calculate RGB -> LAB transform from an image of a Macbeth colour chart\n */\nCalibrate_chart image = class \n        Image value {\n\t_check_args = [\n\t\t[image, \"image\", check_Image]\n\t] ++ super._check_args;\n\t_vislevel = 3;\n\n\t// get macbeth data file to use\n        macbeth = Filename \"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t// get max of input image\n\t_max_value = Image_format.maxval image.format;\n\n\t// measure chart image\n\t_camera = im_measure image.value 0 0 image.width image.height 6 4;\n\n\t// load true values\n\t_true_Lab = Matrix_file macbeth.value;\n\t_true_XYZ = colour_transform \n\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t// get Ys of greyscale\n\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t// camera greyscale (all bands)\n\t_camera_grey = drop 18 _camera.value;\n\n\t// normalise both to 0-1 and combine\n\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t_comb = Matrix (map2 cons _true_grey_Y' _camera_grey');\n\n\t// make a linearising lut ... zero on left\n\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t// and display it\n\tlinearising_lut = Image _linear_lut;\n\n\t// map the original image through the lineariser to get linear 0-1\n\t// RGB image\n\t_image' = im_maplut image.value linearising_lut.value;\n\n\t// remeasure and solve for RGB -> XYZ\n\t_camera' = im_measure _image' 0 0 image.width image.height 6 4;\n\t_pinv = (transpose _camera' * _camera') ** -1;\n\tM = transpose (_pinv * transpose _camera' * _true_XYZ);\n\n\t// convert linear RGB camera to Lab \n\tvalue = colour_transform Image_type.XYZ Image_type.LAB \n\t\t((float) (recomb M _image'));\n\n\t// measure again and compute dE76\n\t_camera'' = im_measure value 0 0 image.width image.height 6 4;\n\n\t_dEs = map abs_vec (map Vector (_camera'' - _true_Lab).value);\n\tfinal_dE76 = mean (Vector _dEs);\n\t_max_dE = foldr max_pair 0 _dEs;\n\t_worst = index (equal _max_dE) _dEs;\n\tworst_patch = _macbeth_names ? _worst ++ \n\t\t\" (patch \" ++ print (_worst + 1) ++ \")\";\n}\n\n/* apply RGB -> LAB transform to an image\n */\nCalibrate_image calib image = class \n        Image value {\n\t_check_args = [\n\t\t[calib, \"calib\", check_instance \"Calibrate_chart\"],\n\t\t[image, \"image\", check_Image]\n\t] ++ super._check_args;\n\n\t// map the original image through the lineariser to get linear 0-1\n\t// RGB image\n\t_image' = im_maplut image.value calib.linearising_lut.value;\n\n\t// convert linear RGB camera to Lab \n\tvalue = colour_transform Image_type.XYZ Image_type.LAB \n\t\t((float) (recomb calib.M _image'));\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.8/Colour.def",
    "content": "/* Save a bit of typing.\n */\n_colour_conv from to x = map_unary (colour_transform from to) x;\n\n/* convert Mono to various formats\n */\nMono_to = class {\n\t/* convert mono colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.B_W Image_type.B_W x;\n\n\t/* convert mono colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.B_W Image_type.XYZ x;\n\n\t/* convert mono colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.B_W Image_type.YXY x;\n\n\t/* convert mono colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.B_W Image_type.LAB x;\n\n\t/* convert mono colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.B_W Image_type.LCH x;\n\n\t/* convert mono colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.B_W Image_type.UCS x;\n\n\t/* convert mono colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.B_W Image_type.RGB x;\n\n\t/* convert mono colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.B_W Image_type.sRGB x;\n\n\t/* convert mono colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.B_W Image_type.LABQ x;\n\n\t/* convert mono colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.B_W Image_type.LABS x;\n}\n\n/* convert XYZ to various formats\n */\nXYZ_to = class {\n\t/* convert XYZ colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.XYZ Image_type.B_W x;\n\n\t/* convert XYZ colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.XYZ Image_type.XYZ x;\n\n\t/* convert XYZ colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.XYZ Image_type.YXY x;\n\n\t/* convert XYZ colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.XYZ Image_type.LAB x;\n\n\t/* convert XYZ colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.XYZ Image_type.LCH x;\n\n\t/* convert XYZ colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.XYZ Image_type.UCS x;\n\n\t/* convert XYZ colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.XYZ Image_type.RGB x;\n\n\t/* convert XYZ colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.XYZ Image_type.sRGB x;\n\n\t/* convert XYZ colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.XYZ Image_type.LABQ x;\n\n\t/* convert XYZ colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.XYZ Image_type.LABS x;\n}\n\n/* convert Yxy to various formats\n */\nYxy_to = class {\n\t/* convert Yxy colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.YXY Image_type.B_W x;\n\n\t/* convert Yxy colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.YXY Image_type.XYZ x;\n\n\t/* convert Yxy colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.YXY Image_type.YXY x;\n\n\t/* convert Yxy colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.YXY Image_type.LAB x;\n\n\t/* convert Yxy colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.YXY Image_type.LCH x;\n\n\t/* convert Yxy colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.YXY Image_type.UCS x;\n\n\t/* convert Yxy colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.YXY Image_type.RGB x;\n\n\t/* convert Yxy colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.YXY Image_type.sRGB x;\n\n\t/* convert Yxy colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.YXY Image_type.LABQ x;\n\n\t/* convert Yxy colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.YXY Image_type.LABS x;\n}\n\n/* convert Lab to various formats\n */\nLab_to = class {\n\t/* convert Lab colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.LAB Image_type.B_W x;\n\n\t/* convert Lab colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.LAB Image_type.XYZ x;\n\n\t/* convert Lab colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.LAB Image_type.YXY x;\n\n\t/* convert Lab colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.LAB Image_type.LAB x;\n\n\t/* convert Lab colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.LAB Image_type.LCH x;\n\n\t/* convert Lab colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.LAB Image_type.UCS x;\n\n\t/* convert Lab colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.LAB Image_type.RGB x;\n\n\t/* convert Lab colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.LAB Image_type.sRGB x;\n\n\t/* convert Lab colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.LAB Image_type.LABQ x;\n\n\t/* convert Lab colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.LAB Image_type.LABS x;\n}\n\n/* convert LCh to various formats\n */\nLCh_to = class {\n\t/* convert LCh colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.LCH Image_type.B_W x;\n\n\t/* convert LCh colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.LCH Image_type.XYZ x;\n\n\t/* convert LCh colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.LCH Image_type.YXY x;\n\n\t/* convert LCh colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.LCH Image_type.LAB x;\n\n\t/* convert LCh colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.LCH Image_type.LCH x;\n\n\t/* convert LCh colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.LCH Image_type.UCS x;\n\n\t/* convert LCh colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.LCH Image_type.RGB x;\n\n\t/* convert LCh colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.LCH Image_type.sRGB x;\n\n\t/* convert LCh colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.LCH Image_type.LABQ x;\n\n\t/* convert LCh colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.LCH Image_type.LABS x;\n}\n\n/* convert UCS to various formats\n */\nUCS_to = class {\n\t/* convert UCS colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.UCS Image_type.B_W x;\n\n\t/* convert UCS colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.UCS Image_type.XYZ x;\n\n\t/* convert UCS colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.UCS Image_type.YXY x;\n\n\t/* convert UCS colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.UCS Image_type.LAB x;\n\n\t/* convert UCS colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.UCS Image_type.LCH x;\n\n\t/* convert UCS colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.UCS Image_type.UCS x;\n\n\t/* convert UCS colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.UCS Image_type.RGB x;\n\n\t/* convert UCS colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.UCS Image_type.sRGB x;\n\n\t/* convert UCS colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.UCS Image_type.LABQ x;\n\n\t/* convert UCS colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.UCS Image_type.LABS x;\n}\n\n/* convert RGB to various formats\n */\nRGB_to = class {\n\t/* convert RGB colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.RGB Image_type.B_W x;\n\n\t/* convert RGB colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.RGB Image_type.XYZ x;\n\n\t/* convert RGB colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.RGB Image_type.YXY x;\n\n\t/* convert RGB colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.RGB Image_type.LAB x;\n\n\t/* convert RGB colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.RGB Image_type.LCH x;\n\n\t/* convert RGB colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.RGB Image_type.UCS x;\n\n\t/* convert RGB colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.RGB Image_type.RGB x;\n\n\t/* convert RGB colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.RGB Image_type.sRGB x;\n\n\t/* convert RGB colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.RGB Image_type.LABQ x;\n\n\t/* convert RGB colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.RGB Image_type.LABS x;\n}\n\n/* convert sRGB to various formats\n */\nsRGB_to = class {\n\t/* convert sRGB colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.sRGB Image_type.B_W x;\n\n\t/* convert sRGB colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.sRGB Image_type.XYZ x;\n\n\t/* convert sRGB colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.sRGB Image_type.YXY x;\n\n\t/* convert sRGB colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.sRGB Image_type.LAB x;\n\n\t/* convert sRGB colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.sRGB Image_type.LCH x;\n\n\t/* convert sRGB colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.sRGB Image_type.UCS x;\n\n\t/* convert sRGB colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.sRGB Image_type.RGB x;\n\n\t/* convert sRGB colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.sRGB Image_type.sRGB x;\n\n\t/* convert sRGB colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.sRGB Image_type.LABQ x;\n\n\t/* convert sRGB colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.sRGB Image_type.LABS x;\n}\n\n/* convert LabQ to various formats\n */\nLabQ_to = class {\n\t/* convert LabQ colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.LABQ Image_type.B_W x;\n\n\t/* convert LabQ colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.LABQ Image_type.XYZ x;\n\n\t/* convert LabQ colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.LABQ Image_type.YXY x;\n\n\t/* convert LabQ colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.LABQ Image_type.LAB x;\n\n\t/* convert LabQ colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.LABQ Image_type.LCH x;\n\n\t/* convert LabQ colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.LABQ Image_type.UCS x;\n\n\t/* convert LabQ colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.LABQ Image_type.RGB x;\n\n\t/* convert LabQ colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.LABQ Image_type.sRGB x;\n\n\t/* convert LabQ colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.LABQ Image_type.LABQ x;\n\n\t/* convert LabQ colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.LABQ Image_type.LABS x;\n}\n\n/* convert LabS to various formats\n */\nLabS_to = class {\n\t/* convert LabS colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.LABS Image_type.B_W x;\n\n\t/* convert LabS colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.LABS Image_type.XYZ x;\n\n\t/* convert LabS colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.LABS Image_type.YXY x;\n\n\t/* convert LabS colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.LABS Image_type.LAB x;\n\n\t/* convert LabS colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.LABS Image_type.LCH x;\n\n\t/* convert LabS colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.LABS Image_type.UCS x;\n\n\t/* convert LabS colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.LABS Image_type.RGB x;\n\n\t/* convert LabS colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.LABS Image_type.sRGB x;\n\n\t/* convert LabS colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.LABS Image_type.LABQ x;\n\n\t/* convert LabS colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.LABS Image_type.LABS x;\n}\n\n#separator\n\n/* recombine image bands with an editable matrix\n */\nColour_recombination in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tmatrix = Matrix_rec (identity_matrix image.bands);\n\n\t\tvalue = recomb matrix image.value;\n\t}\n}\n\n/* colour temperature conversions\n */\nColour_temperature = class {\n\t/* convert XYZ from D65 to D50 ... use the Bradford approximation\n\t */\n\tD65XYZ_to_D50XYZ in = map_unary (colour_unary im_D652D50) in;\n\n\t/* convert XYZ from D50 to D65 ... use the Bradford approximation\n\t */\n\tD50XYZ_to_D65XYZ in = map_unary (colour_unary im_D502D65) in;\n}\n\n/* various colour difference metrics \n */\ndE_ = class {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\t_apply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_instanceof \"Image\" x || is_instanceof \"Colour\" x || \n\t\t\tis_image x\n\t\t= x;\n\n\t_diff cvt in1 in2 = abs_vec (_apply_cvt cvt in1 - _apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\t_lab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\t_ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\t/* calculate delta-E CIE76 for two objects\n\t */\n\tCIE76 in1 in2 = map_binary (_diff _lab_cvt) in1 in2;\n\n\t/* calculate delta-E00 (CIEDE2000) for two objects\n\t */\n\tCIE00 in1 in2 = map_binary \n\t\t(colour_binary \"im_dE00_fromLab\" im_dE00_fromLab) in1 in2;\n\n\t/* calculate delta-E CMC(1:1) for two objects\n\t */\n\tUCS in1 in2 = map_binary (_diff _ucs_cvt) in1 in2;\n}\n\n#separator\n\n/* apply a coloured tint to a monochrome image\n */\nTint_mono_image in \n\t= map_unary apply_tint in\n{\n\tapply_tint in = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\ttint = Colour \"Lab\" [50, 0, 0];\n\n\t\tvalue = image_set_type Image_type.LAB \n\t\t\t(fancytint inp l_tint a_tint b_tint)\n\t\t{\n\t\t\t// input image ... to L only\n\t\t\tinp_lab = colour_transform_to Image_type.LAB in.value;\n\t\t\tinp = inp_lab?0;\n\n\t\t\t// make sure tint is LAB (might be edited)\n\t\t\tlab_tint = colour_transform_to Image_type.LAB tint;\n\n\t\t\t// selected lab\n\t\t\tl_tint = lab_tint.value?0;\n\t\t\ta_tint = lab_tint.value?1;\n\t\t\tb_tint = lab_tint.value?2;\n\n\t\t\t// fancy tint function ... don't tint black and white\n\t\t\tfancytint im l a b\n\t\t\t\t= im ++ ima ++ imb\n\t\t\t{\n\t\t\t\tmod \n\t\t\t\t\t= (100 - im) / (100 - l), im > l\n\t\t\t\t\t= im / l;\n\n\t\t\t\tbackgr = image_new in.width in.height 1\n\t\t\t\t\tImage_format.FLOAT \n\t\t\t\t\tImage_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\n\t\t\t\tima = mod * (backgr + a);\n\t\t\t\timb = mod * (backgr + b);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/* displace neutral axis in LAB colourspace\n */\nAdjust_cast image\n\t= map_unary widget image\n{\n\twidget image = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tgreen_red = Slider (-20) 20 0;\n\t\tblue_yellow = Slider (-20) 20 0;\n\n\t\tvalue\n\t\t\t= (colour_transform_to (get_type image) image'').value\n\t\t{\n\t\t\timage' = colour_transform_to Image_type.LAB image;\n\t\t\timage'' = image' + \n\t\t\t\tVector [0, green_red.value, blue_yellow.value];\n\t\t}\n\t}\n}\n\n/* displace h, scale LC in LCh colourspace\n */\nAdjust_hue_saturation_brightness image\n\t= map_unary widget image\n{\n\twidget image = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\thue = Slider 0 360 0;\n\t\tsaturation = Slider 0.01 5 1;\n\t\tbrightness = Slider 0.01 5 1;\n\n\t\tvalue\n\t\t\t= (colour_transform_to (get_type image) image'').value\n\t\t{\n\t\t\timage' = colour_transform_to Image_type.LCH image;\n\t\t\timage'' = \n\t\t\t\timage' * Vector [bv, sv, 1] + Vector [0, 0, hv];\n\t\t\tbv = brightness.value;\n\t\t\tsv = saturation.value;\n\t\t\thv = hue.value;\n\t\t}\n\t}\n}\n\n/* find pixels with a similar colour\n */\nSimilar_colour image\n\t= map_unary match image\n{\n\tmatch image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\ttarget_patch = Region image \n\t\t\t(20 - image.xoffset) \n\t\t\t(20 - image.yoffset)\n\t\t\t10 10;\n\t\ttarget_colour = Colour_from_image target_patch;\n\t\tdE_threshold = Slider 0 100 10;\n\n\t\tvalue = (dE_.CIE76 image target_colour < dE_threshold).value;\n\t}\n}\n\n/* plot an ab scatter histogram\n */\nPlot_ab_scatter image\n\t= map_unary widget image\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tbins = 8;\n\n\t\tvalue \n\t\t\t= bg * (((90 / mx) * hist) ++ blk)\n\t\t{\n\t\t\tlab = colour_transform_to Image_type.LAB image.value;\n\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\thist = hist_find_nD bins ab;\n\t\t\tmx = max hist;\n\t\t\tbg = lab_slice bins 1;\n\t\t\tblk = 1 + im_black bins bins 2;\n\t\t}\n\t}\n}\n\n\n\n\n"
  },
  {
    "path": "share/nip2/compat/7.8/Filter.def",
    "content": "/* Some useful masks.\n */\n_filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n_filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n_filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n_filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n_filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n_filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\n/* 3x3 blur of image\n */\nBlur x = map_unary (conv _filter_blur) x;\n\n/* 3x3 sharpen of image\n */\nSharpen x = map_unary (conv _filter_sharp) x;\n\n/* 1-pixel displacement emboss\n */\nEmboss x = map_unary (conv _filter_emboss) x;\n\n/* 3x3 median filter of image\n */\nMedian x = map_unary (rank 3 3 5) x;\n\n/* 3x3 laplacian of image\n */\nLaplacian x = map_unary (conv _filter_laplacian) x;\n\n/* 3x3 Sobel edge detect of image\n */\nSobel x\n        = map_unary sobel x\n{ \n\tsobel im\n\t\t= abs (a - 128) + abs (b - 128)\n\t{\n\t\ta = conv _filter_sobel im;\n\t\tb = conv (rot270 _filter_sobel) im;\n\t}\n}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\nLinedet x\n        = map_unary lindet x\n{ \n\tlindet im\n\t\t= foldr1 max_pair images\n\t{\n\t\tmasks = take 4 (iterate rot45 _filter_lindet);\n\t\timages = map (converse conv im) masks;\n        }\n}\n\n#separator\n\n/* custom convolution of an image\n */\nCustom_convolution in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\tseparable \n\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t= false;\n\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\t\tborder = Toggle \"Output image matches input image in size\" true;\n\n\t\tvalue \n\t\t\t= im_embed image' 0 off off image.width image.height,\n\t\t\t\tborder\n\t\t\t= image'\n\t\t{\n\t\t\tconv_op \n\t\t\t\t= im_conv_raw, !separable && type == 0\n\t\t\t\t= im_convsep_raw, separable && type == 0\n\t\t\t\t= im_convf_raw, !separable && type == 1\n\t\t\t\t= im_convsepf_raw, separable && type == 1\n\t\t\t\t= error \"boink!\";\n\n\t\t\timage' = conv_op image.value matrix;\n\n\t\t\toff = (matrix.width + 1) / 2;\n\t\t}\n\t}\n}\n\n/* blur with a radius and shape\n */\nCustom_blur in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tradius = Slider 1 50 1;\n\t\tshape = Option \"Mask shape\" [\n\t\t\t\"Square\",\n\t\t\t\"Gaussian\"\n\t\t] 0;\n\n\t\tvalue \n\t\t\t= im_convsep in.value mask\n\t\t{\n\t\t\t/* Make a square mask.\n\t\t\t */\n\t\t\tmask_sq_line = map (const 1) \n\t\t\t\t[1 .. 2 * radius.value - 1];\n\t\t\tmask_sq_sum = foldr1 add mask_sq_line;\n\t\t\tmask_sq_sep = Matrix_con mask_sq_sum 0 [mask_sq_line];\n\n\t\t\t/* Make a gaussian mask. sigma is not really related\n\t\t\t * to radius very well, sort-of bodge it.\n\t\t\t */\n\t\t\tmask_g = im_gauss_imask (radius.value / 2) 0.2;\n\t\t\tmask_g_line = mask_g.value ? (mask_g.height / 2);\n\t\t\tmask_g_sum = foldr1 add mask_g_line;\n\t\t\tmask_g_sep = Matrix_con mask_g_sum 0 [mask_g_line];\n\n\t\t\tmask\n\t\t\t\t= mask_sq_sep, shape.value == 0\n\t\t\t\t= mask_g_sep;\n\t\t}\n\t}\n}\n\n/* cored sharpen of L only in LAB image\n */\nCustom_sharpen in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tsize = Option \"Mask size\" [\n\t\t\t\"3 x 3\",\n\t\t\t\"5 x 5\",\n\t\t\t\"7 x 7\",\n\t\t\t\"9 x 9\",\n\t\t\t\"11 x 11\"\n\t\t] 0;\n\n\t\tsmooth_threshold = Slider 0 5 1.5;\n\t\tbrighten_max = Slider 1 50 10;\n\t\tdarken_max = Slider 1 50 50;\n\t\tflat_sharp = Slider (-2) 5 1;\n\t\tjaggy_sharp = Slider (-2) 5 2;\n\n\t\tvalue = im_sharpen in.value \n\t\t\t[3, 5, 7, 9, 11]?size\n\t\t\tsmooth_threshold.value \n\t\t\tbrighten_max.value \n\t\t\tdarken_max.value\n\t\t\tflat_sharp.value\n\t\t\tjaggy_sharp.value;\n\t}\n}\n\n/* custom rank filter of an image\n */\nCustom_rank in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\twindow_size_hint = \"Length of side of window to pass \" ++ \n\t\t\t\"over image:\";\n\t\twindow_size = 3;\n\t\trank = (int) ((window_size * window_size + 1) / 2);\n\t\tborder = Toggle \"Output image matches input image in size\" true;\n\n\t\tvalue \n\t\t\t= im_embed image' 0 off off image.width image.height,\n\t\t\t\tborder\n\t\t\t= image'\n\t\t{\n\t\t\timage' = im_rank_raw image.value \n\t\t\t\twindow_size window_size rank;\n\n\t\t\toff = (window_size + 1) / 2;\n\t\t}\n\t}\n}\n\n/* statistical difference of an image\n */\nStatistical_difference in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\twindow_size_hint = \"Length of side of window to pass \" ++ \n\t\t\t\"over image:\";\n\t\twindow_size = 11;\n\t\ttarget_mean = 128;\n\t\ttarget_mean_weight = Slider 0 1 0.8;\n\t\ttarget_deviation = 50;\n\t\ttarget_deviation_weight = Slider 0 1 0.8;\n\t\tborder = Toggle \"Output image matches input image in size\" true;\n\n\t\tvalue \n\t\t\t= im_embed image' 0 off off image.width image.height,\n\t\t\t\tborder\n\t\t\t= image'\n\t\t{\n\t\t\timage' = im_stdif_raw image.value \n\t\t\t\ttarget_mean_weight.value target_mean\n\t\t\t\ttarget_deviation_weight.value target_deviation\n\t\t\t\twindow_size window_size;\n\n\t\t\toff = (window_size + 1) / 2;\n\t\t}\n\t}\n}\n\n#separator\n\n/* various ideal fourier filters\n */\nIdeal_filter = class {\n\t_preview_size = 64;\n\n\t_high_low image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"High or low\" [\"High pass\", \"Low pass\"] 0;\n\n\t\t_type = type.value;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\tfrequency_cutoff.value 0 0 0 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\tfrequency_cutoff.value 0 0 0 0;\n\t}\n\n\t_ring image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tring_width = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Ring pass\", \"Ring reject\"] 0;\n\n\t\t_type = type.value + 6;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\tfrequency_cutoff.value ring_width.value 0 0 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\tfrequency_cutoff.value ring_width.value 0 0 0;\n\t}\n\n\t_band image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\tradius = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Band pass\", \"Band reject\"] 0;\n\n\t\t_type = type.value + 12;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\tfrequency_cutoff_x.value\n\t\t\t\tfrequency_cutoff_y.value\n\t\t\t\tradius.value 0 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\tfrequency_cutoff_x.value frequency_cutoff_y.value\n\t\t\tradius.value 0 0;\n\t}\n\n\t/* high or low pass ideal filter\n\t */\n\tHigh_low x = map_unary _high_low x;\n\n\t/* ring pass or reject ideal filter\n\t */\n\tRing x = map_unary _ring x;\n\n\t/* band pass or reject ideal filter\n\t */\n\tBand x = map_unary _band x;\n}\n\n/* Gaussian fourier filters\n */\nGaussian_filter = class {\n\t_preview_size = 64;\n\n\t_high_low image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"High or low\" [\"High pass\", \"Low pass\"] 0;\n\n\t\t_type = type.value + 4;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\tfrequency_cutoff.value \n\t\t\t\tamplitude_cutoff.value 0 0 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\tfrequency_cutoff.value amplitude_cutoff.value 0 0 0;\n\t}\n\n\t_ring image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tring_width = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Ring pass\", \"Ring reject\"] 0;\n\n\t\t_type = type.value + 10;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\tfrequency_cutoff.value\n\t\t\t\tring_width.value amplitude_cutoff.value 0 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\tfrequency_cutoff.value\n\t\t\tring_width.value amplitude_cutoff.value 0 0;\n\t}\n\n\t_band image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\tradius = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Band pass\", \"Band reject\"] 0;\n\n\t\t_type = type.value + 16;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\tfrequency_cutoff_x.value\n\t\t\t\tfrequency_cutoff_y.value\n\t\t\t\tradius.value amplitude_cutoff.value 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\tfrequency_cutoff_x.value\n\t\t\tfrequency_cutoff_y.value\n\t\t\tradius.value amplitude_cutoff.value 0;\n\t}\n\n\t/* high or low pass Gaussian filter\n\t */\n\tHigh_low x = map_unary _high_low x;\n\n\t/* ring pass or reject Gaussian filter\n\t */\n\tRing x = map_unary _ring x;\n\n\t/* band pass or reject Gaussian filter\n\t */\n\tBand x = map_unary _band x;\n}\n\n/* various Butterworth fourier filters\n */\nButterworth_filter = class {\n\t_preview_size = 64;\n\n\t_high_low image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\torder = Slider 1 10 2;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"High or low\" [\"High pass\", \"Low pass\"] 0;\n\n\t\t_type = type.value + 2;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\torder.value frequency_cutoff.value\n\t\t\t\tamplitude_cutoff.value 0 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\torder.value frequency_cutoff.value\n\t\t\tamplitude_cutoff.value 0 0;\n\t}\n\n\t_ring image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\torder = Slider 1 10 2;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tring_width = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Ring pass\", \"Ring reject\"] 0;\n\n\t\t_type = type.value + 8;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\torder.value frequency_cutoff.value\n\t\t\t\tring_width.value amplitude_cutoff.value 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\torder.value frequency_cutoff.value\n\t\t\tring_width.value amplitude_cutoff.value 0;\n\t}\n\n\t_band image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\torder = Slider 1 10 2;\n\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\tradius = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Band pass\", \"Band reject\"] 0;\n\n\t\t_type = type.value + 14;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\torder.value frequency_cutoff_x.value\n\t\t\t\tfrequency_cutoff_y.value\n\t\t\t\tradius.value amplitude_cutoff.value;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\torder.value frequency_cutoff_x.value\n\t\t\tfrequency_cutoff_y.value\n\t\t\tradius.value amplitude_cutoff.value;\n\t}\n\n\t/* high or low pass Butterworth filter\n\t */\n\tHigh_low x = map_unary _high_low x;\n\n\t/* ring pass or reject Butterworth filter\n\t */\n\tRing x = map_unary _ring x;\n\n\t/* band pass or reject Butterworth filter\n\t */\n\tBand x = map_unary _band x;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.8/Format.def",
    "content": "/* various operations to convert numeric precision\n */\nConvert_format_to = class {\n\t/* convert to unsigned 8 bit [0, 255]\n\t */\n\tunsigned_8bit x = map_unary cast_unsigned_char x;\n\n\t/* convert to signed 8 bit [-128, 127]\n\t */\n\tsigned_8bit x = map_unary cast_signed_char x;\n\n\t/* convert to unsigned 16 bit [0, 65535]\n\t */\n\tunsigned_16bit x = map_unary cast_unsigned_short x;\n\n\t/* convert to signed 16 bit [-32768, 32767]\n\t */\n\tsigned_16bit x = map_unary cast_signed_short x;\n\n\t/* convert to unsigned 32 bit [0, 4294967295]\n\t */\n\tunsigned_32bit x = map_unary cast_unsigned_int x;\n\n\t/* convert to signed 32 bit [-2147483648, 2147483647]\n\t */\n\tsigned_32bit x = map_unary cast_signed_int x;\n\n\t/* convert to IEEE 32 bit floating point\n\t */\n\tfloat_32bit x = map_unary cast_float x;\n\n\t/* convert to IEEE 64 bit floating point\n\t */\n\tfloat_64bit x = map_unary cast_double x;\n\n\t/* convert to 64 bit complex (2 x IEEE 32 bit floating point)\n\t */\n\tcomplex_64bit x = map_unary cast_complex x;\n\n\t/* convert to 128 bit complex (2 x IEEE 64 bit floating point)\n\t */\n\tcomplex_128bit x = map_unary cast_double_complex x;\n}\n\n/* linear scale of pixel values to fit range 0-255\n */\nScale_to_byte x = map_unary scale x;\n\n#separator\n\n/* try to make a matrix out of an object\n */\nConvert_to_matrix in = map_unary to_matrix in;\n\n/* try to make an image out of an object\n */\nConvert_to_image in = map_unary to_image in;\n\n#separator\n\n/* measure average value of a set of patches\n */\nMatrix_from_colour_chart x\n\t= map_unary chart x\n{\n\tchart image = class \n\t\tMatrix value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\n\t\tpacross = 6;\n\t\tpdown = 4;\n\t\tvalue = (im_measure image.value 0 0 image.width image.height\n\t\t\tpacross pdown).value;\n\n\t\t/* Hmm, not very helpful, we throw edits away.\n\t\t */\n\t\tMatrix_vips_edit value scale offset filename display = \n\t\t\tchart image;\n\t}\n}\n\n/* make a synthetic colour chart image from a matrix\n */\nColour_chart_from_matrix matrix\n\t= map_unary build_chart matrix\n{\n\tbuild_chart matrix = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[matrix, \"matrix\", check_Matrix]\n\t\t] ++ super._check_args;\n\n\t\tpatches_across = 6;\n\t\tpatches_down = 4;\n\t\tpatch_width = 50;\n\t\tpatch_height = 50;\n\t\tborder_width = 0;\n\n\t\tvalue\n\t\t\t= imagearray_assemble overlap overlap patch_table \n\t\t{\n\t\t\toverlap = -border_width;\n\n\t\t\t// patch numbers for row starts\n\t\t\trowstart = map (multiply patches_across) \n\t\t\t\t[0 .. patches_down - 1];\n\n\t\t\t// assemble patches ... each one a pixel value\n\t\t\tpatches = map (take patches_across) \n\t\t\t\t(map (converse drop matrix.value) rowstart);\n\n\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\tpatch v = image_new patch_width patch_height (len v) \n\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t// make an image for each patch\n\t\t\tpatch_table = map (map patch) patches;\n\t\t}\n\t}\n}\n\n#separator\n\n/* make a colour from the average values in an image\n */\nColour_from_image image\n\t= map_unary test image\n{\n\ttest x\n\t\t= build_chart x, is_instanceof \"Image\" x\n\t\t= build_chart (Image pixel), is_instanceof \"Point\" x\n\t\t= error (\"Colour_from_image: arg not Image or Point: \" ++ \n\t\t\tprint x)\n\t{\n\t\tpixel = x.image.extract_area x.left x.top 1 1;\n\t}\n\n\tbuild_chart image = class \n\t\tColour colour_space value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\n\t\tcolour_space \n\t\t\t= table.lookup 1 0 type, table.present 1 type\n\t\t\t= error (\"Colour_from_image: unable to make Colour \" ++\n\t\t\t\t\"from \" ++ \n\t\t\t\tImage_type.type_names.lookup 1 0 type ++\n\t\t\t\t\" image\")\n\t\t{\n\t\t\ttable = Image_type.colour_spaces;\n\t\t\ttype = im_header_int \"Type\" image.value;\n\t\t}\n\n\t\tvalue = map mean (bandsplit image.value);\n\t}\n}\n\n/* make a constant image from a colour patch\n */\nImage_from_colour x\n\t= map_unary build x\n{\n\tbuild c = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[c, \"c\", check_Colour]\n\t\t] ++ super._check_args;\n\n\t\twidth = 64;\n\t\theight = 64;\n\n\t\tvalue = image_new width height 3 Image_format.FLOAT \n\t\t\tImage_coding.NOCODING (get_type c) c 0 0;\n\t}\n}\n\n#separator\n\n/* try to break object in into a list of components\n */\nDecompose in\n\t= map_unary dec in\n{\n\tdec x\n\t\t= bandsplit x, is_instanceof \"Image\" x\n\t\t= map Vector x.value, is_instanceof \"Matrix_base\" x\n\t\t= x.value, is_instanceof \"Vector\" x || is_instanceof \"Real\" x\n\t\t= error \"Decompose: not Image/Matrix/Vector/Real\";\n}\n\n/* try to put a list of objects together into a large single object\n */\nCompose x\n\t= Vector x, is_real_list x\n\t= Matrix x, is_matrix x\n\t= bandjoin x, is_listof (is_instanceof \"Image\") x\n\t= Vector (map get_value x), is_listof (is_instanceof \"Real\") x\n\t= Matrix (map get_value x), is_listof (is_instanceof \"Vector\") x\n\t= map_unary Compose x, is_list x\n\t= error \"Compose: not list of Image/Vector/Real/image/real\"\n{\n\tget_value x = x.value;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.8/Histogram.def",
    "content": "/* find histogram of x\n */\nHist_find x = map_unary hist_find x;\n\n/* find n-dimensional histogram from n-band image\n */\nHist_find_nD in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\t// default to something small-ish\n\t\tbins = 8;\n\n\t\tvalue = hist_find_nD bins image.value;\n\t}\n}\n\n/* map image x through histogram hist\n */\nHist_map hist x = map_binary hist_map hist x;\n\n/* find cumulative histogram of hist\n */\nHist_cumulative x = map_unary hist_cum x;\n\n/* find normalised histogram of hist\n */\nHist_normalise x = map_unary hist_norm x;\n\n/* find LUT which matches hist in to hist ref\n */\nHist_match in ref = map_binary hist_match in ref;\n\n#separator\n\n/* histogram equalisation\n */\nHist_equalise = class {\n\t/* histogram equalise x globally\n\t */\n\tGlobal x = map_unary hist_equalize x;\n\n\t/* local histogram equalisation using region r as window\n\t */\n\tLocal r = map_unary (hist_equalize_local r.width r.height) r.image;\n}\n\n/* slice a line of pixels along a guide line and display as a histogram\n */\nGuide_slice in\n\t= map_unary widget in\n{\n\twidget guide = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[guide, \"Guide\", check_Guide]\n\t\t] ++ super._check_args;\n\n\t\tvalue \n\t\t\t= image_set_type Image_type.HISTOGRAM slice\n\t\t{\n\t\t\tslice\n\t\t\t\t= guide.image.extract_area \n\t\t\t\t\tguide.image.rect.left guide.top \n\t\t\t\t\tguide.width 1,\n\t\t\t\t\tis_instanceof \"HGuide\" guide\n\t\t\t\t= guide.image.extract_area\n\t\t\t\t\tguide.left guide.image.rect.top\n\t\t\t\t\t1 guide.height;\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.8/Image.def",
    "content": "/* take a copy of x\n */\nDuplicate x = map_unary copy x;\n\n/* crop image x\n */\nCrop x \n\t= map_unary build_widget x\n{\n\tbuild_widget image = widget image \n\t\t(image.width * 0.25 - image.xoffset)\n\t\t(image.height * 0.25 - image.yoffset)\n\t\t(image.width * 0.5)\n\t\t(image.height * 0.5);\n\n\twidget image left top width height = class \n\t\tRegion image left top width height {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 4;\n\n\t\tRegion_edit image left top width height \n\t\t\t= widget image left top width height;\n\t}\n}\n\n/* insert image b into image a\n */\nInsert a b = class \n\tImage value {\n\t_check_args = [\n\t\t[a, \"a\", check_Image],\n\t\t[b, \"b\", check_Image]\n\t] ++ super._check_args;\n\t_check_all = [\n\t\t[a.format == b.format && a.coding == b.coding && \n\t\t\ta.bands == b.bands, \n\t\t\t\"a.format == b.format && a.coding == b.coding && \" ++\n\t\t\t\t\"a.bands == b.bands\"],\n\t\t[a.width >= b.width && a.height >= b.height,\n\t\t\t\"First image should be able to enclose second\"]\n\t];\n\t_vislevel = 3;\n\n\tplace = Area a ((a.width - b.width) / 2) ((a.height - b.height) / 2) \n\t\tb.width b.height;\n\n\tvalue\n\t\t= im_insert_noexpand a' b'' place.left place.top\n\t{\n\t\ta' = a.value;\n\t\tb' = b.value;\n\n\t\tb'' = clip2fmt a.format b';\n\t}\n}\n\n/* join two images left/right or up/down\n */\nJoin = class {\n\t_check_ab_args a b = [\n\t\t[a, \"a\", check_Image],\n\t\t[b, \"b\", check_Image]\n\t];\n\t_check_ab_all a b = [\n\t\t[a.format == b.format && a.coding == b.coding && \n\t\t\ta.bands == b.bands,\n\t\t\t\"a.format == b.format && a.coding == b.coding && \" ++\n\t\t\t\t\"a.bands == b.bands\"]\n\t];\n\n\t/* join two images left-right\n\t */\n\tLeft_right a b = class \n\t\tImage value {\n\t\t_check_args = _check_ab_args a b ++ super._check_args;\n\t\t_check_all = _check_ab_all a b ++ super._check_all;\n\n\t\tshim = Slider 0 100 0;\n\t\tbackground_colour = 0;\n\t\talign = Option \"Alignment\" [\"Top\", \"Centre\", \"Bottom\"] 1;\n\n\t\tvalue = im2\n\t\t{\n\t\t\tw = a.width + b.width + shim.value;\n\t\t\th = max_pair a.height b.height;\n\n\t\t\tbg = image_new w h a.bands\n\t\t\t\ta.format a.coding a.type\n\t\t\t\tbackground_colour\n\t\t\t\t0 0;\n\n\t\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\t\tmax_pair 0 (a.height - b.height)]; \n\n\t\t\tim1 = im_insert_noexpand bg a.value \n\t\t\t\t0 (ya?align);\n\t\t\tim2 = im_insert_noexpand im1 b.value \n\t\t\t\t(a.width + shim.value) (yb?align);\n\t\t}\n\t}\n\n\t/* join two images top-bottom\n\t */\n\tTop_bottom a b = class Image value {\n\t\t_check_args = _check_ab_args a b ++ super._check_args;\n\t\t_check_all = _check_ab_all a b ++ super._check_all;\n\n\t\tshim = Slider 0 100 0;\n\t\tbackground_colour = 0;\n\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 1;\n\n\t\tvalue = im2\n\t\t{\n\t\t\tw = max_pair a.width b.width;\n\t\t\th = a.height + b.height + shim.value;\n\n\t\t\tbg = image_new w h a.bands\n\t\t\t\ta.format a.coding a.type\n\t\t\t\tbackground_colour\n\t\t\t\t0 0;\n\n\t\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\t\tmax_pair 0 (a.width - b.width)]; \n\n\t\t\tim1 = im_insert_noexpand bg a.value \n\t\t\t\t(xa?align) 0;\n\t\t\tim2 = im_insert_noexpand im1 b.value \n\t\t\t\t(xb?align) (a.height + shim.value);\n\t\t}\n\t}\n\n\t/* join a 2-D array of images\n\t */\n\tArray x = class Image value {\n\t\thspacing = Slider (-100) (100) 0;\n\t\tvspacing = Slider (-100) (100) 0;\n\t\tvalue \n\t\t\t= imagearray_assemble \n\t\t\t\t(-hspacing.value) (-vspacing.value) x'\n\t\t{\n\t\t\tx' = map (map getval) x;\n\t\t\tgetval x \n\t\t\t\t= x.value, is_class x\n\t\t\t\t= x;\n\t\t}\n\t}\n}\n\n/* morph images to match (needs the rubbersheet plugin)\n */\nRubber = class {\n\t_rubber_interp = Option \"Interpolation\"\n\t\t(map (extract 0) Interpolate.names.value)\n\t\tInterpolate.bilinear;\n\t_rubber_order = Option \"order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t_rubber_edges = Toggle \"Wrap image edges\" false;\n\n\t/* find a transform which will turn sample image into reference image\n\t */\n\tRubber_find reference sample = class\n\t\tMatrix transformation {\n\t\t_vislevel = 3;\n\n\t\t// controls\n\t\torder = _rubber_order;\n\t\tinterp = _rubber_interp;\n\t\tedges = _rubber_edges;\n\t\tmax_error = 0.3;\n\t\tmax_iterations = 10;\n\n\t\t// transform\n\t\t_result = resample sample.value reference.value \n\t\t\tmax_error max_iterations order.value \n\t\t\tinterp.value edges.value;\n\n\t\t// results\n\t\ttransformed_image = Image (_result?0);\n\t\ttransformation = (_result?1).value;\n\t\tfinal_error = _result?2;\n\t}\n\n\t/* apply a transform to an image\n\t */\n\tRubber_apply transform image = class\n\t\tImage value {\n\t\t// controls\n\t\tinterp = _rubber_interp;\n\t\tedges = _rubber_edges;\n\n\t\tvalue = im_transform image.value transform \n\t\t\tinterp.value edges.value;\n\t}\n\n\t/* change a transformation's scale factor\n\t */\n\tRubber_scale transform = class \n\t\tMatrix scaled_transform {\n\t\tfactor_hint = \"scale transform by this factor\";\n\t\tfactor_x = 1;\n\t\tfactor_y = 1;\n\n\t\t// pairwise multiply\n\t\tscaled_transform \n\t\t\t= map2 (map2 multiply) transform.value facs\n\t\t{\n\t\t\tfacs = [[ factor_x, factor_y ],\n\t\t\t\t[ 1, 1 ],\n\t\t\t\t[ 1, 1 ],\n\t\t\t\t[ 1 / factor_x, 1 / factor_y ],\n\t\t\t\t[ 1 / factor_x, 1 / factor_y ],\n\t\t\t\t[ 1 / factor_x, 1 / factor_y ]];\n\t\t}\n\t}\n}\n\n#separator\n\n/* set pixels to 255 - x\n */\nPhotographic_negative x \n\t= map_unary invert x\n{\n\tinvert x\n\t\t= oo_unary_function neg_op x, is_class x\n\t\t= im_invert x, is_image x\n\t\t= 255 - x, is_number x \n\t\t= error (errors.badargs ++ \"invert\");\n\n\tneg_op = Operator \"photographic_negative\" \n\t\tinvert Operator_type.ARITHMETIC false;\n}\n\n/* falsecolour a mono image\n */\nFalsecolour x = map_unary falsecolour x;\n\n#separator\n\n/* adjust brightness and contrast of image x\n */\nAdjust_scale_offset x\n\t= map_unary widget x\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tscale = Slider 0.001 255 1;\n\t\toffset = Slider (-128) 128 0;\n\n\t\tvalue = clip2fmt image.format (image * scale + offset).value;\n\t}\n}\n\n/* adjust gamma of image x\n */\nAdjust_gamma x\n\t= map_unary widget x\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tgamma = Slider 0.001 4 1;\n\t\timage_maximum_hint = \"Change image_maximum if this is \" ++\n\t\t\t\"not an 8 bit image\";\n\t\timage_maximum = 255;\n\n\t\tvalue = clip2fmt image.format gammaed.value \n\t\t{\n\t\t\tgammaed = (image_maximum / image_maximum ** gamma) * \n\t\t\t\timage ** gamma;\n\t\t}\n\t}\n}\n\n/* change advisory header fields of image x\n */\nEdit_header x\n\t= map_unary widget x\n{\n\ttype_names = Image_type.type_names;\n\tnames = sort (map (extract 0) type_names.value);\n\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\txres = image.xres;\n\t\tyres = image.yres;\n\t\txoffset = image.xoffset;\n\t\tyoffset = image.yoffset;\n\n\t\ttype_option \n\t\t\t= Option \"Image type\" names pos\n\t\t{\n\t\t\tname = type_names.lookup 1 0 image.type;\n\t\t\tpos = index (equal name) names;\n\t\t}\n\n\t\tvalue = im_copy_set image.value \n\t\t\ttype xres yres xoffset yoffset\n\t\t{\n\t\t\ttype = type_names.lookup 0 1 names?type_option;\n\t\t}\n\t}\n}\n\n#separator\n\n/* rotate and scale one image to match another\n */\nMatch a b = class \n\tImage value {\n\t_check_args = [\n\t\t[a, \"a\", check_Image],\n\t\t[b, \"b\", check_Image]\n\t] ++ super._check_args;\n\t_vislevel = 3;\n\n\tap1 = Point_relative a 0.5 0.25;\n\tbp1 = Point_relative b 0.5 0.25;\n\tap2 = Point_relative a 0.5 0.75;\n\tbp2 = Point_relative b 0.5 0.75;\n\n\trefine = Toggle \"Refine selected tie-points\" false;\n\n\tvalue\n\t\t= b'''\n\t{\n\t\t_prefs = Workspaces.Preferences;\n\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\ta' = a.value;\n\t\tb' = b.value;\n\n\t\tb'' = clip2fmt a.format b';\n\n\t\tap1' = ap1.image_rect;\n\t\tap2' = ap2.image_rect;\n\t\tbp1' = bp1.image_rect;\n\t\tbp2' = bp2.image_rect;\n\n\t\tb''' \n\t\t\t= im_match_linear_search a' b''\n\t\t\t\tap1'.left ap1'.top bp1'.left bp1'.top\n\t\t\t\tap2'.left ap2'.top bp2'.left bp2'.top\n\t\t\t\tobject window,\n\t\t\t\t\trefine \n\t\t\t= im_match_linear a' b''\n\t\t\t\tap1'.left ap1'.top bp1'.left bp1'.top\n\t\t\t\tap2'.left ap2'.top bp2'.left bp2'.top;\n\t}\n}\n\n/* make a colour overlay of two mono images\n */\nOverlay a b = class \n\tImage value {\n\t_check_args = [\n\t\t[a, \"a\", check_Image],\n\t\t[b, \"b\", check_Image]\n\t] ++ super._check_args;\n\t_check_all = [\n\t\t[a.bands == 1 && b.bands == 1,\n\t\t\t\"a.bands == 1 && b.bands == 1\"]\n\t] ++ super._check_all;\n\t_vislevel = 3;\n\n\tap1 = Point_relative a 0.5 0.25;\n\tbp1 = Point_relative b 0.5 0.25;\n\tap2 = Point_relative a 0.5 0.75;\n\tbp2 = Point_relative b 0.5 0.75;\n\n\trefine = Toggle \"Refine selected tie-points\" false;\n\tlock = Toggle \"No resize\" false;\n\tcolour = Option \"Colour overlay as\" [\n\t\t\"Green over Red\",\n\t\t\"Blue over Red\",\n\t\t\"Red over Green\",\n\t\t\"Red over Blue\",\n\t\t\"Blue over Green\",\n\t\t\"Green over Blue\"\n\t] 0;\n\n\tvalue\n\t\t= [(a' ++ b''' ++ black), \n\t\t\t(a' ++ black ++ b'''), \n\t\t\t(b''' ++ a' ++ black), \n\t\t\t(b''' ++ black ++ a'), \n\t\t\t(black ++ a' ++ b'''), \n\t\t\t(black ++ b''' ++ a')]?colour\n\t{\n\t\t_prefs = Workspaces.Preferences;\n\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\ta' = a.value;\n\t\tb' = b.value;\n\n\t\tb'' = clip2fmt a.format b';\n\n\t\tap1' = ap1.image_rect;\n\t\tap2' = ap2.image_rect;\n\t\tbp1' = bp1.image_rect;\n\t\tbp2' = bp2.image_rect;\n\n\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t// distance along the vector joining p1 and p2\n\t\tnorm p1 p2\n\t\t\t= Rect left' top' 0 0, lock\n\t\t\t= p2\n\t\t{\n\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t// 100000 to give precision since we pass points as\n\t\t\t// ints to match\n\t\t\tn = 100000 * sign v;\n\t\t\tleft' = p1.left + re n;\n\t\t\ttop' = p1.top + im n;\n\t\t}\n\n\t\tap2'' = norm ap1' ap2';\n\t\tbp2'' = norm bp1' bp2';\n\n\t\tb''' \n\t\t\t= im_match_linear_search a' b''\n\t\t\t\tap1'.left ap1'.top bp1'.left bp1'.top\n\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\tobject window,\n\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\trefine && !lock\n\t\t\t= im_match_linear a' b''\n\t\t\t\tap1'.left ap1'.top bp1'.left bp1'.top\n\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\n\t\tblack = image_new a.width a.height \n\t\t\ta.bands a.format a.coding a.type \n\t\t\t0 0 0;\n\t}\n}\n\n/* browse through the bands of a multiband image with a slider\n */\nBrowse_multiband image = class\n        Image value {\n\t_vislevel = 3;\n\n        band = Slider 0 (image.bands - 1) 0;\n        display = Option \"Display as\" [\n            \"Grey\",\n            \"Green over Red\",\n            \"Blue over Red\",\n            \"Red over Green\",\n            \"Red over Blue\",\n            \"Blue over Green\",\n            \"Green over Blue\"\n\t] 0;\n\n        value \n\t\t= output\n\t{\n\n                down = (int) band.value;\n                up = (int) (band.value + 1);\n                remainder = band.value - down;\n\n                a = (image.value ? up) * remainder;\n                b = (image.value ? down) * (1 - remainder);\n\t\tc = image_new image.width image.height 1\n\t\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W\n\t\t\t0 0 0;\n\n                output = [  \n\t\t\ta + b, \n\t\t\ta ++ b ++ c, \n\t\t\ta ++ c ++ b, \n\t\t\tb ++ a ++ c,\n\t\t\tb ++ c ++ a, \n\t\t\tc ++ a ++ b, \n\t\t\tc ++ b ++ a\n\t\t] ? display;\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.8/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/7.8\n\nstart_DATA = \\\n\tMath.def \\\n\tImage.def \\\n\tMosaic.def \\\n\tColour.def \\\n\tResize.def \\\n\tCapture.def \\\n\tFormat.def \\\n\tFilter.def \\\n\tMorphology.def \\\n\tNew.def \\\n\tHistogram.def \\\n\tPrint.def \\\n\tRotate.def \\\n\tStatistics.def \\\n\tX_ray.def \\\n\t_convert.def \\\n\t_errors.def \\\n\t_generate.def \\\n\t_list.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\t_types.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/7.8/Math.def",
    "content": "/* basic arithmetic for objects\n */\nArithmetic = class {\n\t/* add a and b\n\t */\n\tAdd a b = map_binary add a b;\n\n\t/* subtract b from a \n\t */\n\tSubtract a b = map_binary subtract a b;\n\n\t/* multiply a by b\n\t */\n\tMultiply a b = map_binary multiply a b;\n\n\t/* divide a by b\n\t */\n\tDivide a b = map_binary divide a b;\n\n\t/* remainder after dividing a by b\n\t */\n\tRemainder a b = map_binary remainder a b;\n\n\tsep1 = Separator;\n\n\t/* absolute value of x\n\t */\n\tAbsolute_value x = map_unary abs x;\n\n\t/* like Absolute_value, but treat pixels as vectors\n\t */\n\tAbsolute_value_vector x = map_unary abs_vec x;\n\n\t/* calculate unit vector for band elements\n\t */\n\tSign x = map_unary sign x;\n\n\t/* multiply by -1\n\t */\n\tNegate x = map_unary unary_minus x;\n}\n\n/* trigonometry operations (all in degrees)\n */\nTrig = class {\n\t/* calculate sine x\n\t */\n\tSin x = map_unary sin x;\n\n\t/* calculate cosine x\n\t */\n\tCos x = map_unary cos x;\n\n\t/* calculate tangent x\n\t */\n\tTan x = map_unary tan x;\n\n\tsep1 = Separator;\n\n\t/* calculate arc sine x\n\t */\n\tAsin x = map_unary asin x;\n\n\t/* calculate arc cosine x\n\t */\n\tAcos x = map_unary acos x;\n\n\t/* calculate arc tangent x\n\t */\n\tAtan x = map_unary atan x;\n\n\tsep2 = Separator;\n\n\t/* convert degrees to radians\n\t */\n\tRad x = map_unary rad x;\n\n\t/* convert radians to degrees\n\t */\n\tDeg x = map_unary deg x;\n\n\tsep3 = Separator;\n\n\t/* is angle within t degrees of r, mod 360\n\t */\n\tAngle_range t r angle\n\t      =\tclock (max - angle) < 2*r\n\t{\n\t\tmax = clock (t + r);\n\n\t\tclock a \n\t\t      =\ta + 360, a < 0;\n\t\t      =\ta - 360, a >= 360;\n\t\t      = a;\n\t}\n}\n\n/* logarithms and anti-logs\n */\nLog = class {\n\t/* calculate e ** x\n\t */\n\tExponential x = map_unary (power e) x;\n\n\t/* log base e of x\n\t */\n\tLog_natural x = map_unary log x;\n\n\tsep1 = Separator;\n\n\t/* log base 10 of x\n\t */\n\tLog10 x = map_unary log10 x;\n\n\t/* calculate 10 ** x\n\t */\n\tExponential10 x = map_unary (power 10) x;\n\n\tsep2 = Separator;\n\n\t/* calculate x ** y\n\t */\n\tRaise_to_power x y = map_binary power x y;\n}\n\n/* operations on complex numbers and images\n */\nComplex = class {\n\t/* extract fields from complex\n\t */\n\tComplex_extract = class {\n\t\t/* extract real part of complex\n\t\t */\n\t\tReal in = map_unary re in;\n\n\t\t/* extract imaginary part of complex\n\t\t */\n\t\tImaginary in = map_unary im in;\n\t}\n\n\t/* join a and b to make a complex \n\t */\n\tComplex_build a b = map_binary comma a b;\n\n\tsep1 = Separator;\n\n\t/* convert real and imag to amplitude and phase\n\t */\n\tPolar a = map_unary polar a;\n\n\t/* convert (amplitude, phase) image to rectangular coordinates\n\t */\n\tRectangular x = map_unary rectangular x;\n\n\tsep2 = Separator;\n\n\t/* invert imaginary part\n\t */\n\tConjugate x = map_unary conj x;\n}\n\n/* bitwise boolean operations for integer objects\n */\nBoolean = class {\n\t/* bitwise and of a and b\n\t */\n\tAnd a b = map_binary bitwise_and a b;\n\n\t/* bitwise or of a and b\n\t */\n\tOr a b = map_binary bitwise_or a b;\n\n\t/* bitwise exclusive or of a and b\n\t */\n\tEor a b = map_binary eor a b;\n\n\t/* invert a\n\t */\n\tNot a = map_unary not a;\n\n\tsep1 = Separator;\n\n\t/* shift a right by b bits\n\t */\n\tRight_shift a b = map_binary right_shift a b;\n\n\t/* shift a left by b bits\n\t */\n\tLeft_shift a b = map_binary left_shift a b;\n\n\tsep2 = Separator;\n\n\t/* b where a is non-zero, c elsewhere\n\t */\n\tIf_then_else a b c = map_trinary if_then_else a b c;\n\n\t/* or the bands of an image together\n\t */\n\tBand_or im = foldr1 bitwise_or (bandsplit im);\n\n\t/* and the bands of an image together\n\t */\n\tBand_and im = foldr1 bitwise_and (bandsplit im);\n}\n\n/* all comparison operations\n */\nRelational = class {\n\t/* find points at which a is equal to b\n\t */\n\tEqual a b = map_binary equal a b;\n\n\t/* find points at which a is not equal to b\n\t */\n\tNot_equal a b = map_binary not_equal a b;\n\n\t/* find points at which a is greater than b\n\t */\n\tMore a b = map_binary more a b;\n\n\t/* find points at which a is less than b\n\t */\n\tLess a b = map_binary less a b;\n\n\t/* find points at which a is greater than or equal to b\n\t */\n\tMore_equal a b = map_binary more_equal a b;\n\n\t/* find points at which a is less than or equal to b\n\t */\n\tLess_equal a b = map_binary less_equal a b;\n}\n\n/* operations on lists\n */\nList = class {\n\t/* take first element of list\n\t */\n\tHead x = hd x;\n\n\t/* drop the first element of list \n\t */\n\tTail x = tl x;\n\n\t/* drop the last element of list\n\t */\n\tInit x = init x;\n\n\t/* take the last element of list\n\t */\n\tLast x = last x;\n\n\tsep1 = Separator;\n\n\t/* reverse order of elements in list \n\t */\n\tReverse x = reverse x;\n\n\t/* sort elements of list into ascending order\n\t */\n\tSort x = sort x;\n\n\t/* remove duplicates from list\n\t */\n\tMake_set x = mkset equal x;\n\n\t/* exchange rows and columns in a list of lists\n\t */\n\tTranspose_list x = transpose x;\n\n\t/* flatten a list of lists into a single list\n\t */\n\tConcat l = concat l;\n\n\tsep2 = Separator;\n\n\t/* find the length of list \n\t */\n\tLength x = len x;\n\n\t/* return element n from list (index from zero)\n\t */\n\tSubscript n x = n ? x;\n\n\t/* take the first n elements of list x\n\t */\n\tTake n x = take n x;\n\n\t/* drop the first n elements of list x\n\t */\n\tDrop n x = drop n x;\n\n\tsep3 = Separator;\n\n\t/* join two lists end to end\n\t */\n\tJoin a b = a ++ b;\n\n\t/* put element a on the front of list x\n\t */\n\tCons a x = a : x;\n\n\t/* join two lists, pairwise\n\t */\n\tZip a b = zip2 a b;\n}\n\n/* various rounding operations\n */\nRound = class {\n\t/* smallest integral value not less than x \n\t */\n\tCeil x = map_unary ceil x;\n\n\t/* largest integral value not greater than x \n\t */\n\tFloor x = map_unary floor x;\n\n\t/* round to nearest integer\n\t */\n\tRint x = map_unary rint x;\n}\n\n/* forward and reverse fourier transforms\n */\nFourier = class {\n\t/* find fourier transform of image\n\t */\n\tForward a = map_unary (rotquad @ fwfft) a;\n\n\t/* find inverse fourier transform of image\n\t */\n\tReverse a = map_unary (invfft @ rotquad) a;\n\n\t/* rotate quadrants \n\t */\n\tRotate_quadrants a = map_unary rotquad a;\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.8/Morphology.def",
    "content": "/* Some useful masks.\n */\n_morph_mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n_morph_mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n_morph_mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n_morph_thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n/* dilate x with 8-connected mask\n */\nDilate8 x = map_unary (dilate _morph_mask8) x;\n\n/* dilate x with 4-connected mask\n */\nDilate4 x = map_unary (dilate _morph_mask4) x;\n\n/* erode x with 8-connected mask\n */\nErode8 x = map_unary (erode _morph_mask8) x;\n\n/* erode x with 4-connected mask\n */\nErode4 x = map_unary (erode _morph_mask4) x;\n\n#separator\n\n/* open with 8-connected mask\n */\nOpen x = map_unary (dilate _morph_mask8 @ erode _morph_mask8) x;\n\n/* close with 8-connected mask\n */\nClose x = map_unary (erode _morph_mask8 @ dilate _morph_mask8) x;\n\n/* remove single points \n */\nClean x \n\t= map_unary clean x\n{\n\tclean x = x ^ erode _morph_mask1 x;\n}\n\n/* thin once\n */\nThin x \n\t= map_unary thinall x\n{\n\tmasks = take 8 (iterate rot45 _morph_thin);\n\tthin1 m x = x ^ erode m x;\n\tthinall x = foldr thin1 x masks;\n}\n\n#separator\n\n/* dilate object x with mask m\n */\nDilate m x = map_unary (dilate m) x;\n\n/* erode object x with mask m\n */\nErode m x = map_unary (erode m) x;\n\n/* dilate mask m with itself n times\n */\nDilate_multiple m n = (iterate (dilate m) m)?n;\n\n/* erode mask m with itself n times\n */\nErode_multiple m n = (iterate (erode m) m)?n;\n\n#separator\n\n/* morph with a mask you can edit\n */\nCustom_morphology in\n\t= map_unary morph in\n{\n\tmorph image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tmask = _morph_mask8;\n\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\thint_apply_n_times = \"Number of times to apply mask:\";\n\t\tapply_n_times = 1;\n\t\tborder = Toggle \"Output image matches input image in size\" true;\n\n\t\tvalue \n\t\t\t= im_embed image' 0 xoff yoff image.width image.height,\n\t\t\t\tborder\n\t\t\t= image'\n\t\t{\n\t\t\tfatmask = (iterate (dilate mask) mask) ? \n\t\t\t\t(apply_n_times - 1);\n\n\t\t\timage'\n\t\t\t\t= im_erode_raw image.value fatmask, \n\t\t\t\t\ttype.value == 0\n\t\t\t\t= im_dilate_raw image.value fatmask;\n\n\t\t\txoff = (fatmask.width + 1) / 2;\n\t\t\tyoff = (fatmask.height + 1) / 2;\n\t\t}\n\t}\n}\n\n/* search in from the edges of an image for the first non-zero pixel\n */\nFind_profile in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\tvalue = image_set_type Image_type.HISTOGRAM [\n\t\t\tim_profile image.value 0,\n\t\t\trot270 (im_profile image.value 1),\n\t\t\tim_profile (flipud image.value) 0,\n\t\t\trot270 (im_profile (fliplr image.value) 1)\n\t\t]?edge;\n\t}\n}\n\n/* count the average number of black-to-white transitions across an image\n */\nCount_lines in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tReal value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Count\" [\n\t\t\t\"Horizontal lines\", \n\t\t\t\"Vertical lines\"\n\t\t] 0;\n\n\t\tvalue = im_cntlines image.value edge.value;\n\t}\n}\n\n\n\n"
  },
  {
    "path": "share/nip2/compat/7.8/Mosaic.def",
    "content": "\n/* Check and group a point list by image.\n */\n_mosaic_sort_test l\n\t= error \"mosaic: not all points\",\n\t\t!is_listof (is_instanceof \"Point\") l\n\t= error \"mosaic: points not on two images\",\n\t\tlen images != 2 \n\t= error \"mosaic: images do not match in format and coding\",\n\t\t!all_equal (map get_format l) ||\n\t\t!all_equal (map get_coding l)\n\t= error \"mosaic: not same number of points on each image\",\n\t\t!foldr1 equal (map len l') \n\t= l'\n{\n\t// test for all elements of a list equal\n\tall_equal l = land (map (equal (hd l)) (tl l));\n\n\tget_format x = x.image.format;\n\tget_coding x = x.image.coding;\n\n\t// all the different images\n\tget_image x = x.image;\n\timages = mkset pointer_equal (map get_image l);\n\n\t// find all points defined on image\n\ttest_image image p = p.image === image;\n\tfind l image = filter (test_image image) l;\n\n\t// group point list by image\n\tl' = map (find l) images;\n}\n\n/* Sort a point group to get right before left, and within each group to get \n * above before below.\n */\n_mosaic_sort_lr l\n\t= l''\n{\n\t// sort to get upper point first\n\tabove a b = a.top < b.top;\n\tl' = map (sortc above) l;\n\n\t// sort to get right group before left group\n\tright a b = (a?0).left > (b?0).left;\n\tl'' = sortc right l';\n}\n\n/* Sort a point group to get top before bottom, and within each group to get \n * left before right.\n */\n_mosaic_sort_tb l\n\t= l''\n{\n\t// sort to get upper point first\n\tleft a b = a.left < b.left;\n\tl' = map (sortc left) l;\n\n\t// sort to get right group before left group\n\tbelow a b = (a?0).top > (b?0).top;\n\tl'' = sortc below l';\n}\n\n/* Put 'em together! Group by image, sort vertically (or horizontally) with\n * one of the above, transpose to get pairs matched up, and flatten again.\n */\n_mosaic_sort fn = concat @ transpose @ fn @ _mosaic_sort_test;\n\n/* translate and blend two images together left/right or up/down\n */\nMosaic_translate = class {\n\t_check_ab_args a b = [\n\t\t[a, \"a\", check_Point],\n\t\t[b, \"b\", check_Point]\n\t];\n\n\t// shortcut to prefs\n\t_prefs = Workspaces.Preferences;\n\t_search_area = _prefs.MOSAIC_WINDOW_SIZE;\n\t_object_size = _prefs.MOSAIC_OBJECT_SIZE;\n\t_blend_width = Slider 0 100 _prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t_refine = Toggle \"Refine selected tie-points\" _prefs.MOSAIC_REFINE;\n\n\t/* translate and blend two images left/right\n\t */\n\tLeft_right a b = class \n\t\tImage value {\n\t\t_check_args = _check_ab_args a b ++ super._check_args;\n\n\t\tblend_width = _blend_width;\n\t\trefine = _refine;\n\n\t\tvalue \n\t\t\t= im_lrmosaic a'.image.value b'.image.value\n\t\t\t\t0\n\t\t\t\tra'.left ra'.top\n\t\t\t\trb'.left rb'.top\n\t\t\t\t(_object_size / 2) (_search_area / 2)\n\t\t\t\t0\n\t\t\t\tblend_width.value,\n\t\t\t\t\trefine\n\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t(rb'.left - ra'.left)\n\t\t\t\t(rb'.top - ra'.top)\n\t\t\t\tblend_width.value\n\t\t{\n\t\t\tsorted = _mosaic_sort _mosaic_sort_lr [a, b];\n\t\t\ta' = sorted?0;\n\t\t\tb' = sorted?1;\n\t\t\tra' = a'.image_rect;\n\t\t\trb' = b'.image_rect;\n\t\t}\n\t}\n\n\t/* translate and blend two images top/bottom\n\t */\n\tTop_bottom a b = class \n\t\tImage value {\n\t\t_check_args = _check_ab_args a b ++ super._check_args;\n\n\t\tblend_width = _blend_width;\n\t\trefine = _refine;\n\n\t\tvalue \n\t\t\t= im_tbmosaic a'.image.value b'.image.value\n\t\t\t\t0\n\t\t\t\tra'.left ra'.top\n\t\t\t\trb'.left rb'.top\n\t\t\t\t(_object_size / 2) (_search_area / 2)\n\t\t\t\t0\n\t\t\t\tblend_width.value,\n\t\t\t\t\trefine\n\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t(rb'.left - ra'.left)\n\t\t\t\t(rb'.top - ra'.top)\n\t\t\t\tblend_width.value\n\t\t{\n\t\t\tsorted = _mosaic_sort _mosaic_sort_tb [a, b];\n\t\t\ta' = sorted?0;\n\t\t\tb' = sorted?1;\n\t\t\tra' = a'.image_rect;\n\t\t\trb' = b'.image_rect;\n\t\t}\n\t}\n}\n\n/* forcibly translate and blend two images together left/right or up/down\n */\nMosaic_force = class {\n\t_check_ab_args a b = [\n\t\t[a, \"a\", check_Point],\n\t\t[b, \"b\", check_Point]\n\t];\n\n\t// shortcut to prefs\n\t_prefs = Workspaces.Preferences;\n\t_blend_width = Slider 0 100 _prefs.MOSAIC_MAX_BLEND_WIDTH;\n\n\t/* forcibly translate and blend two images left/right\n\t */\n\tLeft_right a b = class \n\t\tImage value {\n\t\t_check_args = _check_ab_args a b ++ super._check_args;\n\n\t\tblend_width = _blend_width;\n\n\t\tvalue \n\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t(rb'.left - ra'.left)\n\t\t\t\t(rb'.top - ra'.top)\n\t\t\t\tblend_width.value\n\t\t{\n\t\t\tsorted = _mosaic_sort _mosaic_sort_lr [a, b];\n\t\t\ta' = sorted?0;\n\t\t\tb' = sorted?1;\n\t\t\tra' = a'.image_rect;\n\t\t\trb' = b'.image_rect;\n\t\t}\n\t}\n\n\t/* forcibly translate and blend two images top/bottom\n\t */\n\tTop_bottom a b = class \n\t\tImage value {\n\t\t_check_args = _check_ab_args a b ++ super._check_args;\n\n\t\tblend_width = _blend_width;\n\n\t\tvalue \n\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t(rb'.left - ra'.left)\n\t\t\t\t(rb'.top - ra'.top)\n\t\t\t\tblend_width.value\n\t\t{\n\t\t\tsorted = _mosaic_sort _mosaic_sort_tb [a, b];\n\t\t\ta' = sorted?0;\n\t\t\tb' = sorted?1;\n\t\t\tra' = a'.image_rect;\n\t\t\trb' = b'.image_rect;\n\t\t}\n\t}\n}\n\n/* translate, rotate, scale and blend two images together left/right or up/down\n */\nMosaic_affine = class {\n\t_check_abcd_args a b c d = [\n\t\t[a, \"a\", check_Point],\n\t\t[b, \"b\", check_Point],\n\t\t[c, \"c\", check_Point],\n\t\t[d, \"d\", check_Point]\n\t];\n\n\t// shortcut to prefs\n\t_prefs = Workspaces.Preferences;\n\t_search_area = _prefs.MOSAIC_WINDOW_SIZE;\n\t_object_size = _prefs.MOSAIC_OBJECT_SIZE;\n\t_blend_width = Slider 0 100 _prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t_refine = Toggle \"Refine selected tie-points\" _prefs.MOSAIC_REFINE;\n\n\t/* translate, rotate, scale and blend two images left/right\n\t */\n\tLeft_right a b c d = class \n\t\tImage value {\n\t\t_check_args = _check_abcd_args a b c d ++ super._check_args;\n\n\t\tblend_width = _blend_width;\n\t\trefine = _refine;\n\n\t\tvalue \n\t\t\t= im_lrmosaic1 a'.image.value b'.image.value\n\t\t\t\t0\n\t\t\t\tra'.left ra'.top\n\t\t\t\trb'.left rb'.top\n\t\t\t\trc'.left rc'.top\n\t\t\t\trd'.left rd'.top\n\t\t\t\t(_object_size / 2) (_search_area / 2)\n\t\t\t\t0\n\t\t\t\tblend_width.value,\n\t\t\t\t\trefine\n\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\tra'.left ra'.top\n\t\t\t\trb'.left rb'.top\n\t\t\t\trc'.left rc'.top\n\t\t\t\trd'.left rd'.top\n\t\t\t\tblend_width.value\n\t\t{\n\t\t\tsorted = _mosaic_sort _mosaic_sort_lr [a, b, c, d];\n\t\t\ta' = sorted?0;\n\t\t\tb' = sorted?1;\n\t\t\tc' = sorted?2;\n\t\t\td' = sorted?3;\n\t\t\tra' = a'.image_rect;\n\t\t\trb' = b'.image_rect;\n\t\t\trc' = c'.image_rect;\n\t\t\trd' = d'.image_rect;\n\t\t}\n\t}\n\n\t/* translate, rotate, scale and blend two images top/bottom\n\t */\n\tTop_bottom a b c d = class \n\t\tImage value {\n\t\t_check_args = _check_abcd_args a b c d ++ super._check_args;\n\n\t\tblend_width = _blend_width;\n\t\trefine = _refine;\n\n\t\tvalue \n\t\t\t= im_tbmosaic1 a'.image.value b'.image.value\n\t\t\t\t0\n\t\t\t\tra'.left ra'.top\n\t\t\t\trb'.left rb'.top\n\t\t\t\trc'.left rc'.top\n\t\t\t\trd'.left rd'.top\n\t\t\t\t(_object_size / 2) (_search_area / 2)\n\t\t\t\t0\n\t\t\t\tblend_width.value,\n\t\t\t\t\trefine\n\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\tra'.left ra'.top\n\t\t\t\trb'.left rb'.top\n\t\t\t\trc'.left rc'.top\n\t\t\t\trd'.left rd'.top\n\t\t\t\tblend_width.value\n\t\t{\n\t\t\tsorted = _mosaic_sort _mosaic_sort_tb [a, b, c, d];\n\t\t\ta' = sorted?0;\n\t\t\tb' = sorted?1;\n\t\t\tc' = sorted?2;\n\t\t\td' = sorted?3;\n\t\t\tra' = a'.image_rect;\n\t\t\trb' = b'.image_rect;\n\t\t\trc' = c'.image_rect;\n\t\t\trd' = d'.image_rect;\n\t\t}\n\t}\n}\n\n#separator\n\n/* disassemble mosaic, adjust brightnesses to match, and reassemble\n */\nMosaic_balance x\n\t= map_unary balance x\n{\n\tbalance x\n\t\t= oo_unary_function balance_op x, is_class x\n\t\t= im_global_balancef x \n\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\tis_image x\n\t\t= error (errors.badargs ++ \"balance\")\n\t{\n\t\tbalance_op = Operator \"balance\" balance \n\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t}\n}\n\n/* brighten along a left/right or up/down axis\n */\nTilt_brightness = class {\n\t/* brighten along a left/right axis\n\t */\n\tLeft_right x \n\t\t= map_unary tilt_lr x\n\t{\n\t\ttilt_lr image = class\n\t\t\tImage value {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t] ++ super._check_args;\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Slider (-1) 1 0;\n\n\t\t\tvalue\n\t\t\t\t= final\n\t\t\t{\n\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\tramp' = bandjoin \n\t\t\t\t\t(map (const ramp) [1..image.bands]);\n\t\t\t\tscale = (ramp' - 0.5) * tilt + 1;\n\t\t\t\tfinal = image.value * scale;\n\t\t\t}\n\t\t}\n\t}\n\n\t/* brighten along a top/bottom axis\n\t */\n\tTop_bottom x \n\t\t= map_unary tilt_tb x\n\t{\n\t\ttilt_tb image = class\n\t\t\tImage value {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t] ++ super._check_args;\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Slider (-1) 1 0;\n\n\t\t\tvalue\n\t\t\t\t= final\n\t\t\t{\n\t\t\t\tramp = rot90 \n\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\tramp' = bandjoin \n\t\t\t\t\t(map (const ramp) [1..image.bands]);\n\t\t\t\tscale = (ramp' - 0.5) * tilt + 1;\n\t\t\t\tfinal = image.value * scale;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\n/* disassemble mosaic, substitute different image files, and reassemble\n */\nMosaic_rebuild x \n\t= map_unary remosaic x\n{\n\tremosaic image = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\told_hint = \"For the name of each file making up the mosaic, \" ++\n\t\t\t\"exchange this string:\";\n\t\told = \"foo\";\n\t\tnew_hint = \"for this string:\";\n\t\tnew = \"bar\";\n\n\t\tvalue = im_remosaic image.value old new;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.8/New.def",
    "content": "\n/* make a new blank image\n */\nNew_image \n\t= widget\n{\n\ttype_names = Image_type.type_names;\n\tnames = sort (map (extract 0) type_names.value);\n\n\tdefault_type_name = type_names.lookup 1 0 Image_type.MULTIBAND;\n\tdefault_type_pos = index (equal default_type_name) names;\n\n\twidget = class \n\t\tImage value {\n\t\twidth = 64;\n\t\theight = 64;\n\t\tbands = 1;\n\n\t\tformat_option = Option \"Image format\" [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t] 0;\n\n\t\ttype_option = Option \"Image type\" names default_type_pos;\n\n\t\tvalue\n\t\t\t= image_new width height bands format\n\t\t\t\tImage_coding.NOCODING type 0 0 0\n\t\t{\n\t\t\tformat = format_option.value;\n\t\t\ttype = type_names.lookup 0 1 names?type_option;\n\t\t}\n\t}\n}\n\n/* pick a colour ... any colour space\n */\nNew_colour\n\t= widget \"Lab\" [50,0,0]\n{\n\twidget default_colour value = class\n\t\tColour colour_space value {\n\t\t_colourspaces = [\n\t\t\t\"XYZ\",         \n\t\t\t\"Yxy\",         \n\t\t\t\"Lab\",         \n\t\t\t\"LCh\",         \n\t\t\t\"UCS\",        \n\t\t\t\"RGB\",       \n\t\t\t\"sRGB\"      \n\t\t];\n\n\t\tcolour_space_option = Option \"Colour space\" _colourspaces\n\t\t\t(index (equal default_colour) _colourspaces);\n\n\t\tcolour_space = colour_space_option.labels?\n\t\t\tcolour_space_option.value;\n\n\t\tColour_edit colour_space value = widget colour_space value;\n\t}\n}\n\n/* make a slider\n */\nNew_slider = Slider 0 255 128;\n\n/* make a toggle widget\n */\nNew_toggle = Toggle \"untitled\" false;\n\n/* make an option widget\n */\nNew_option = Option \"untitled\" [\"option0\", \"option1\"] 0;\n\n/* make a string entry widget\n */\nNew_string = String \"Enter a string\" \"sample text\";\n\n/* make a number entry widget\n */\nNew_number = Number \"Enter a number\" 42;\n\n/* make a file chooser\n */\nNew_filename = Filename \"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n\n/* make a matrix\n */\nNew_matrix = class {\n\t/* make a plain matrix\n\t */\n\tPlain = Matrix (identity_matrix 3);\n\n\t/* make a convolution matrix\n\t */\n\tConvolution = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\n\t/* make a recombination matrix\n\t */\n\tRecombination = Matrix_rec (identity_matrix 3);\n\n\t/* make a morphology matrix\n\t */\n\tMorphology = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n}\n\n/* make a mark on an image\n */\nNew_mark = class {\n\t/* mark a region on an image\n\t */\n\tRegion image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\n\t/* mark a point on an image\n\t */\n\tPoint image = scope.Point_relative image 0.5 0.5;\n\n\t/* mark an arrow on an image\n\t */\n\tArrow image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\n\t/* mark a horizontal guide on an image\n\t */\n\tHGuide image = scope.HGuide_relative image 0.5;\n\n\t/* mark a vertical guide on an image\n\t */\n\tVGuide image = scope.VGuide_relative image 0.5;\n}\n\n#separator\n\n/* make a spatial response pattern image\n */\nNew_eye = class\n\tImage value {\n\twidth = 64;\n\theight = 64;\n\tfactor = Slider 0.001 1 0.2;\n\n\tvalue = im_eye width height factor.value;\n}\n\n/* make a zone plate image\n */\nNew_zone_plate = class\n\tImage value {\n\tsize = 64;\n\n\tvalue = im_zone size;\n}\n\n/* make a grey ramp image\n */\nNew_grey = class\n\tImage value {\n\twidth = 64;\n\theight = 64;\n\torientation = Option \"\" [\"Horizontal\", \"Vertical\"] 0;\n\n\tvalue = [im_grey width height, \n\t\tim_rot90 (im_grey height width)]?orientation;\n}\n\n/* make a two band image whose pixel values are their coordinates\n */\nNew_xy = class\n\tImage value {\n\twidth = 64;\n\theight = 64;\n\n\tvalue = make_xy width height; \n}\n\n/* make a new image of gaussian noise\n */\nNew_gauss_noise = class\n\tImage value {\n\tsize = 64;\n\tmean = Slider 0 255 128;\n\tdeviation = Slider 0 128 50;\n\n\tvalue = im_gaussnoise size size mean.value deviation.value;\n}\n\n/* make a 2d fractal image\n */\nNew_fractal = class\n\tImage value {\n\tsize = 64;\n\tdimension = Slider 2.001 2.999 2.001;\n\n\tvalue = im_fractsurf size dimension.value; \n}\n\n/* make a CRT calibration chart\n */\nNew_CRT_test_chart = class\n\tImage value {\n\tbrightness = Slider 0 255 200;\n\tpatch_size = 32;\n\n\tvalue \n\t\t= imagearray_assemble 0 0 [[green, red], [blue, white]]\n\t{\n\n\t\tblack = image_new patch_size patch_size 1\n\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\tImage_type.B_W 0 0 0;\n\t\tnotblack = black + brightness;\n\n\t\tgreen = black ++ notblack ++ black;\n\t\tred = notblack ++ black ++ black;\n\t\tblue = black ++ black ++ notblack;\n\t\twhite = notblack ++ notblack ++ notblack;\n\t}\n}\n\n/* make a frequency test chart\n */\nNew_frequency_test_chart = class\n\tImage value {\n\twidth = 64;\n\tstrip_height = 10;\n\twavelengths = [64, 32, 16, 8, 4, 2];\n\n\tvalue \n\t\t= join.value\n\t{\n\t\tfreq_slice wave \n\t\t\t= Image (sin ((im_fgrey width strip_height) * 360 * \n\t\t\t\twidth / wave) > 0);\n\t\tstrips = map freq_slice wavelengths;\n\t\tjoin = foldl1 Join.Top_bottom strips;\n\t}\n}\n\n/* make a checkerboard pattern\n */\nNew_checkerboard = class\n\tImage value {\n\twidth = 64;\n\theight = 64;\n\thorizontal_patch_size = 8;\n\tvertical_patch_size = 8;\n\thorizontal_patch_offset = 0;\n\tvertical_patch_offset = 0;\n\n\tvalue\n\t\t= xstripes ^ ystripes\n\t{\n\t\tpixels = make_xy width height;\n\t\txpixels = pixels?0 + horizontal_patch_offset;\n\t\typixels = pixels?1 + vertical_patch_offset;\n\n\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\txstripes = make_stripe xpixels horizontal_patch_size;\n\t\tystripes = make_stripe ypixels vertical_patch_size;\n\t}\n}\n\n/* make a grid pattern\n */\nNew_grid = class\n\tImage value {\n\twidth = 64;\n\theight = 64;\n\thorizontal_line_spacing = 8;\n\tvertical_line_spacing = 8;\n\tline_thickness = 1;\n\thorizontal_grid_offset = 0;\n\tvertical_grid_offset = 0;\n\n\tvalue\n\t\t= xstripes | ystripes\n\t{\n\t\tpixels = make_xy width height;\n\t\txpixels = pixels?0 + horizontal_grid_offset;\n\t\typixels = pixels?1 + vertical_grid_offset;\n\n\t\tmake_stripe pix swidth = pix % swidth < line_thickness;\n\n\t\txstripes = make_stripe xpixels horizontal_line_spacing;\n\t\tystripes = make_stripe ypixels vertical_line_spacing;\n\t}\n}\n\n#separator\n\n/* make a gaussian matrix\n */\nNew_gauss_matrix = class\n\tMatrix_vips _mask.value \n\t\t_mask.scale _mask.offset _mask.filename _mask.display {\n\tsigma = Slider 0.001 10 1;\n\tmin_amplitude = Slider 0 1 0.2;\n\tinteger = Toggle \"Integer\" false;\n\t_mask \n\t\t= fn sigma.value min_amplitude.value\n\t{\n\t\tfn\n\t\t\t= im_gauss_imask, integer\n\t\t\t= im_gauss_dmask;\n\t}\n}\n\n/* make a laplacian of a gaussian mask\n */\nNew_log_matrix = class\n\tMatrix_vips _mask.value \n\t\t_mask.scale _mask.offset _mask.filename _mask.display {\n\tsigma = Slider 0.001 10 1.5;\n\tmin_amplitude = Slider 0 1 0.1;\n\tinteger = Toggle \"Integer\" false;\n\t_mask \n\t\t= fn sigma.value min_amplitude.value\n\t{\n\t\tfn\n\t\t\t= im_log_imask, integer\n\t\t\t= im_log_dmask;\n\t}\n}\n\n#separator\n\n/* make the mask images for various ideal fourier filters\n */\nNew_ideal = class {\n\t/* make a mask image for an ideal highpass/lowpass fourier filter\n\t */\n\tHigh_low = class \n\t\tImage value {\n\t\tsize = 64;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"High or low\" [\"High pass\", \"Low pass\"] 0;\n\n\t\t_type = type.value;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\tfrequency_cutoff.value 0 0 0 0;\n\t\t}\n\t}\n\n\t/* make a mask image for an ideal ring pass/reject fourier filter\n\t */\n\tRing = class \n\t\tImage value {\n\t\tsize = 64;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tring_width = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Ring pass\", \"Ring reject\"] 0;\n\n\t\t_type = type.value + 6;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\tfrequency_cutoff.value ring_width.value 0 0 0;\n\t\t}\n\t}\n\n\t/* make a mask image for an ideal band pass/reject fourier filter\n\t */\n\tBand = class \n\t\tImage value {\n\t\tsize = 64;\n\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\tradius = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Band pass\", \"Band reject\"] 0;\n\n\t\t_type = type.value + 12;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\tfrequency_cutoff_x.value\n\t\t\t\tfrequency_cutoff_y.value\n\t\t\t\tradius.value 0 0;\n\t\t}\n\t}\n}\n\n/* various Gaussian fourier filters\n */\nNew_gaussian = class {\n\t/* make a mask image for a gaussian highpass/lowpass fourier filter\n\t */\n\tHigh_low = class \n\t\tImage value {\n\t\tsize = 64;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"High or low\" [\"High pass\", \"Low pass\"] 0;\n\n\t\t_type = type.value + 4;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\tfrequency_cutoff.value \n\t\t\t\tamplitude_cutoff.value 0 0 0;\n\t\t}\n\t}\n\n\t/* make a mask image for a gaussian ring pass/reject fourier filter\n\t */\n\tRing = class \n\t\tImage value {\n\t\tsize = 64;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tring_width = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Ring pass\", \"Ring reject\"] 0;\n\n\t\t_type = type.value + 10;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\tfrequency_cutoff.value\n\t\t\t\tring_width.value amplitude_cutoff.value 0 0;\n\t\t}\n\t}\n\n\t/* make a mask image for a gaussian band pass/reject fourier filter\n\t */\n\tBand = class \n\t\tImage value {\n\t\tsize = 64;\n\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\tradius = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Band pass\", \"Band reject\"] 0;\n\n\t\t_type = type.value + 16;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\tfrequency_cutoff_x.value\n\t\t\t\tfrequency_cutoff_y.value\n\t\t\t\tradius.value amplitude_cutoff.value 0;\n\t\t}\n\t}\n}\n\n/* various Butterworth fourier filters\n */\nNew_butterworth = class {\n\t/* make a mask image for a Butterworth highpass/lowpass fourier filter\n\t */\n\tHigh_low = class \n\t\tImage value {\n\t\tsize = 64;\n\t\torder = Slider 1 10 2;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"High or low\" [\"High pass\", \"Low pass\"] 0;\n\n\t\t_type = type.value + 2;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\torder.value frequency_cutoff.value\n\t\t\t\tamplitude_cutoff.value 0 0;\n\t\t}\n\t}\n\n\t/* make a mask image for a Butterworth ring pass/reject fourier filter\n\t */\n\tRing = class \n\t\tImage value {\n\t\tsize = 64;\n\t\torder = Slider 1 10 2;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tring_width = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Ring pass\", \"Ring reject\"] 0;\n\n\t\t_type = type.value + 8;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\torder.value frequency_cutoff.value\n\t\t\t\tring_width.value amplitude_cutoff.value 0;\n\t\t}\n\t}\n\n\t/* make a mask image for a Butterworth band pass/reject fourier filter\n\t */\n\tBand = class \n\t\tImage value {\n\t\tsize = 64;\n\t\torder = Slider 1 10 2;\n\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\tradius = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Band pass\", \"Band reject\"] 0;\n\n\t\t_type = type.value + 14;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\torder.value frequency_cutoff_x.value\n\t\t\t\tfrequency_cutoff_y.value\n\t\t\t\tradius.value amplitude_cutoff.value;\n\t\t}\n\t}\n}\n\n#separator\n\n/* make a slice through CIELAB space\n */\nNew_CIELAB_slice = class\n\tImage value {\n\tsize = 64;\n\tL = Slider 0 100 50;\n\tvalue = lab_slice size L.value;\n}\n\n/* pick a colour in LAB space\n */\nNew_LAB_colour\n\t= widget \"Lab\" [50, 0, 0]\n{\n\t// ab_slice size\n\tsize = 512;\n\n\t// range of values ... +/- 128 for ab\n\trange = 256;\n\n\t// map xy in slice image to ab and back\n\txy2ab x = x / (size / range);\n\tab2xy a = (a * (size / range));\n\n\twidget space default_value = class\n\t\tColour space value {\n\t\tL = default_value?0;\n\t\ta = default_value?1;\n\t\tb = default_value?2;\n\t\tlightness = Slider 0 100 L;\n\t\tab_slice = Image (lab_slice size lightness.value);\n\t\tpoint = Point ab_slice (ab2xy a) (ab2xy b);\n\t\tvalue = [lightness.value, xy2ab point.left, xy2ab point.top];\n\t\tColour_edit colour_space value = widget colour_space value;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.8/Print.def",
    "content": "/* cored sharpen of L only in LAB image ... tuned for typical printers\n */\nSharpen_for_print in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\"300 dpi\",\n\t\t\t\"150 dpi\",\n\t\t\t\"75 dpi\"\n\t\t] 0;\n\n\t\t// sharpen params for 300, 150 and 75 dpi\n\t\t// just change the size of the area we search\n\t\t_param_table = [\n\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t[3, 2.5, 40, 20, 0.5, 1.5]\n\t\t];\n\t\t_params = _param_table?target_dpi;\n\n\t\tvalue = im_sharpen \n\t\t\t(colour_transform_to Image_type.LABQ in.value)\n\t\t\t_params?0 _params?1 _params?2 _params?3 _params?4\n\t\t\t_params?5;\n\t}\n}\n\n/* adjust tone curve on L*\n */\nTone_for_print in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tblack = Slider 0 100 0;\n\t\twhite = Slider 0 100 100;\n\n\t\tshadow_point = Slider 0.1 0.3 0.2;\n\t\tmid_point = Slider 0.4 0.6 0.5;\n\t\thighlight_point = Slider 0.7 0.9 0.8;\n\n\t\tshadow_adjust = Slider (-15) 15 0;\n\t\tmid_adjust = Slider (-30) 30 0;\n\t\thighlight_adjust = Slider (-15) 15 0;\n\n\t\tpreview_curve = Image (im_tone_build \n\t\t\tblack.value white.value\n\t\t\tshadow_point.value mid_point.value highlight_point.value\n\t\t\tshadow_adjust.value mid_adjust.value\n\t\t\thighlight_adjust.value);\n\n\t\tvalue = im_tone_map \n\t\t\t(colour_transform_to Image_type.LABQ in.value) \n\t\t\tpreview_curve.value;\n\t}\n}\n\n/* morph image colours in LAB space ... useful for tweaking colour for print\n */\nMorph_for_print in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tL_scale = 1.15;\n\t\tL_offset = -4.2;\n\t\tab_scale = Slider 1 1.5 1.15;\n\t\ta_offset = Slider (-10) 10 0;\n\t\tb_offset = Slider (-10) 10 5;\n\t\tgrey_correction = Matrix_con 1 0 [\n\t\t\t[5, 5, -1 ],\n\t\t\t[10, 4, -1 ],\n\t\t\t[15, 2, -1 ],\n\t\t\t[20, 1, 1 ],\n\t\t\t[25, 1, 2 ],\n\t\t\t[30, 0, 1 ],\n\t\t\t[35, 0, 1 ],\n\t\t\t[40, 0, 1 ],\n\t\t\t[45, 0, 1 ],\n\t\t\t[50, 0, 1 ],\n\t\t\t[55, 0, 0 ],\n\t\t\t[99, 0, 0 ]\n\t\t];\n\n\t\tvalue = im_lab_morph in.value \n\t\t\t(Vector [0, a_offset.value, b_offset.value] +\n\t\t\t\tgrey_correction)\n\t\t\tL_offset L_scale ab_scale.value ab_scale.value;\n\t}\n}\n\n#separator\n\n_sample_print_profile = \n\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n_sample_monitor_profile = \n\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n_render_intents = Option \"Render intent\" [\n\t\"Perceptual\",\n\t\"Relative\",\n\t\"Saturation\",\n\t\"Absolute\"\n] 3;\n\n/* transform from PCS to device space\n */\nICC_export in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tprofile = Filename _sample_print_profile;\n\t\tintent = _render_intents;\n\t\tdepth = Option \"Output depth\" [\"8 bit\", \"16 bit\"] 0;\n\n\t\tvalue = im_icc_export_depth in.value [8, 16]?depth\n\t\t\t(expand profile.value) intent.value;\n\t}\n}\n\n/* transform from device space to PCS\n */\nICC_import in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_check_all = [\n\t\t\t[in.bands == 3 || in.bands == 4, \n\t\t\t\t\"in.bands == 3 || in.bands == 4\" ]\n\t\t] ++ super._check_all;\n\t\t_vislevel = 3;\n\n\t\tprofile \n\t\t\t= Filename _sample_monitor_profile, in.bands == 3\n\t\t\t= Filename _sample_print_profile;\n\t\tintent = _render_intents;\n\n\t\tvalue = im_icc_import in.value \n\t\t\t(expand profile.value) intent.value;\n\t}\n}\n\n/* transform between two device spaces\n */\nICC_transform in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tin_profile = Filename _sample_monitor_profile;\n\t\tout_profile = Filename _sample_print_profile;\n\t\tintent = _render_intents;\n\n\t\tvalue = im_icc_transform in.value \n\t\t\t(expand in_profile.value) \n\t\t\t(expand out_profile.value) intent.value;\n\t}\n}\n\n/* transform from absolute to relative colorimetry\n */\nICC_ac2rc in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tprofile = Filename _sample_print_profile;\n\n\t\tvalue = im_icc_ac2rc in.value (expand profile.value);\n\t}\n}\n\n#separator\n\n/* convert between XYZ and Lab for D50\n */\nD50XYZ_to_D50Lab in = map_unary (colour_unary im_D50XYZ2Lab) in;\n\n/* convert between XYZ and Lab for D50\n */\nD50Lab_to_D50XYZ in = map_unary (colour_unary im_D50Lab2XYZ) in;\n\n#separator\n\n/* add an editable drop shadow to an image \n */\nDrop_shadow x\n\t= map_unary shadow x\n{\n\tshadow image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tshadow_width = Slider 0 50 5;\n\t\tshadow_height = Slider 0 50 5;\n\t\tshadow_softness = Slider 0 20 5;\n\t\tuse_mask = Toggle \"Use mask to make shadow\" false;\n\t\tmask_image = foldr1 bitwise_and (bandsplit (image > 128));\n\t\tbackground_colour = 255;\n\t\tshadow_colour = 128;\n\n\t\tvalue \n\t\t\t = final\n\t\t{\n\t\t\tblur_size = shadow_softness.value * 2 + 1;\n\n\t\t\t// matrix we blur with to soften shadows\n\t\t\tmask_g = im_gauss_imask (blur_size / 3) 0.2;\n\t\t\tmask_g_line = mask_g.value ? (mask_g.height / 2);\n\t\t\tmask_g_sum = foldr1 add mask_g_line;\n\t\t\tblur_matrix = Matrix_con mask_g_sum 0 [mask_g_line];\n\t\t\tmask_size = mask_g.width;\n\n\t\t\t// size of final image we build\n\t\t\tfinal_width = image.width + 2 * mask_size + \n\t\t\t\tshadow_width.value;\n\t\t\tfinal_height = image.height + 2 * mask_size + \n\t\t\t\tshadow_height.value;\n\n\t\t\t// make a plain image \n\t\t\tmk_background colour = image_new \n\t\t\t\tfinal_width final_height\n\t\t\t\timage.bands image.format \n\t\t\t\tImage_coding.NOCODING image.type\n\t\t\t\tcolour\n\t\t\t\t0 0;\n\n\t\t\t// make a mask image ... place at (x,y) in the final\n\t\t\t// image\n\t\t\tmk_mask x y \n\t\t\t\t= im_insert black mask_image.value x y,\n\t\t\t\t\tuse_mask\n\t\t\t\t= im_insert black white x y\n\t\t\t{\n\t\t\t\tblack = image_new \n\t\t\t\t\tfinal_width final_height\n\t\t\t\t\t1 Image_format.UCHAR\n\t\t\t\t\tImage_coding.NOCODING Image_type.B_W\n\t\t\t\t\t0\n\t\t\t\t\t0 0;\n\t\t\t\twhite = image_new \n\t\t\t\t\timage.width image.height\n\t\t\t\t\t1 Image_format.UCHAR\n\t\t\t\t\tImage_coding.NOCODING Image_type.B_W\n\t\t\t\t\t255\n\t\t\t\t\t0 0;\n\t\t\t}\n\n\t\t\t// make the shadow mask image ... offset mask and\n\t\t\t// soften\n\t\t\tshadow_mask = mk_mask  \n\t\t\t\t(mask_size + shadow_width.value)\n\t\t\t\t(mask_size + shadow_height.value);\n\t\t\tshadow_mask' = im_convsep shadow_mask blur_matrix;\n\n\t\t\t// make underlay ... use shadow mask to blend between\n\t\t\t// background colour and shadow colour\n\t\t\tbackground = mk_background background_colour;\n\t\t\tshadow = mk_background shadow_colour;\n\t\t\tunderlay = im_blend shadow_mask' shadow background;\n\n\t\t\t// overlay ... place image at final position\n\t\t\toverlay = mk_background 0;\n\t\t\toverlay' = im_insert overlay image.value\n\t\t\t\tmask_size mask_size;\n\n\t\t\t// overlay mask\n\t\t\toverlay_mask = mk_mask mask_size mask_size;\n\n\t\t\tfinal = if overlay_mask then overlay' else underlay;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.8/Resize.def",
    "content": "_resize_interp = Option \"Interpolation\" \n\t(map (extract 0) Interpolate.names.value)\n\tInterpolate.bilinear;\n\n/* resize image x by any scale factor\n */\nResize_image x\n\t= map_unary widget x\n{\n\twidget image = class\n\t\tImage value {\n\t\t_vislevel = 3;\n\t\tfactor = 1;\n\t\tinterp = _resize_interp;\n\t\tvalue = resize factor factor interp.value image.value;\n\t}\n}\n\n/* resize image with separate x/y factors\n */\nResize_xy_image x\n\t= map_unary widget x\n{\n\twidget image = class\n\t\tImage value {\n\t\t_vislevel = 3;\n\t\txfactor = 1;\n\t\tyfactor = 1;\n\t\tinterp = _resize_interp;\n\t\tvalue = resize xfactor yfactor interp.value image.value;\n\t}\n}\n\n/* place image x in a larger piece of image\n */\nResize_canvas x\n\t= map_unary widget x\n{\n\twidget image = class\n\t\tImage value {\n\t\t_vislevel = 3;\n\t\tnew_image_width = image.width;\n\t\tnew_image_height = image.height;\n\t\tposition = Option \"Position\" [\n\t\t\t\"North-west\",\n\t\t\t\"North\",\n\t\t\t\"North-east\",\n\t\t\t\"West\",\n\t\t\t\"Centre\",\n\t\t\t\"East\",\n\t\t\t\"South-west\",\n\t\t\t\"South\",\n\t\t\t\"South-east\"\n\t\t] 4;\n\t\tfill = Option \"Fill background with\" [\n\t\t\t\"White\",\n\t\t\t\"Black\"\n\t\t] 0;\n\n\t\tvalue \n\t\t\t= im_insert_noexpand background image.value xp yp\n\t\t{\n\t\t\twidth = image.width;\n\t\t\theight = image.height;\n\t\t\tcoding = image.coding;\n\t\t\tbands \n\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t= image.bands;\n\t\t\tformat \n\t\t\t\t= Image_format.FLOAT, \n\t\t\t\t\tcoding == Image_coding.LABPACK\n\t\t\t\t= image.format;\n\t\t\ttype = image.type;\n\n\t\t\tbackground_colour \n\t\t\t\t= image_white image, fill == 0\n\t\t\t\t= Vector (map (const 0) [1 .. bands]);\n\n\t\t\t// placement vectors ... left, centre, right\n\t\t\txposv = [0, new_image_width / 2 - width / 2, \n\t\t\t\tnew_image_width - width];\n\t\t\typosv = [0, new_image_height / 2 - height / 2, \n\t\t\t\tnew_image_height - height];\n\n\t\t\txp = xposv?((int) (position % 3));\n\t\t\typ = yposv?((int) (position / 3));\n\n\t\t\tbackground = image_new new_image_width new_image_height\n\t\t\t\tbands format coding type background_colour 0 0;\n\t\t}\n\t}\n}\n\n#separator\n\n/* resize image x so that the shortest axis is a certain size\n */\nShrink_to = class {\n\t_shrink_width default_size image = class\n\t\tImage value {\n\t\tsize = default_size;\n\t\tinterp = _resize_interp;\n\t\tvalue \t\n\t\t\t= resize factor factor interp.value image.value\n\t\t{\n\t\t\txfac = size / image.width;\n\t\t\tyfac = size / image.height;\n\t\t\tfactor = max_pair xfac yfac;\n\t\t}\n\t}\n\n\t/* shrink minimum dimension to 400 pixels \n\t */\n\tQuicklook x = map_unary (_shrink_width 400) x;\n\n\t/* shrink minimum dimension to 64 pixels \n\t */\n\tIcon x = map_unary (_shrink_width 64) x;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.8/Rotate.def",
    "content": "/* rotate images and matricies by fixed angles\n */\nRotate_fixed = class {\n        /* rotate image clockwise in 90 degree increments\n         */\n        _rotate_widget default a\n                = map_unary widget a\n        {\n                widget image = class\n                        Image value {\n                        _check_args = [\n                                [image, \"image\", check_Image]\n                        ] ++ super._check_args;\n                        _vislevel = 3;\n\n                        angle = Option \"Rotate by\" [\n                                \"Don't rotate\", \n                                \"90 degrees clockwise\",\n                                \"180 degrees\",\n                                \"90 degrees anticlockwise\"\n                        ] default;\n\n                        value = [\n                                image.value, \n                                rot90 image.value,\n                                rot180 image.value,\n                                rot270 image.value\n                        ] ? angle;\n                }\n        }\n\n        /* clockwise rotate by 90 degrees\n         */\n        R90 x = _rotate_widget 1 x;\n\n        /* rotate by 180 degrees\n         */\n        R180 x = _rotate_widget 2 x;\n\n        /* clockwise rotate by 270 degrees\n         */\n        R270 x = _rotate_widget 3 x;\n\n        /* rotate by 45 degrees ... square, odd-length-sides, matrices only\n         */\n        R45 x = map_unary rot45 x;\n}\n\n/* rotate image anticlockwise by any angle\n */\nRotate_free a\n\t= map_unary widget a\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tangle = Slider 0 360 0;\n\n\t\tvalue = rotate angle image.value;\n\t}\n}\n\n#separator\n\n/* mirror left/right or up/down\n */\nFlip = class {\n\t/* mirror object up/down\n\t */\n\tUp_down x = map_unary flipud x;\n\n\t/* mirror object left/right\n\t */\n\tLeft_right x = map_unary fliplr x;\n}\n\n/* swap rows and columns\n */\nTranspose x = map_unary transpose x;\n\n#separator\n\n/* smallest rotate that gets arrow vertical or horizontal\n */\nStraighten_arrow x\n\t= map_unary straighten x\n{\n\tstraighten arrow\n\t\t= rotate angle'' arrow.image\n\t{\n\t\tx = arrow.width;\n\t\ty = arrow.height;\n\n\t\tangle = im (polar (x, y));\n\n\t\tangle'\n\t\t\t= angle - 360, angle > 315\n\t\t\t= angle - 180, angle > 135\n\t\t\t= angle;\n\n\t\tangle''\n\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t= 90 - angle';\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.8/Statistics.def",
    "content": "/* mean value of object\n */\nMean a = map_unary mean a;\n\n/* standard deviation of object\n */\nDeviation a = map_unary deviation a;\n\n/* calculate a large set of stats on an object\n */ \nStats a = map_unary stats a;\n\n#separator\n\n/* maximum of an object\n */\nMax a = map_unary max a;\n\n/* minimum of an object\n */\nMin a = map_unary min a;\n\n/* return complex number (max, min)\n */\nMaxmin a \n\t= map_unary maxmin a\n{\n\tmaxmin x = (Max x, Min x);\n}\n\n/* position of maximum in an image\n */ \nMaximum_position a = map_unary maxpos a;\n\n/* position of minimum in an image \n */ \nMinimum_position a = map_unary minpos a;\n\n#separator\n\n/* count the number of non-zeros in an image \n */\nCount_set a\n\t= map_unary cset a\n{\n\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n}\n\n/* count the number of zeros in an image \n */\nCount_clear a\n\t= map_unary cclear a\n{\n\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n}\n\n#separator\n\n/* plot a scatter graph of a list of [x,y] coordinates\n */\nPlot_scatter x \n\t//= map_unary widget x\n\t= widget x\n{\t\n\twidget data\n\t\t= class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[data, \"data\", check_xy_list]\n\t\t] ++ super._check_args;\n\n\t\twidth = 512;\n\t\theight = 512;\n\t\tplot_colour = Colour \"Lab\" [80, -80, 80];\n\t\txmin = foldr1 min_pair (map (extract 0) data);\n\t\txmax = foldr1 max_pair (map (extract 0) data);\n\t\tymin = foldr1 min_pair (map (extract 1) data);\n\t\tymax = foldr1 max_pair (map (extract 1) data);\n\t\taxies = Toggle \"Draw axies\" true;\n\t\tmark \n\t\t\t= Point this x y\n\t\t{\n\t\t\tp = _to_image data?0;\n\t\t\tx = p?0;\n\t\t\ty = p?1;\n\t\t}\n\t\tmark_position_hint = \"mark is at position:\";\n\t\tmark_position = _from_image [mark.left, mark.top];\n\n\t\t// geometry\n\t\t_xrange = xmax - xmin;\n\t\t_yrange = ymax - ymin;\n\t\t_xscale = width / _xrange;\n\t\t_yscale = height / _yrange;\n\n\t\t// map an [x,y] point into the image coordinates\n\t\t_to_image p = [(p?0 - xmin) * _xscale, \n\t\t\theight - (p?1 - ymin) * _yscale];\n\n\t\t// map an [x,y] point from image cods back to real cods\n\t\t_from_image p = [p?0 / _xscale + xmin, \n\t\t\t(height - p?1) / _yscale + ymin];\n\n\t\tvalue\n\t\t\t= foldr plot background' data\n\t\t{\n\t\t\tplot_image_new width height pixel\n\t\t\t\t= image_new width height 3\n\t\t\t\t\tImage_format.FLOAT \n\t\t\t\t\tImage_coding.NOCODING\n\t\t\t\t\t(Image_type.colour_spaces.lookup \n\t\t\t\t\t\t0 1 plot_colour.colour_space)\n\t\t\t\t\tpixel 0 0;\n\n\t\t\t// background\n\t\t\tbackground = plot_image_new width height 0;\n\n\t\t\t// mark we plot\n\t\t\tmark_width = max_pair 1 (width / 100);\n\t\t\tmark_height = max_pair 1 (height / 100);\n\t\t\tmark = plot_image_new mark_width mark_height \n\t\t\t\t\tplot_colour;\n\n\t\t\t// draw axies on background \n\t\t\tbackground' \n\t\t\t\t= drawxy, axies\n\t\t\t\t= background\n\t\t\t{\n\t\t\t\t// axies\n\t\t\t\txaxis = plot_image_new width 1 \n\t\t\t\t\t(Colour \"Lab\" [100, 0, 0]); \n\t\t\t\tyaxis = plot_image_new 1 height \n\t\t\t\t\t(Colour \"Lab\" [100, 0, 0]);\n\t\t\t\torigin = _to_image [0, 0];\n\n\t\t\t\tdrawx = im_insert_noexpand \n\t\t\t\t\tbackground xaxis 0 origin?1;\n\t\t\t\tdrawxy = im_insert_noexpand \n\t\t\t\t\tdrawx yaxis origin?0 0;\n\t\t\t}\n\n\t\t\t// plot a single point on an image\n\t\t\tplot p im \n\t\t\t\t= im_insert_noexpand im mark \n\t\t\t\t\t(x - mark_width / 2) \n\t\t\t\t\t(y - mark_height / 2)\n\t\t\t{\n\t\t\t\tp' = _to_image p;\n\t\t\t\tx = p'?0;\n\t\t\t\ty = p'?1;\n\t\t\t}\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.8/X_ray.def",
    "content": "/* replace dark or light section of im1 with section from im2\n */\nReplace_area im1 im2 = class \n\tImage value \n{\n\t_check_args = [\n\t\t[im1, \"im1\", check_Image],\n\t\t[im2, \"im2\", check_Image]\n\t] ++ super._check_args;\n\t\n\t_vislevel = 3;\n\n\t/* Region on first image placed in the top left hand corner,\n\t * positioned and size relative to the height and width of im1.\n\t */\n\tr1 = Region_relative im1 0.1 0.1 0.1 0.1;\n\n\t/* Point on second image placed in the top left hand corner,\n\t * positioned relative to the height and width of im2. Used to\n\t * define _r2, the region from which the section of image is cloned \n\t * from.\n\t */\n\n\tp2 = Point im2 \n\t\t\t(im2.width * 0.1 - im2.xoffset)\n\t\t\t(im2.height * 0.1 - im2.yoffset);\n\n\t_r2 = Region im2 \n\t\tp2.left\n\t\tp2.top\n\t\tr1.width\n\t\tr1.height;\n\n\t_mask = [r1 <= Options.scale_cutoff, r1 >= Options.scale_cutoff] ? Options.control;\n\tmask = _mask?0;\n\n\tOptions = option_1, format  < 4\n\t\t\t= option_2\n\t\t{\n\t\tformat = im1.format;\n\t\t\n\t\toption_1 = class\n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\t/* Option toggle used to define whether the user is replacing a\n\t \t\t * dark or a light area.\n\t \t\t */\n\t\t\tcontrol = Option \"Removing a\" [\n\t\t\t\t\t\t\t \"Dark Area\",\n\t\t\t\t\t\t\t \"Light Area\"\n\t\t\t\t\t\t\t ] 1;\n\t\t\t\t\n\t\t\t/* Used to select the area to be replaced.\n\t\t\t */\t\t\t \n\t\t\tscale_cutoff = Slider 0.01 mx (mx / 2)\n\t\t\t\t{\n\t\t\t\tmx = Image_format.maxval im1.format;\n\t\t\t\t}\n\t\t\t\n\t\t\t/* Option toggle how the levels in the replacment area are calculated.\n\t \t\t * Replacement with gaussian noise uses the scale&offset balancing.\n\t \t\t */\t\t\t\t\t\t\t \n\t\t\tprocess = Option \"Use\" [\n\t\t\t\t\t\t\t \"Scale&Offset Balancing\",\n\t\t\t\t\t\t\t \"Gaussian noise replacement\",\n\t\t\t\t\t\t\t \"Histogram Balancing\"\n\t\t\t\t\t\t\t ] 0;\n\t\t\t\t\t\t\t \n\t\t\t/* This allows the function to be paused. \n\t\t\t */\t\t\t\t \n\t\t\tpause = Toggle \"Pause function to allow easy adjustment of region r1.\" true;\n\t\t\t}\n\t\toption_2 = class\n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\t/* Option toggle used to define whether the user is replacing a\n\t \t\t * dark or a light area.\n\t \t\t */\n\t\t\tcontrol = Option \"Removing a\" [\n\t\t\t\t\t\t\t \"Dark Area\",\n\t\t\t\t\t\t\t \"Light Area\"\n\t\t\t\t\t\t\t ] 1;\n\t\t\t\t\n\t\t\t/* Used to select the area to be replaced.\n\t\t\t */\t\t\t \n\t\t\tscale_cutoff = Slider 0.01 mx (mx / 2)\n\t\t\t\t{\n\t\t\t\t/* the below function can not cope with floats \n\t\t\t\t * and don't need massive range for 32-bit ints so \n\t\t\t\t * will just define the max as for a 16 bit unsigned.\n\t\t\t\t */\t\t\n\t\t\t\t mx = Image_format.maxval 2; //im1.format;\n\t\t\t\t}\n\t\t\t\n\t\t\t/* Option toggle how the levels in the replacment area are calculated.\n\t \t\t * Replacement with gaussian noise uses the scale&offset balancing.\n\t \t\t */\t\t\t\t\t\t\t \n\t\t\tprocess = Option \"Use\" [\n\t\t\t\t\t\t\t \"Scale&Offset Balancing\",\n\t\t\t\t\t\t\t \"Gaussian noise replacement\"\n\t\t\t\t\t\t\t ] 0;\n\t\t\t\t\t\t\t \n\t\t\t/* This allows the function to be paused. \n\t\t\t */\t\t\t\t \n\t\t\tpause = Toggle \"Pause function to allow easy adjustment of region r1.\" true;\n\t\t\t}\n\t\t}\n\t\t\n\tvalue \n\t\t= im1.value, Options.pause \n\t\t= im_insert im1.value patch r1.left r1.top \n\t{\n\t\tpatch = _so_balance mask r1.value _r2.value false, Options.process == 0;\n\t\t\t  = _so_balance mask r1.value _r2.value true, Options.process == 1;\n\t\t\t  = _hist_balance_2 mask r1.value _r2.value;\n\t}\n};\n\n#separator\n\n/* Balance the effect of secondary structure on an X-ray image\n * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference \n * masks, where the masks are white on a black background.  Then simplifys \n * the original X-ray to reduce  interference from stretchers cradles etc.\n */\n\nBalance_areas im_in m_control m_list = class\n\tImage value \n\t{\n\t_vislevel = 3;\n\t\n\t_format = im_in.format;\n\t\n\tOptions = option_1, format  < 4\n\t\t\t= option_2\n\t\t{\n\t\tformat = im_in.format;\n\t\t\n\t\toption_1 = class\n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\tpause = Toggle \"Pause Process.\" true;\n\t\t\tblur = Slider 0 5 0;\n\t\t\t_blur = rint blur.value;\n\t\t\toption = Toggle \"Use Scale&Offset Balancing rather than Histogram.\" true;\n\t\t\t_option = option;\n\t\t\t}\n\n\t\toption_2 = class\n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\tpause = Toggle \"Pause Process.\" true;\n\t\t\tblur = Slider 0 5 0;\n\t\t\t_blur = rint blur.value;\n\t\t\t_option = true;\n\t\t\t}\n\t\t}\n\n\t_control_im = _section_select2 im_in m_control;\n\t_control_values = _so_values _control_im;\n\n\t/* blur mask over a set number of pixels then histogram match an area\n\t * of the original image defined by m_current to the _control_im\n\t * then blend the matched area back into im_in.\n\t */\n\tprocess m_current im_start \n\t\t= im_out\n\t\t{\n\t\talternative = false;\n\t\tbl_mask    = _mask_blur_2 m_current Options._blur;\n\t\tscaled_im  = _so_convert _control_values im_start m_current, Options._option == true\n\t\t\t\t\t\t= _hist_convert_2 _control_im im_start m_current;\n\t\tfmt_im      = clip2fmt im_start.format scaled_im;\n\t\tblended_im  = im_blend bl_mask scaled_im.value im_start.value;\n\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t}\n\n\tvalue = im_in.value, Options.pause == true\n\t\t  = (foldr process im_in m_list).value;\n};\n\n_so_balance mask im1 im2 gauss \n\t= result\n{\n\t/* Extract the undamaged areas.\n\t */\n\tim1' = if !mask then Image im1 else 0;\n\tim2' = if !mask then Image im2 else 0;\n\n\t/* Find the non_zero means of the undamaged areas.\n\t */\n\tm1 = _mean_fn im1';\n\tm2 = _mean_fn im2';\n\t\n\tim1_mn = im1' - m1;\t\n\tim2_mn = im2' - m2;\n\t\n\tscale = (max im1_mn)/(max im2_mn);\n\t\n\tim2_corrected_a = ((im2 - m2) * scale) + m1;\n\tim2_corrected_b = clip2fmt im1'.format im2_corrected_a;\n\t\n\t/* Option to convert replacement image to scaled gaussian noise\n\t */\t\n\tim2_corrected = im2_corrected_b, gauss == false\n\t\t\t\t   = _gauss_noise im2_corrected_b;\n\n\t/* Blur mask.\n\t */\n\tmask' = _mask_blur_2 mask 5;\n\t//mask' = _feather_mask_2 5 mask.value;\n\n\t/* Blend im2 into im1.\n\t */\n\tresult = im_blend mask' im2_corrected im1;\n};\n\n/* make a new image of gaussian noise\n */\n_gauss_noise im2 = value \n\t{\n\ti = Image (im2);\n\twidth = i.width;\n\theight = i.height;\n\tmean = Mean i;\n\tdeviation = Deviation i;\n\n\tnoise = im_gaussnoise width height mean deviation;\n\tvalue = clip2fmt i.format noise;\n};\n\n/* Dilate and blur a mask by a number of pixels.\n *\n *_feather_mask_2 pixels mask \n *\t= im_convsep (dilate dilate_matrix mask) blur_matrix\n *{\n *\tdilate_matrix = (iterate (dilate _morph_mask8) _morph_mask8) ? pixels;\n *\tblur_matrix = Matrix_con pixels 0 [(map (const 1) [1 .. pixels])];\n *};\n */\n\n/* Mask is 255 to indicate parts of im1 which are damaged: replace these bits\n * with the corresponding parts of im2.\n *\n * Match the histograms of the two images to hide grey-level differences, be\n * careful to only consider undamaged sections.\n *\n * Feather the edges of the blend to hide the join.\n *\n * mask is an Image class. im1, im2 and result are vips images.\n */\n_hist_balance_2 mask im1 im2 \n\t= result\n{\n\tformat = im_header_int \"BandFmt\" im1;\n\tbands = im_header_int \"Bands\" im1;\n\n\t/* checks for 8 or 16 bit signed and converts to unsigned\n\t */\n\tforce_unsigned i \n\t\t= clip2fmt Image_format.UCHAR (i + 128), \n\t\t\tformat == Image_format.CHAR\n\t\t= clip2fmt Image_format.USHORT (i + 32768), \n\t\t\tformat == Image_format.SHORT\n\t\t= i;\n\n\t/* undo any force_unsigned \n\t */\n\tformat_restore i \n\t\t= clip2fmt Image_format.CHAR (i - 128),\n\t\t\tformat == Image_format.CHAR\n\t\t= clip2fmt Image_format.SHORT (i - 32768),\n\t\t\tformat == Image_format.SHORT\n\t\t= i;\n\n\t/* Find histogram and then zap the zero column (0 == background). For\n\t * 16-bit images, the histogram can be smaller than 65535 .... expand\n\t * up to full size.\n\t */\n\tbuild_hist i\n\t\t= im_insert big_black h' 0 0\n\t{\n\t\tmax_value = Image_format.maxval i.format;\n\n\t\th = hist_find i.value;\n\n\t\tblack_1 = image_new 1 1 i.bands \n\t\t\tImage_format.UINT Image_coding.NOCODING i.type 0 0 0;\n\t\tbig_black = image_new max_value 1 i.bands \n\t\t\tImage_format.UINT Image_coding.NOCODING i.type 0 0 0;\n\n\t\th' = im_insert h black_1 0 0;\n\t}\n\n\t/* We can't get hists of signed images :-( go unsigned if we have to.\n\t */\n\tim1' = force_unsigned im1;\n\tim2' = force_unsigned im2;\n\n\t/* Extract the undamaged areas.\n\t */\n\treference = if !mask then Image im1' else 0;\n\tsecondary = if !mask then Image im2' else 0;\n\n\t/* Find the hists of the undamaged areas.\n\t */\n\th1 = build_hist reference;\n\th2 = build_hist secondary;\n\n\t/* Match greylevels of im2 to match im1.\n\t */\n\tim2'' = hist_map (hist_match h1 h2) im2';\n\n\t/* Feather mask.\n\t */\n\tmask' = _mask_blur_2 mask 5;\n\t//mask' = _feather_mask_2 5 mask.value;\n\n\t/* Blend im2 into im1.\n\t */\n\tim1'' = im_blend mask' im2'' im1';\n\n\t/* Undo any signed/unsigned nonsense.\n\t */\n\tresult = format_restore im1'';\n};\n\n// Blurs the edges of an 8 bit mask, over a given number of pixels.\n_mask_blur_2 mask pixel \n\t= value\n{\n\tpixels   = 1, pixel == 0\n\t\t     = pixel;\n\tblack = im_black (mask.width + (2*pixels)) (mask.height + (2*pixels)) 1;\n\tnew_mask = Image (im_insert black mask.value pixels pixels);\n\tblur_matrix = Matrix_con pixels 0 [(map (const 1) [1 .. pixels])];\n\tim_blur = im_convsep new_mask.value blur_matrix;\n\n\tleft = pixels;\n\ttop = pixels;\n\twidth = mask.width;\n\theight = mask.height;\n\n\tvalue = im_extract_area im_blur left top width height;\n};\n\n_so_values im = result\n{\n\tmean_of_im = _mean_fn im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\n\tresult = [mean_of_im, max_of_im];\n};\n\n_so_convert con_values im mask = result\n{\n\tim' = _section_select2 im mask;\n\tim_values = _so_values im';\n\t\n\tmean_of_con = con_values?0; \n\tmean_of_im  = im_values?0;\n\t\n\tmax_of_con = con_values?1; \n\tmax_of_im  = im_values?1;\n\t\n\tscale = (max_of_con)/(max_of_im);\n\t\n\tim_convert = ((im - mean_of_im) * scale) + mean_of_con;\n\tresult = clip2fmt im.format im_convert;\n};\n\n/* Convert the histogram of part of image im_a, depending on the mask im_m,\n * to match the histogram of im_c.\n */\n_hist_convert_2 control_im im adjust_mask\n\t= im_final\n{\n\tmax_value = Image_format.maxval im.format;\n\n\tadjust_im = _section_select2 im adjust_mask;\n\thist_c = hist_fn control_im;\n\thist_a = hist_fn adjust_im;\n\n\t/* Find histogram and then edit out any information related to parts \n\t * of the image with value 0.  Ensure that the histogram represents \n\t * the full scale for the appropriate format. Output corrected \n\t * histograms for the correct parts of the image.\n\t */\n\thist_fn im_in \n\t\t= output\n\t{\n\t\thist_1 = hist_find im_in;\n\t\tblack_1 = clip2fmt hist_1.format (im_black 1 1 1);\n\t\thist_2 = im_insert hist_1.value black_1 0 0;\n\t\tblack_2 = clip2fmt hist_1.format (im_black max_value 1 1);\n\t\toutput = im_insert black_2 hist_2 0 0;\n\t}\n\n\tim_final = hist_map (hist_match hist_a hist_c) im;\n};\n\n//-------------------------------------------------------------------------------\n\n/*Returns a section of im, defined by a mask, on a black background*/\n_section_select2 im_in mask = output\n\t{\n\toutput  \n\t\t= clip2fmt im_in.format (im_black im_in.width im_in.height 1), mask == 0\n\t        = im_in;\n        };\n\n_mean_fn im = no_out\n   {\n   zero_im = (im == 0);\n   zero_mean = mean zero_im;              \n   no_mean = mean im;\n   no_out = no_mean/(1 - (zero_mean/255));\n   } \n\n"
  },
  {
    "path": "share/nip2/compat/7.8/_convert.def",
    "content": "\n/* Convert an image ... just set the Type field.\n */\nimage_set_type type in = im_copy_set in type \n\t(im_header_double \"Xres\" in) (im_header_double \"Yres\" in)\n\t(im_header_int \"Xoffset\" in) (im_header_int \"Yoffset\" in);\n\n/* Convert an image ... just set origin\n */\nimage_set_origin xoff yoff in = im_copy_set in \n\t(im_header_int \"Type\" in) \n\t(im_header_double \"Xres\" in) (im_header_double \"Yres\" in)\n\txoff yoff;\n\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x, is_real x || is_image x \n\t= error (errors.badargs ++ \"to_matrix\")\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (errors.badargs ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i && bands == 1\n\t\t= (im_vips2mask ((double) i'')).value, \n\t\t\tis_image i && bands == 3 && width == 1\n\t\t= error errors.not1band3band\n        {\n\t\twidth = im_header_int \"Xsize\" i;\n\t\tbands = im_header_int \"Bands\" i;\n\n                split = bandsplit i;\n                i' = im_insert (split?0) (split?1) 1 0;\n                i'' = im_insert i' (split?2) 2 0;\n        }\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_instanceof \"Colour\" x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x, is_real x || is_image x \n\t= error (errors.badargs ++ \"to_image\")\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (errors.badargs ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n                        = b1 ++ b2 ++ b3\n                {\n                        b1 = extract_area 0 0 1 height i;\n                        b2 = extract_area 1 0 1 height i;\n                        b3 = extract_area 2 0 1 height i;\n                }\n\t}\n}\n\n/* Try to make a real.\n */\nto_real x\n\t= to_real x.value, is_class x\n\t= x, is_real x\n\t= abs x, is_complex x\n\t= error (errors.badargs ++ \"to_real\");\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n        /* Turn a char digit to a number.\n         */\n        parse_c ch\n                = error \"parse_c: not a digit\", ! is_digit ch\n                = (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n        = error \"parse_number: badly formed number\", len parts != 2\n        = sign * n\n{\n        parts = splitpl [ member \"+-\", is_digit ] l;\n\n        n = parse_pint parts?1;\n        sign\n                = 1, parts?0 == [] || parts?0 == \"+\"\n                = -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n        = err, len parts != 4\n        = (ipart + fpart) * 10 ** exp\n{\n\terr = error \"parse_float: badly formed number\";\n\n        parts = splitpl [\n                member \"+-0123456789\", member \".0123456789\",\n                member \"eE\", member \"+-0123456789\" ] l;\n\n        ipart = parse_int parts?0;\n        fpart\n                = 0, parts?1 == [];\n                = err, parts?1?0 != '.'\n                = parse_pint (tl parts?1) / 10**(len parts?1 - 1);\n        exp\n                = 0, parts?2 == [] && parts?3 == []\n                = err, parts?2 == [] \n                = parse_int parts?3;\n\n}\n\n/* Print integer as hex.\n */\nprint_hex i\n\t= \"0\", chars == []\n\t= \"0x\" ++ reverse chars\n{\n\tdigits = takewhile (not_equal 0)\n\t\t(map (bitwise_and 0xf) \n\t\t\t(iterate (converse right_shift 4) i));\n\tchars = map tohd digits;\n\n\ttohd x\n\t\t= (char) ((int) '0' + x), x < 10\n\t        = (char) ((int) 'a' + (x - 10));\n}\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n        [[ 0.8951,  0.2664, -0.1614],\n         [-0.7502,  1.7135,  0.0367],\n         [ 0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n        = xyz'''\n{\n\t// divide by D50 white point\n        xyz' = xyz / Vector [96.4250, 100.0, 82.4680];\n\n        rgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n        rgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n        xyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * Vector [95.0470, 100.0, 108.8827];\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n        = xyz'''\n{\n\t// divide by D65 white point\n        xyz' = xyz / Vector [95.0470, 100.0, 108.8827];\n\n        rgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n        rgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n        xyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D50\n\txyz''' = xyz'' * Vector [96.4250, 100.0, 82.4680];\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz 96.4250 100 82.4680;\n\n/* Convert D50 Lab to XYZ.\n */\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab 96.4250 100 82.4680;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in = clip2fmt \n\t(im_header_int \"BandFmt\" in)\n\t(im_recomb in (Matrix [[.3, .6, .1]]));\nim_mono2sRGB in = (unsigned char) (in ++ in ++ in);\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= fn x, is_image x\n\t= error (errors.badargs ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= fn x, is_image x\n\t\t= error (errors.badargs ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (errors.badargs ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (errors.badargs ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, LAB, im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, sRGB, im_mono2sRGB],\n\t[B_W, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ \n\t\tim_mono2sRGB],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy],\n\t[XYZ, LAB, im_XYZ2Lab],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS],\n\t[XYZ, RGB, im_XYZ2disp],\n\t[XYZ, sRGB, im_XYZ2sRGB],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ],\n\t[YXY, XYZ, im_Yxy2XYZ],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ],\n\n\t[LAB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ],\n\t[LAB, XYZ, im_Lab2XYZ],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ],\n\t[LAB, LAB, image_set_type LAB],\n\t[LAB, LCH, im_Lab2LCh],\n\t[LAB, UCS, im_Lab2UCS],\n\t[LAB, RGB, im_Lab2disp],\n\t[LAB, sRGB, im_XYZ2sRGB @ im_Lab2XYZ],\n\t[LAB, LABQ, im_Lab2LabQ],\n\t[LAB, LABS, im_Lab2LabS],\n\n\t[LCH, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LCh2Lab],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab],\n\t[LCH, YXY, im_XYZ2Yxy @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LCh2Lab],\n\t[LCH, LAB, im_LCh2Lab],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab],\n\t[LCH, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LCh2Lab],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ],\n\t[UCS, XYZ, im_UCS2XYZ],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab],\n\t[UCS, LAB, im_UCS2Lab],\n\t[UCS, LCH, im_UCS2LCh],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab],\n\t[UCS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_UCS2Lab],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_XYZ2Lab @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ \n\t\tim_clip],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (\"unable to convert \" ++ from_name ++ \" to \" ++ to_name)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n\tfrom_name = Image_type.type_names.lookup 1 0 from;\n\tto_name = Image_type.type_names.lookup 1 0 to;\n}\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x\n\t= is_image x || is_instanceof \"Image\" x || is_instanceof \"Arrow\" x ||\n\t\tis_instanceof \"Colour\" x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_instanceof \"Image\" x\n\t= get_type_im x.image.value, is_instanceof \"Arrow\" x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space,\n\t\tis_instanceof \"Colour\" x\n\t= error (\"get_type: unable to get type from \" ++ print x)\n{\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.B_W, bands == 1\n\t\t= type, bands == 3 && is_colorimetric\n\t\t= Image_type.MULTIBAND, bands != 3 && !is_colorimetric\n\t\t= type\n\t{\n\t\tis_colorimetric = Image_type.colour_spaces.present 1 type;\n\t\ttype = im_header_int \"Type\" im;\n\t\tcoding = im_header_int \"Coding\" im;\n\t\tbands = im_header_int \"Bands\" im;\n\t}\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n"
  },
  {
    "path": "share/nip2/compat/7.8/_errors.def",
    "content": "\n/* Lots of error messages.\n */\n\nerrors = class {\n\tnot1band = \"not 1 band image\";\n\tnot1band8bit = \"not 1 band 8-bit image\";\n\tnot1band3band = \"not 1 band image, or 3 band 1 column image\";\n\tnotodd = \"not odd width|height\";\n\tnotmask = \"not mask\";\n\tnotmaskim = \"not image|mask, mask\";\n\tbadcoding = \"not NOCODING or LABPACK\";\n\tbadlab = \"unable to convert to LAB\";\n\tallreal = \"not all real numbers\";\n\tallreg = \"not all regions\";\n\tbadargs = \"bad arguments to \";\n\tbadbands = \"images have differing numbers of bands\";\n\tbadcolour = \"bad arg to colourspace function\";\n\tbadmatrixmatch = \"matrix arguments do not match\";\n\tbadnum = \"wrong number of real number arguments\";\n\tbandFmt = \"bad BandFmt\";\n\tinternal = \"menu macro sanity failure!\";\n\tlengthdiff = \"list arguments differ in length\";\n\tnoimage = \"no image argument\";\n\tnoregion = \"no region argument\";\n\tnotim = \"not image\";\n\tnotimcmplx = \"not image|complex\";\n\tnotimnotreal = \"non image arguments not all real numbers\";\n\tnotimreg = \"not image|region\";\n\tnotregimreg = \"not region, image|region\";\n\tnotimregnum = \"not image|region|number\";\n\tnotimregstr = \"not image|region|string\";\n\tnotmatnum = \"not real|matrix|mask\";\n\tnotmatrix = \"not matrix|mask\";\n\tnotodd_square_matrix = \"not odd-sided square matrix|mask\";\n\tnotreal = \"not real number\";\n\tnotreglist = \"not region|[region]\";\n\tnotsquare_matrix = \"not square matrix|mask\";\n\tregwrong = \"regions not on two images\";\n\tsfacgt1 = \"shrink factors should be >= 1\";\n\tunknownType = \"unknown type\";\n\tusage = \"usage: \";\n};\n"
  },
  {
    "path": "share/nip2/compat/7.8/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y\n\t= (unsigned int) (h ++ v)\n{\n\th = (x - 1) * im_fgrey x y;\n\tv = (y - 1) * im_rot90 (im_fgrey y x);\n}\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= im''''\n{\n\tim = im_black w h b + pixel;\n\n\tim' = clip2fmt fmt im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_origin (size / 2) (size / 2) \n\t\t(image_set_type Image_type.LAB im)\n{\n\tL = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W \n\t\tl 0 0;\n\tA1 = im_fgrey size size;\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = L ++ A2 ++ A4;\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (map (const (max_value.lookup 1 0 format)) [1 .. bands])\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n"
  },
  {
    "path": "share/nip2/compat/7.8/_list.def",
    "content": "/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn (tl l), fn (hd l)\n\t= l;\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* foldl fn st l: fold list l up from the left using function fn and start value st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st (hd l)) (tl l);\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn (hd l) (tl l);\n\n/* foldr fn st l: fold up list l, right to left, with function fn and start \n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn (hd l) (foldr fn st (tl l));\n\n/* foldrl fn l: like foldr, but use the 1st element as the start value\n *\n * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= foldr fn (hd l) (tl l);\n\n/* Search a list for an element, returning it's index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn (hd l)\n\t\t= search (tl l) (n + 1);\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= hd l : init (tl l);\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* land l: and all the elements of list l together\n *\n * land (map (==0) list) == true, if every element of list is zero.\n * land :: [bool] -> bool\n */\nland = foldr logical_and true;\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= hd l, tl l == []\n\t= last (tl l);\n\n/* len l: length of list l\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta = l?0;\n\tb = l?1;\n\tx = tl (tl l);\n}\n\n/* lor l: or all the elements of list l together\n *\n * lor (map (equal 0) list) == true, if any element of list is zero.\n * lor :: [bool] -> bool\n */\nlor = foldr logical_or false;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2\n\t= map fn' (zip2 l1 l2)\n{\n\tfn' p = fn p?0 p?1;\n}\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3\n\t= map fn' (zip3 l1 l2 l3)\n{\n\tfn' p = fn p?0 p?1 p?2;\n}\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = lor (map (equal x) l);\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta = hd l;\n\tx = tl l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scan fn st l: apply (fold fn r) to every initial segment of a list\n *\n * scan add 0 [1,2,3] == [1,3,6]\n * scan :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscan fn \n\t= g \n{\n\tg st l\n\t\t= [st], l == []\n\t\t= st : g (fn st (hd l)) (tl l);\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta = hd l1;\n\t\tx = tl l1;\n\t\tb = hd l2;\n\t\ty = tl l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by fn\n *\n * split is_space \"hello world\" == [\"hello\", \"world\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n  \n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together\n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/7.8/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true of character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && land (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, land (map is_obj l)\n\t= true, land (map is_list l) &&\n\t\tland (map (not @ is_obj) l) &&\n\t\tland (map is_rectangular l) &&\n\t\tlen l > 0 &&\n\t\tland (map (equal (hd lengths)) (tl lengths))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n\tlengths = map len l;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n */\nis_matrix l = is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == []\n      = is_matrix l && len l == len (hd l);\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == []\n      = is_matrix l && (len l) % 2 == 1 && (len (l?0)) % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && (len l) % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_Guide x = is_instanceof \"HGuide\" x || is_instanceof \"VGuide\" x;\n\nis_Point x = is_instanceof \"Point\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && land (map xy l)\n{\n\txy l = is_real_list l && len l == 2;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.8/_stdenv.def",
    "content": "/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\njoin a b = a ++ b;\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\nif_then_else a b c = if a then b else c;\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error \"unimplemented vector operation\"\n{\n\tzeros = map (const 0) [1 .. len vec];\n\tones = map (const 1) [1 .. len vec];\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n/* Macbeth chart patch names.\n */\n_macbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (errors.badargs ++ \"bandsplit\")\n{\n\tbands = im_header_int \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= Image (concat (map get_value l)), \n\t\tis_listof (is_instanceof \"Image\") l\n\t= concat l, is_listof is_image l\n\t= error (errors.badargs ++ \"bandjoin\")\n{\n\tget_value x = x.value;\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= error (errors.badargs ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean_object Operator_type.COMPOUND false;\n\n\tmean_object x\n\t\t= im_avg x, is_image x\n\t\t= mean_list x, is_real_list x || is_matrix x\n\t\t= error (errors.badargs ++ \"mean\");\n\n\tmean_list l \n\t\t= s / n\n\t{\n\t\ttotals = sum l;\n\t\tn = totals?0;\n\t\ts = totals?1;\n\t}\n\n\t// return [n, sum] for a list of numbers, or a list of list of num\n\t// etc.\n\tsum x\n\t\t= foldr accumulate [0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s], is_real x\n\t\t\t= [n + n', s + s'], is_list x\n\t\t\t= error \"mean_list: not real or [real]\"\n\t\t{\n\t\t\tn = sofar?0;\n\t\t\ts = sofar?1;\n\n\t\t\tsub_acc = sum x;\n\n\t\t\tn' = sub_acc?0;\n\t\t\ts' = sub_acc?1;\n\t\t}\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= error (errors.badargs ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation_object Operator_type.COMPOUND false;\n\n\tdeviation_object x\n\t\t= im_deviate x, is_image x\n\t\t= deviation_list x, is_real_list x || is_matrix x\n\t\t= error (errors.badargs ++ \"deviation\");\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\ttotals = sum_sum2_list l;\n\t\tn = totals?0;\n\t\ts = totals?1;\n\t\ts2 = totals?2;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\tn = sofar?0;\n\t\t\ts = sofar?1;\n\t\t\ts2 = sofar?2;\n\n\t\t\tsub_acc = sum_sum2_list x;\n\n\t\t\tn' = sub_acc?0;\n\t\t\ts' = sub_acc?1;\n\t\t\ts2' = sub_acc?2;\n\t\t}\n\t}\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= error (errors.badargs ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs_object Operator_type.COMPOUND false;\n\n\tabs_object x\n\t\t= im_abs x, is_image x\n\t\t= abs_cmplx x, is_complex x\n\t\t= abs_num x, is_real x\n\t\t= abs_list x, is_real_list x\n\t\t= abs_list (map abs_list x), is_matrix x\n\t\t= error (errors.badargs ++ \"abs\");\n\n\tabs_list l = (foldr1 add (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= error (errors.badargs ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec_object Operator_type.COMPOUND false;\n\n\tabs_vec_object x\n\t\t= abs_vec_image x, is_image x\n\t\t= abs_vec_cmplx x, is_complex x\n\t\t= abs_vec_num x, is_real x\n\t\t= abs_vec_list x, is_real_list x\n\t\t= mean (Vector (map abs_vec_list x)), is_matrix x\n\t\t= error (errors.badargs ++ \"abs_vec\");\n\n\tabs_vec_list l = (foldr1 add (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (foldr1 add (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_matrix x, is_list x && is_list (hd x)\n\t= error (errors.badargs ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose_object Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_object x\n\t\t= transpose_matrix x, is_matrix x\n\t\t= transpose_image x, is_image x\n\t\t= error (errors.badargs ++ \"transpose\");\n\n\ttranspose_matrix l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_matrix (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (errors.badargs ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (errors.badargs ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\nrot90 x\n\t= oo_unary_function rot90_op x, is_class x\n\t= im_rot90 x, is_image x\n\t= error (errors.badargs ++ \"rot90\")\n{\n\trot90_op = Operator \"rot90\" \n\t\trot90_object Operator_type.COMPOUND_REWRAP false;\n\n\trot90_object x\n\t\t= rot90_matrix x, is_matrix x\n\t\t= im_rot90 x, is_image x\n\t\t= error (errors.badargs ++ \"rot90\");\n\n\t// slow, but what the heck\n\trot90_matrix l = (im_rotate_dmask90 (Matrix l)).value;\n}\n\nrot180 x\n\t= oo_unary_function rot180_op x, is_class x\n\t= im_rot180 x, is_image x\n\t= error (errors.badargs ++ \"rot180\")\n{\n\trot180_op = Operator \"rot180\" \n\t\trot180_object Operator_type.COMPOUND_REWRAP false;\n\n\trot180_object x\n\t\t= rot180_matrix x, is_matrix x\n\t\t= im_rot180 x, is_image x\n\t\t= error (errors.badargs ++ \"rot180\");\n\n\t// slow, but what the heck\n\trot180_matrix l = (im_rotate_dmask90 \n\t\t(im_rotate_dmask90 (Matrix l))).value;\n}\n\nrot270 x\n\t= oo_unary_function rot270_op x, is_class x\n\t= im_rot270 x, is_image x\n\t= error (errors.badargs ++ \"rot270\")\n{\n\trot270_op = Operator \"rot270\" \n\t\trot270_object Operator_type.COMPOUND_REWRAP false;\n\n\trot270_object x\n\t\t= rot270_matrix x, is_matrix x\n\t\t= im_rot270 x, is_image x\n\t\t= error (errors.badargs ++ \"rot270\");\n\n\t// slow, but what the heck\n\trot270_matrix l = (im_rotate_dmask90 (im_rotate_dmask90 \n\t\t(im_rotate_dmask90 (Matrix l)))).value;\n}\n\nrotquad x\n\t= oo_unary_function rotquad_op x, is_class x\n\t= im_rotquad x, is_image x\n\t= error (errors.badargs ++ \"rotquad\")\n{\n\trotquad_op = Operator \"rotquad\" \n\t\trotquad_object Operator_type.COMPOUND_REWRAP false;\n\n\trotquad_object x\n\t\t= rotquad_matrix x, is_matrix x\n\t\t= im_rotquad x, is_image x\n\t\t= error (errors.badargs ++ \"rotquad\");\n\n\trotquad_matrix l = error \"rotquad matrix: not implemented\"; \n}\n\nflipud x\n\t= oo_unary_function flipud_op x, is_class x\n\t= im_flipver x, is_image x\n\t= error (errors.badargs ++ \"flipud\")\n{\n\tflipud_op = Operator \"flipud\" \n\t\tflipud_object Operator_type.COMPOUND_REWRAP false;\n\n\tflipud_object x\n\t\t= flipud_matrix x, is_matrix x\n\t\t= im_flipver x, is_image x\n\t\t= error (errors.badargs ++ \"flipud\");\n\n\tflipud_matrix l = reverse l;\n}\n\nfliplr x\n\t= oo_unary_function fliplr_op x, is_class x\n\t= im_fliphor x, is_image x\n\t= error (errors.badargs ++ \"fliplr\")\n{\n\tfliplr_op = Operator \"fliplr\" \n\t\tfliplr_object Operator_type.COMPOUND_REWRAP false;\n\n\tfliplr_object x\n\t\t= fliplr_matrix x, is_matrix x\n\t\t= im_fliphor x, is_image x\n\t\t= error (errors.badargs ++ \"fliplr\");\n\n\tfliplr_matrix l = map reverse l;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= x, is_number x\n\t= error (errors.badargs ++ \"max\")\n{\n\tmax_op = Operator \"max\" max_list Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_matrix x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= x, is_number x\n\t= error (errors.badargs ++ \"min\")\n{\n\tmin_op = Operator \"min\" min_list Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_matrix x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= error (errors.badargs ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" \n\t\tmaxpos_object Operator_type.COMPOUND false;\n\n\tmaxpos_object x\n\t\t= maxpos_matrix x, is_matrix x\n\t\t= im_maxpos x, is_image x\n\t\t= error (errors.badargs ++ \"maxpos\");\n\n\tmaxpos_matrix m \n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= error (errors.badargs ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" \n\t\tminpos_object Operator_type.COMPOUND false;\n\n\tminpos_object x\n\t\t= minpos_matrix x, is_matrix x\n\t\t= im_minpos x, is_image x\n\t\t= error (errors.badargs ++ \"minpos\");\n\n\tminpos_matrix m \n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= error (errors.badargs ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats_object Operator_type.COMPOUND false;\n\n\tstats_object x\n\t\t= im_stats (to_image x).value, is_matrix x\n\t\t= im_stats x, is_image x\n\t\t= error (errors.badargs ++ \"stats\");\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (errors.badargs ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= rint_value x, is_image x || is_number x \n\t= error (errors.badargs ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint_value Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= scale_prim x\n{\n\tscale_op = Operator \"scale\" \n\t\tscale_prim Operator_type.COMPOUND_REWRAP false;\n\n\tscale_prim x\n\t\t= (unsigned char) x, is_number x \n\t\t= im_scale x, is_image x \n\t\t= scale_list x, is_real_list x || is_matrix x\n\t\t= error (errors.badargs ++ \"scale\");\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (errors.badargs ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (errors.badargs ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (errors.badargs ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= im_falsecolour x, is_image x \n\t= error (errors.badargs ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (errors.badargs ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (errors.badargs ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\nrecomb matrix image\n\t= colour_unary recomb_op image\n{\n\trecomb_op x\n\t\t= im_recomb x matrix, is_image x\n\t\t= error (errors.badargs ++ \"recomb\");\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= extract_area_prim obj\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" \n\t\textract_area_prim \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_area_prim obj\n\t\t= im_extract_area obj x' y' w' h', is_image obj\n\t\t= map (extract_range x' w') (extract_range y' h' obj),\n\t\t\tis_matrix obj\n\t\t= error (errors.badargs ++ \"extract_area\");\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_row_prim obj\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" \n\t\textract_row_prim \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_row_prim obj\n\t\t= im_extract_area obj 0 y' width 1, is_image obj\n\t\t= [obj?y'], is_matrix obj\n\t\t= error (errors.badargs ++ \"extract_row\")\n\t{\n\t\twidth = im_header_int \"Xsize\" obj;\n\t}\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_column_prim obj\n{\n\tx' = to_real x;\n\n\textract_column_op = Operator \"extract_column\" \n\t\textract_column_prim \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_column_prim obj\n\t\t= im_extract_area obj x' 0 1 height, is_image obj\n\t\t= map (converse cons [] @ converse subscript x') obj, \n\t\t\tis_matrix obj\n\t\t= error (errors.badargs ++ \"extract_column\")\n\t{\n\t\theight = im_header_int \"Ysize\" obj;\n\t}\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join_lr_prim a b\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin_lr_prim Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_lr_prim a b\n\t\t= im_extract_area (im_insert a b a_width 0)\n\t\t\t0 0 (a_width + b_width) out_height,\n\t\t\tis_image a && is_image b\n\t\t= map2 join a b,\n\t\t\tis_matrix a && is_matrix b\n\t\t= error (errors.badargs ++ \"join_lr\")\n\t{\n\t\ta_height = im_header_int \"Ysize\" a;\n\t\tb_height = im_header_int \"Ysize\" b;\n\t\ta_width = im_header_int \"Xsize\" a;\n\t\tb_width = im_header_int \"Xsize\" b;\n\t\tout_height = min_pair a_height b_height;\n\t}\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join_tb_prim a b\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin_tb_prim Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_tb_prim a b\n\t\t= im_extract_area (im_insert a b 0 a_height) \n\t\t\t0 0 out_width (a_height + b_height),\n\t\t\tis_image a && is_image b\n\t\t= map (take out_matrix_width) a ++ \n\t\t\tmap (take out_matrix_width) b,\n\t\t\tis_matrix a && is_matrix b\n\t\t= error (errors.badargs ++ \"join_tb\")\n\t{\n\t\ta_height = im_header_int \"Ysize\" a;\n\t\tb_height = im_header_int \"Ysize\" b;\n\t\ta_width = im_header_int \"Xsize\" a;\n\t\tb_width = im_header_int \"Xsize\" b;\n\t\tout_width = min_pair a_width b_width;\n\n\t\tout_matrix_width \n\t\t\t= min_pair a_matrix_width b_matrix_width\n\t\t{\n\t\t\ta_matrix_width = len a?0;\n\t\t\tb_matrix_width = len b?0;\n\t\t}\n\t}\n}\n\ninsert x y small big\n\t= oo_binary_function insert_op small big, is_class small\n\t= oo_binary'_function insert_op small big, is_class big\n\t= im_insert big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (errors.badargs ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n}\n\nmeasure x y w h u v image\n\t= oo_unary_function measure_op image, is_class image\n\t= im_measure image \n\t\t(to_real x) (to_real y) (to_real w) (to_real h)\n\t\t(to_real u) (to_real v), \n\t\t\tis_image image\n\t= error (errors.badargs ++ \"measure\")\n{\n\tmeasure_op = Operator \"measure\" \n\t\t(measure x y w h u v) Operator_type.COMPOUND_REWRAP false;\n}\n\nrotate angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_similarity image (cos angle) (sin angle) 0 0, \n\t\tis_real angle && is_image image \n\t= error (errors.badargs ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\trotate Operator_type.COMPOUND_REWRAP false;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = im_header_int \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\n\nclip2fmt format image\n\t= oo_unary_function (clip2fmt_op format) image, is_class image\n\t= im_clip2fmt image format, is_image image\n\t= error (errors.badargs ++ \"clip2fmt\")\n{\n\tclip2fmt_op format = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\timage = (unsigned char) im_mask2vips (Matrix m2);\n\tm2_width = im_header_int \"Xsize\" image;\n\tm2_height = im_header_int \"Ysize\" image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = im_embed image 0 (m1.width - 1) (m1.height - 1) \n\t\t(m2_width + 2 * (m1.width - 1))\n\t\t(m2_height + 2 * (m1.height - 1));\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image mask, is_image image\n\t= error (errors.badargs ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image mask, is_image image\n\t= error (errors.badargs ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image mask, is_image image\n\t= error (errors.badargs ++ \"conv\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image w h n, is_image image\n\t= error (errors.badargs ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find image\n\t= oo_unary_function hist_find_op image, is_class image\n\t= im_histgr image (-1), is_image image\n\t= error (errors.badargs ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\thist_find Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image bins, is_image image\n\t= error (errors.badargs ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\thist_find_nD Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (errors.badargs ++ \"hist_map\")\n{\n\thist_map_op = Operator \"hist_map\" \n\t\thist_map Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (errors.badargs ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (errors.badargs ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (errors.badargs ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= im_lhisteq image w h, is_image image\n\t= error (errors.badargs ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n}\n\nresize xfac yfac interp image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (errors.badargs ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac yfac, \n\t\t\tis_int xfac && is_int yfac && xfac >= 1 && yfac >= 1 &&\n\t\t\tinterp == Interpolate.nearest_neighbour\n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.nearest_neighbour\n\n\t\t// upscale by any factor, nearest neighbour \n\t\t// can't really do this right ... upscale by integer part, then\n\t\t// bilinear to exact size\n\t\t= scale (break xfac)?1 (break yfac)?1\n\t\t\t(im_zoom im (break xfac)?0 (break yfac)?0),\n\t\t\txfac >= 1 && yfac >= 1 &&\n\t\t\tinterp == Interpolate.nearest_neighbour\n\n\t\t// downscale by any factor, nearest neighbour \n\t\t// can't really do this right ... downscale by integer part, \n\t\t// then bilinear to exact size\n\t\t= scale (1 / (break xfac')?1) (1 / (break yfac')?1)\n\t\t\t(im_subsample im (break xfac')?0 (break yfac')?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.nearest_neighbour\n\n\t\t// upscale by any factor, bilinear\n\t\t= scale xfac yfac im,\n\t\t\txfac >= 1 && yfac >= 1 &&\n\t\t\tinterp == Interpolate.bilinear\n\n\t\t// downscale by any factor, bilinear\n\t\t// block shrink by integer factor, then bilinear resample to \n\t\t// exact\n\t\t= scale (1 / (break xfac')?1) (1 / (break yfac')?1)\n\t\t\t(im_shrink im (break xfac')?0 (break yfac')?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.bilinear\n\n\t\t= error (\"resize: unimplemented argument combination:\\n\" ++ \n\t\t\t\"  xfac = \" ++ print xfac ++ \"\\n\" ++\n\t\t\t\"  yfac = \" ++ print yfac ++ \"\\n\" ++\n\t\t\t\"  interp = \" ++ print interp ++ \" (\" ++\n\t\t\t\tInterpolate.names.lookup 1 0 interp ++ \")\")\n\t{\n\t\txfac' = 1 / xfac;\n\t\tyfac' = 1 / yfac;\n\n\t\t// convert a float scale to integer plus fraction\n\t\t// eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25)\n\t\tbreak f = [floor f, f / floor f];\n\n\t\t// binlinear resize\n\t\tscale xfac yfac im\n\t\t\t= im_affine im \n\t\t\t\txfac 0 0 yfac \n\t\t\t\t0 0 \n\t\t\t\t0 0 (width * xfac) (height * yfac)\n\t\t{\n\t\t\twidth = im_header_int \"Xsize\" im;\n\t\t\theight = im_header_int \"Ysize\" im;\n\t\t}\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c\n\t= map3 (map_trinary fn) a b c, is_list a && is_list b && is_list c\n\n\t= map2 (map_trinary fn a) b c, is_list b && is_list c\n\t= map2 (map_trinary (converse31 fn) b) a c, is_list a && is_list c\n\t= map2 (map_trinary (converse32 fn) c) a b, is_list a && is_list b\n\n\t= map (map_trinary fn a b) c, is_list c\n\t= map (map_trinary (converse32 fn) a c) b, is_list b\n\t= map (map_trinary (converse34 fn) b c) a, is_list a\n\n\t= fn a b c\n{\n\tconverse31 fn a b c = fn b a c;\n\tconverse32 fn a b c = fn c a b;\n\tconverse33 fn a b c = fn a c b;\n\tconverse34 fn a b c = fn b c a;\n}\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b\n\t= map2 (map_binary fn) a b, is_list a && is_list b\n\t= map (map_binary fn a) b, is_list b\n\t= map (map_binary (converse fn) b) a, is_list a\n\t= fn a b;\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a \n\t= map (map_unary fn) a, is_list a\n\t= fn a;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop block_size overlap i\n\t= map chop' [0, step .. height]\n{\n\twidth = im_header_int \"Xsize\" i;\n\theight = im_header_int \"Ysize\" i;\n\tbands = im_header_int \"Bands\" i;\n\tformat = im_header_int \"BandFmt\" i;\n\ttype = im_header_int \"Type\" i;\n\n\t/* Unique pixels per tile.\n\t */\n\tstep = block_size - overlap;\n\n\t/* Calculate padding ... pad up to block_size pixel boundary.\n\t */\n\tsx = block_size + (width - width % step);\n\tsy = block_size + (height - height % step);\n\n\t/* Expand image with black to pad size.\n\t */\n\tbackground = image_new sx sy bands format Image_coding.NOCODING type \n\t\t0 0 0;\n\tpad = im_insert background i 0 0;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, step .. width]\n\t{\n\t\tchop'' x = im_extract_area pad x y block_size block_size;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= vjoin (map hjoin il)\n{\n\t/* Join a list of tiles horizontally.\n\t */\n\thjoin l \n\t\t= foldl1 lrj l\n\t{\n\t\tlrj l r = im_lrmerge l r \n\t\t\t(hoverlap - im_header_int \"Xsize\" l) 0 10;\n\t}\n\n\t/* Join a list of tiles vertically.\n\t */\n\tvjoin l \n\t\t= foldl1 tbj l\n\t{\n\t\ttbj t b = im_tbmerge t b \n\t\t\t0 (voverlap - im_header_int \"Ysize\" t) 10;\n\t}\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n"
  },
  {
    "path": "share/nip2/compat/7.8/_types.def",
    "content": "\n/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), \"any\"];\ncheck_bool = [is_bool, \"boolean\"];\ncheck_real = [is_real, \"real\"];\ncheck_ureal = [is_ureal, \"unsigned real\"];\ncheck_preal = [is_preal, \"positive real\"];\ncheck_real_list = [is_real_list, \"list of real\"];\ncheck_string = [is_string, \"string\"];\ncheck_string_list = [is_string_list, \"list of string\"];\ncheck_int = [is_int, \"integer\"];\ncheck_uint = [is_uint, \"unsigned integer\"];\ncheck_pint = [is_pint, \"positive integer\"];\ncheck_matrix = [is_matrix, \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, \"0, 1, 2 or 3\"];\ncheck_image = [is_image, \"image\"];\ncheck_xy_list = [is_xy_list, \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_instanceof \"Matrix_base\", \"Matrix\"];\ncheck_colour_space = [is_colour_space, \"colour_space\"];\ncheck_rectangular = [is_rectangular, \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, \"HGuide or VGuide\"];\ncheck_Point = check_instance \"Point\";\ncheck_Colour = check_instance \"Colour\";\n\n/* Check a set of args. Grab _check_table. It's a list of two check\n * lists: the first checks each arg, and the second checks all args \n * together. \n *\n * - each line in argcheck is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in allcheck is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down a bit.\n */\ncheck_args x\n\t= x, badargs == [] && badalls == []\n\t= error message\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// join two strings up with a separator string\n\tjoin_sep j a b = a ++ j ++ b;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = errors.badargs ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++\n\t\t\"\\nusage\\n\" ++ indent ++ usage ++ \"\\nwhere\\n\" ++ \n\t\targ_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t\" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t\"you passed \" ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t\"you passed\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = \"condition failed: \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make usage note\n\tusage = x.name ++ \" \" ++ \n\t\tfoldr (join_sep \" \") [] (map (extract 1) argcheck);\n\n\t// make arg type notes\n\targ_types = foldr (join_sep \"\\n\") [] (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"and\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = foldr (join_sep \"\\n\") [] all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t// eg. add\n\tRELATIONAL = 2;\t\t// eg. less\n\tCOMPOUND = 3;\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (\"unknown binary operator: \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (\"unknown unary operator: \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n        \tOperator \"cast_signed_char\" cast_signed_char \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_signed_short\" cast_signed_short \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_signed_int\" cast_signed_int \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_float\" cast_float \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_double\" cast_double \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_complex\" cast_complex \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_double_complex\" cast_double_complex \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"unary_minus\" unary_minus \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"negate\" negate \n\t\t\tOperator_type.RELATIONAL false,\n        \tOperator \"complement\" complement \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"unary_plus\" unary_plus \n\t\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n        \tOperator \"re\" re Operator_type.ARITHMETIC false,\n        \tOperator \"im\" im Operator_type.ARITHMETIC false,\n        \tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n        \tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n        \tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n        \tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n        \tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n        \tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n        \tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n        \tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n        \tOperator \"log\" log Operator_type.ARITHMETIC false,\n        \tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n        \tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n        \tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n        \tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n        \tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= error (\"No method found for binary operator.\\n\" ++\n\t\t\"left = \" ++ print a ++ \"\\n\" ++\n\t\t\"operator = \" ++ op.op_name ++ \"\\n\" ++\n\t\t\"right = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n */\noo_binary'_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\top.symmetric && matches2 != []\n\t= error (\"No method found for binary operator.\\n\" ++\n\t\t\"left = \" ++ print a ++ \"\\n\" ++\n\t\t\"operator = \" ++ op.op_name ++ \"\\n\" ++\n\t\t\"right = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0,\n\t\tmatches != []\n\t= error (\"No method found for unary operator.\\n\" ++ \n\t\t\"operator = \" ++ op.op_name ++ \"\\n\" ++\n\t\t\"argument = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t/* Default: no checks ... override in subclasses.\n\t */\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x \n\t\t= oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x \n\t\t= oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op \n\t\t= oo_unary_function (oo_unary_lookup op) this;\n\n\t/* Provide a fallback for class == thing ... just use pointer\n\t * equality.\n\t */\n\too_binary_table op x = [\n\t\t[ pointer_equal this x,\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\" ],\n\t\t[ not_pointer_equal this x,\n\t\t\top.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\" ]\n\t];\n\too_unary_table op = [];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t] ++ super._check_args;\n\n\t// methods\n        oo_binary_table op x = [ \n\t\t[ this.Real (op.fn this.value x.value), \n\t\t\tis_instanceof \"Real\" x &&\n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ op.fn this.value x.value, \n\t\t\tis_instanceof \"Real\" x && \n\t\t\top.type == Operator_type.RELATIONAL ],\n\t\t[ op.fn this.value x, \n\t\t\t!is_class x ]\n\t] ++ super.oo_binary_table op x;\n\n        oo_unary_table op = [\n\t\t[ this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ op.fn this.value,\n\t\t\ttrue ]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t] ++ super._check_args;\n\n\t// methods\n        oo_binary_table op x = [ \n\t\t[ if value then x?0 else x?1,\n\t\t\top.op_name == \"if_then_else\" ],\n\t\t[ this.Bool (op.fn this.value x.value), \n\t\t\tis_instanceof \"Bool\" x ],\n\t\t[ this.Bool (op.fn this.value x), \n\t\t\tis_bool x ]\n\t] ++ super.oo_binary_table op x;\n\n        oo_unary_table op = [\n\t\t[ this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL ]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t] ++ super._check_args;\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t] ++ super._check_args;\n\n\tReal value = Number caption value;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t] ++ super._check_args;\n}\n\n// the old name\nFilename = Pathname \"Pick a file\";\n\n/* Vector type ... just a finite list of real ... handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t] ++ super._check_args;\n\n\tbands = len value;\n\n\t// methods\n        oo_binary_table op x = [ \n\t\t// Vector ++ Vector means bandwise join\n\t\t[ this.Vector (op.fn this.value x.value), \n\t\t\tis_instanceof \"Vector\" x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\") ],\n\t\t// extra check for lengths equal\n\t\t[ this.Vector (map_binary op.fn this.value x.value), \n\t\t\tis_instanceof \"Vector\" x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ this.Vector (map_binary op.fn this.value x.value), \n\t\t\tis_instanceof \"Real\" x &&\n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ this.Vector (map_binary op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC ],\n\n\t\t// need extra length check\n\t\t[ this.Vector (map bool_to_real \n\t\t\t(map_binary op.fn this.value x.value)), \n\t\t\tis_instanceof \"Vector\" x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL ],\n\t\t[ this.Vector (map bool_to_real \n\t\t\t(map_binary op.fn this.value x.value)), \n\t\t\tis_instanceof \"Real\" x &&\n\t\t\top.type == Operator_type.RELATIONAL ],\n\t\t[ this.Vector (map bool_to_real\n\t\t\t(map_binary op.fn this.value x)), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.RELATIONAL ],\n\t\t[ this.Vector (op.fn this.value x.value),\n\t\t\tis_instanceof \"Vector\" x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP ],\n\t\t[ x.Image (vec op'.op_name x.value value),\n\t\t\tis_instanceof \"Image\" x ],\n\t\t[ vec op'.op_name x value,\n\t\t\tis_image x ],\n\t\t[ op.fn this.value x, \n\t\t\tis_real x ]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n        oo_unary_table op = [\n\t\t[ this.Vector (map_unary op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ this.Vector (map bool_to_real\n\t\t\t(map_unary op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL ],\n\t\t[ this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP ],\n\t\t[ op.fn this.value,\n\t\t\ttrue ]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t] ++ super._check_args;\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// methods\n        oo_binary_table op x = [\n\t\t// mat multiply is special\n                [ this.Matrix_base mul.value,\n\t\t\tis_instanceof \"Matrix_base\" x &&\n\t\t\top.op_name == \"multiply\" ],\n                [ this.Matrix_base mul'.value,\n\t\t\tis_instanceof \"Matrix_base\" x &&\n\t\t\top.op_name == \"multiply'\" ],\n\n\t\t// mat divide is also special\n                [ this.Matrix_base div.value,\n\t\t\tis_instanceof \"Matrix_base\" x &&\n\t\t\top.op_name == \"divide\" ],\n                [ this.Matrix_base div'.value,\n\t\t\tis_instanceof \"Matrix_base\" x &&\n\t\t\top.op_name == \"divide'\" ],\n\n\t\t// power -1 means invert\n                [ this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\" ],\n                [ this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\" ],\n                [ error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\" ],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n                [ this.Matrix_base (map (map_binary op'.fn x.value) this.value),\n\t\t\tis_instanceof \"Vector\" x &&\n\t\t\top.type == Operator_type.ARITHMETIC ],\n                [ this.Matrix_base (map_binary op.fn this.value x.value),\n\t\t\t(is_instanceof \"Matrix_base\" x || \n\t\t\t is_instanceof \"Real\" x) && \n\t\t\top.type == Operator_type.ARITHMETIC ],\n\n                [ this.Matrix_base (map_binary op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC ],\n\n\t\t// compound ... don't do iteration\n                [ this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_instanceof \"Matrix_base\" x || \n\t\t\t is_instanceof \"Real\" x || \n\t\t\t is_instanceof \"Vector\" x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP ]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n        oo_unary_table op = [\n                [ this.Matrix_base (map_unary op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ],\n                [ this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP ],\n                [ op.fn this.value,\n\t\t\ttrue ]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t] ++ super._check_args;\n\n\tMatrix_base value = Matrix_vips value scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {};\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = im_read_dmask (expand filename);\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t] ++ super._check_args;\n\t_check_all = [\n\t\t[len value == 3, \"len value == 3\"]\n\t] ++ super._check_all;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = im_header_int \"Type\" im;\n\t\tbands = im_header_int \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n        oo_binary_table op x = [\n\t\t[ itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP ]\n\t] ++ super.oo_binary_table op x;\n\n        oo_unary_table op = [\n\t\t[ itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP ]\n\t] ++ super.oo_unary_table op;\n\n\tVector value = Colour colour_space value;\n}\n\n/* Base slider type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t] ++ super._check_args;\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t] ++ super._check_all;\n\n\t// methods\n        oo_binary_table op x = [ \n\t\t[ this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_instanceof \"Scale\" x &&\n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC ]\n\t] ++ super.oo_binary_table op x;\n\n\tReal value = Scale caption from to value;\n}\n\nSlider = Scale \"\";\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t] ++ super._check_args;\n\n\tBool value = Toggle caption value;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tReal value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t] ++ super._check_args;\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t] ++ super._check_args;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (map (extract col) value) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (\"item \" ++ print x ++ \" not in table\")\n\t{\n\t\tn = index (equal x) (map (extract from) value);\n\t}\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t] ++ super._check_args;\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// equal to another rect\n\tequal r = left == r.left && top == r.top && \n\t\twidth == r.width && height == r.height;\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n\n\t// operator overloading\n\t// just define equal and not equal\n        oo_binary_table op x = [ \n\t\t[ equal x, \n\t\t\tis_instanceof \"Rect\" x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\") ],\n\t\t[ !equal x, \n\t\t\tis_instanceof \"Rect\" x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\") ]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647\t// INT\n\t\t  ] ? fmt, fmt >= 0 && fmt <= INT\n\t\t= error errors.bandFmt;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tFOURIER = 24;\n\tYXY = 23;\n\tsRGB = 22;\n\tLABS = 21;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tLABQ = 16;\n\tCMYK = 15;\n\tCMC = 14;\n\tLAB = 13;\n\tXYZ = 12;\n\tLUT = 11;\n\tHISTOGRAM = 10;\n\tPOWER_SPECTRUM = 9;\n\tBLUE_ONLY = 8;\n\tGREEN_ONLY = 7;\n\tRED_ONLY = 6;\n\tYUV = 5;\n\tIR = 4;\n\tXRAY = 3;\n\tLUMINACE = 2;\n\tB_W = 1;\n\tMULTIBAND = 0;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Table [\n\t\t[ \"FOURIER\", FOURIER ],\n\t\t[ \"YXY\", YXY ],\n\t\t[ \"sRGB\", sRGB ],\n\t\t[ \"LABS\", LABS ],\n\t\t[ \"LCH\", LCH ],\n\t\t[ \"UCS\", UCS ],\n\t\t[ \"RGB\", RGB ],\n\t\t[ \"LABQ\", LABQ ],\n\t\t[ \"CMYK\", CMYK ],\n\t\t[ \"CMC\", CMC ],\n\t\t[ \"LAB\", LAB ],\n\t\t[ \"XYZ\", XYZ ],\n\t\t[ \"LUT\", LUT ],\n\t\t[ \"HISTOGRAM\", HISTOGRAM ],\n\t\t[ \"POWER_SPECTRUM\", POWER_SPECTRUM ],\n\t\t[ \"BLUE_ONLY\", BLUE_ONLY ],\n\t\t[ \"GREEN_ONLY\", GREEN_ONLY ],\n\t\t[ \"RED_ONLY\", RED_ONLY ],\n\t\t[ \"YUV\", YUV ],\n\t\t[ \"IR\", IR ],\n\t\t[ \"XRAY\", XRAY ],\n\t\t[ \"LUMINACE\", LUMINACE ],\n\t\t[ \"B_W\", B_W ],\n\t\t[ \"MULTIBAND\", MULTIBAND ]\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t */\n\tcolour_spaces = Table [\n\t\t[ \"XYZ\", Image_type.XYZ ],\n\t\t[ \"Yxy\", Image_type.YXY ],\n\t\t[ \"Lab\", Image_type.LAB ],\n\t\t[ \"LCh\", Image_type.LCH ],\n\t\t[ \"UCS\", Image_type.UCS ],\n\t\t[ \"RGB\", Image_type.RGB ],\n\t\t[ \"sRGB\", Image_type.sRGB ]\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t] ++ super._check_args;\n\n\t// fields from VIPS header\n\twidth = im_header_int \"Xsize\" value;\n\theight = im_header_int \"Ysize\" value;\n\tbands = im_header_int \"Bands\" value;\n\tformat = im_header_int \"BandFmt\" value;\n\tcoding = im_header_int \"Coding\" value;\n\ttype = im_header_int \"Type\" value;\n\txres = im_header_double \"Xres\" value;\n\tyres = im_header_double \"Yres\" value;\n\txoffset = im_header_int \"Xoffset\" value;\n\tyoffset = im_header_int \"Yoffset\" value;\n\tfilename = im_header_string \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy as a rect\n\trect = Rect (-xoffset) (-yoffset) width height;\n\n\t// extract an area, addressed in nip cordinates\n\textract_area left top width height = im_extract_area value \n\t\t(left + xoffset) (top + yoffset) width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n        oo_binary_table op x = [\n                [ this.Image (op.fn this.value x.value),\n\t\t\tis_instanceof \"Image\" x ||\n\t\t\tis_instanceof \"Real\" x ],\n                [ this.Image result_image,\n\t\t\top.op_name == \"if_then_else\" ],\n\t\t[ this.Image (vec op.op_name value x.value),\n\t\t\tis_instanceof \"Vector\" x ],\n                [ this.Image (op.fn this.value x),\n\t\t\tis_number x || is_image x ]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tto_image x\n\t\t\t= x, is_image x\n\t\t\t= x.value, is_instanceof \"Image\" x\n\t\t\t= black + x\n\t\t{\n\t\t\tblack = im_black width height target_bands;\n\t\t}\n\n\t\t// get a member from the first of a list of objects to have it\n\t\tget_property has get objects\n\t\t\t= hd members, members != []\n\t\t\t= error \"unable to get property\"\n\t\t{\n\t\t\tmembers = map get (filter has objects);\n\t\t}\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\tthen_part = x?0;\n\t\telse_part = x?1;\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_property \n\t\t\t(has_member \"bands\") (get_member \"bands\") objects;\n\t\ttarget_format = get_property \n\t\t\t(has_member \"format\") (get_member \"format\") objects;\n\t\ttarget_type = get_property has_type get_type objects;\n\n\t\tthen_image = to_image then_part;\n\t\telse_image = to_image else_part;\n\n\t\tthen_image' = clip2fmt target_format then_image;\n\t\telse_image' = clip2fmt target_format else_image;\n\n\t\tresult_image = image_set_type target_type\n\t\t\t(if value then then_image' else else_image');\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n        oo_unary_table op = [\n                [ this.Image result,\n\t\t\tis_image result ],\n                [ result,\n\t\t\ttrue ]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file str = class \n\tImage value {\n\t_check_args = [\n\t\t[str, \"str\", check_string]\n\t] ++ super._check_args;\n\n\tfile = Filename str;\n\n\tvalue = vips_image file.value;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t] ++ super._check_args;\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= image.extract_area left top width height,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height = Area image left top width height;\n}\n\nArrow image left top width height = class \n\tRect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t] ++ super._check_args;\n\t_check_all = [\n\t\t[image.rect.includes_rect this,\n\t\t\t\"image.rect.includes_rect this\"]\n\t] ++ super._check_all;\n\n\t// our rect, translated to image cods (ie. offset by origin)\n\timage_rect = Rect \n\t\t(left + image.xoffset) (top + image.yoffset) width height;\n\n\t// methods\n        oo_binary_table op x = [\n                [ this.Arrow this.image left' top' width' height',\n\t\t\tis_instanceof \"Arrow\" x && \n\t\t\top.type == Operator_type.ARITHMETIC ]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn this.left x.left;\n\t\ttop' = op.fn this.top x.top;\n\t\twidth' = op.fn this.width x.width;\n\t\theight' = op.fn this.height x.height;\n\t}\n\n        oo_unary_search op = [\n                [ this.Arrow this.image left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC ]\n\t] ++ super.oo_unary_table op \n\t{\n\t\tleft' = op.fn this.left;\n\t\ttop' = op.fn this.top;\n\t\twidth' = op.fn this.width;\n\t\theight' = op.fn this.height;\n\t}\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = VGuide image left;\n}\n\nPoint image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = Point image left top;\n}\n\n// Mark is the name nip2 expects for Point\nMark = Point;\n\n// convenience functions: make relative on an image ... subtract origin \n// offset, ie. make in pixel coordinates\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u - image.xoffset)\n\t\t(image.height * v - image.yoffset)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u - image.xoffset)\n\t\t(image.height * v - image.yoffset)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u - image.xoffset)\n\t\t(image.height * v - image.yoffset)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v - image.yoffset);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u - image.xoffset);\n\nPoint_relative image u v\n\t= Point image \n\t\t(image.width * u - image.xoffset)\n\t\t(image.height * v - image.yoffset);\n\nInterpolate = class {\n\tnearest_neighbour = 0;\n\tbilinear = 1;\n\tbicubic = 2;\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tnames = Table [\n\t\t[ \"Nearest neighbour\", nearest_neighbour ],\n\t\t[ \"Bilinear\", bilinear ],\n\t\t[ \"Bicubic\", bicubic ]\n\t];\n}\n\nSeparator = class {}\n\n// renamed in 7.9\nestpar = im_estpar;\nresample = im_transform_search;\n"
  },
  {
    "path": "share/nip2/compat/7.9/Capture.def",
    "content": "/* make a new capture image\n */\nCapture_video = class\n\tImage value {\n\t// shortcut to prefs\n\t_prefs = Workspaces.Preferences;\n\n\tdevice = _prefs.VIDEO_DEVICE;\n\tchannel = Option \"Input channel\" [\n\t\t\"TV\",\n\t\t\"Composite 1\",\n\t\t\"Composite 2\",\n\t\t\"Composite 3\"\n\t] _prefs.VIDEO_CHANNEL;\n\tbrightness = Slider 0 32767 _prefs.VIDEO_BRIGHTNESS;\n\tcolour = Slider 0 32767 _prefs.VIDEO_COLOUR;\n\tcontrast = Slider 0 32767 _prefs.VIDEO_CONTRAST;\n\thue = Slider 0 32767 _prefs.VIDEO_HUE;\n\tframes_hint = \"Average this many frames:\";\n\tframes = Slider 0 100 _prefs.VIDEO_FRAMES;\n\tmono = Toggle \"Monochrome grab\" _prefs.VIDEO_MONO;\n\tcrop = Toggle \"Crop image\" _prefs.VIDEO_CROP;\n\n\t// grab, but hide it ... if we let the crop edit\n\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\tbrightness.value colour.value contrast.value hue.value\n\t\tframes.value);\n\n\tedit_crop\n\t\t= Region _raw_grab left top width height\n\t{\n\t\tleft = _prefs.VIDEO_CROP_LEFT;\n\t\ttop = _prefs.VIDEO_CROP_TOP;\n\t\twidth = min_pair\n\t\t\t_prefs.VIDEO_CROP_WIDTH\n\t\t\t(_raw_grab.width + left);\n\t\theight = min_pair\n\t\t\t_prefs.VIDEO_CROP_HEIGHT\n\t\t\t(_raw_grab.height + top);\n\t}\n\n\taspect_hint = \"Stretch vertically by this factor:\";\n\taspect_ratio = _prefs.VIDEO_ASPECT;\n\n\tvalue \n\t\t= frame'\n\t{\n\t\tframe \n\t\t\t= edit_crop.value, crop\n\t\t\t= _raw_grab.value;\n\n\t\tframe' \n\t\t\t= colour_transform Image_type.sRGB Image_type.B_W frame,\n\t\t\t\tmono\n\t\t\t= frame;\n\t}\n}\n\n#separator\n\n/* use white image w to correct image i \n */\nLight_correct w i\n\t= map_binary wc w i\n{\n\twc w i\n\t\t= clip2fmt i.format (w' * i)\n\t{\n\t\tfac = mean w / max w;\n\t\tw' = fac * (max w / w);\n\t}\n}\n\n/* equalize bands in region r\n */\nWhite_balance r\n\t= map_unary wb r\n{\n\twb region\n\t\t= clip2fmt region.format (region.image * Vector facs)\n\t{\n\t\ttarget = mean region; \n\t\tfacs = map (divide target) (map mean (bandsplit region));\n\t}\n}\n\n/* remove features larger than a certain size from image x\n */\nSmooth_image x\n      = map_unary smooth x\n{\n\tsmooth image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfeature = Slider 1 50 20;\n\n\t\tvalue = im_resize_linear \n\t\t\t(im_shrink image.value feature.value feature.value)\n\t\t\timage.width image.height;\n\t}\n}\n\n#separator\n\n/* calculate RGB -> LAB transform from an image of a Macbeth colour chart\n */\nCalibrate_chart image = class \n        Image value {\n\t_check_args = [\n\t\t[image, \"image\", check_Image]\n\t] ++ super._check_args;\n\t_vislevel = 3;\n\n\t// get macbeth data file to use\n        macbeth = Filename \"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t// get max of input image\n\t_max_value = Image_format.maxval image.format;\n\n\t// measure chart image\n\t_camera = im_measure image.value 0 0 image.width image.height 6 4;\n\n\t// load true values\n\t_true_Lab = Matrix_file macbeth.value;\n\t_true_XYZ = colour_transform \n\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t// get Ys of greyscale\n\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t// camera greyscale (all bands)\n\t_camera_grey = drop 18 _camera.value;\n\n\t// normalise both to 0-1 and combine\n\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t_comb = Matrix (map2 cons _true_grey_Y' _camera_grey');\n\n\t// make a linearising lut ... zero on left\n\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t// and display it\n\tlinearising_lut = Image _linear_lut;\n\n\t// map the original image through the lineariser to get linear 0-1\n\t// RGB image\n\t_image' = im_maplut image.value linearising_lut.value;\n\n\t// remeasure and solve for RGB -> XYZ\n\t_camera' = im_measure _image' 0 0 image.width image.height 6 4;\n\t_pinv = (transpose _camera' * _camera') ** -1;\n\tM = transpose (_pinv * transpose _camera' * _true_XYZ);\n\n\t// convert linear RGB camera to Lab \n\tvalue = colour_transform Image_type.XYZ Image_type.LAB \n\t\t((float) (recomb M _image'));\n\n\t// measure again and compute dE76\n\t_camera'' = im_measure value 0 0 image.width image.height 6 4;\n\n\t_dEs = map abs_vec (map Vector (_camera'' - _true_Lab).value);\n\tfinal_dE76 = mean (Vector _dEs);\n\t_max_dE = foldr max_pair 0 _dEs;\n\t_worst = index (equal _max_dE) _dEs;\n\tworst_patch = _macbeth_names ? _worst ++ \n\t\t\" (patch \" ++ print (_worst + 1) ++ \")\";\n}\n\n/* apply RGB -> LAB transform to an image\n */\nCalibrate_image calib image = class \n        Image value {\n\t_check_args = [\n\t\t[calib, \"calib\", check_instance \"Calibrate_chart\"],\n\t\t[image, \"image\", check_Image]\n\t] ++ super._check_args;\n\n\t// map the original image through the lineariser to get linear 0-1\n\t// RGB image\n\t_image' = im_maplut image.value calib.linearising_lut.value;\n\n\t// convert linear RGB camera to Lab \n\tvalue = colour_transform Image_type.XYZ Image_type.LAB \n\t\t((float) (recomb calib.M _image'));\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.9/Colour.def",
    "content": "/* Save a bit of typing.\n */\n_colour_conv from to x = map_unary (colour_transform from to) x;\n\n/* convert Mono to various formats\n */\nMono_to = class {\n\t/* convert mono colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.B_W Image_type.B_W x;\n\n\t/* convert mono colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.B_W Image_type.XYZ x;\n\n\t/* convert mono colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.B_W Image_type.YXY x;\n\n\t/* convert mono colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.B_W Image_type.LAB x;\n\n\t/* convert mono colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.B_W Image_type.LCH x;\n\n\t/* convert mono colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.B_W Image_type.UCS x;\n\n\t/* convert mono colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.B_W Image_type.RGB x;\n\n\t/* convert mono colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.B_W Image_type.sRGB x;\n\n\t/* convert mono colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.B_W Image_type.LABQ x;\n\n\t/* convert mono colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.B_W Image_type.LABS x;\n}\n\n/* convert XYZ to various formats\n */\nXYZ_to = class {\n\t/* convert XYZ colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.XYZ Image_type.B_W x;\n\n\t/* convert XYZ colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.XYZ Image_type.XYZ x;\n\n\t/* convert XYZ colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.XYZ Image_type.YXY x;\n\n\t/* convert XYZ colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.XYZ Image_type.LAB x;\n\n\t/* convert XYZ colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.XYZ Image_type.LCH x;\n\n\t/* convert XYZ colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.XYZ Image_type.UCS x;\n\n\t/* convert XYZ colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.XYZ Image_type.RGB x;\n\n\t/* convert XYZ colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.XYZ Image_type.sRGB x;\n\n\t/* convert XYZ colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.XYZ Image_type.LABQ x;\n\n\t/* convert XYZ colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.XYZ Image_type.LABS x;\n}\n\n/* convert Yxy to various formats\n */\nYxy_to = class {\n\t/* convert Yxy colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.YXY Image_type.B_W x;\n\n\t/* convert Yxy colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.YXY Image_type.XYZ x;\n\n\t/* convert Yxy colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.YXY Image_type.YXY x;\n\n\t/* convert Yxy colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.YXY Image_type.LAB x;\n\n\t/* convert Yxy colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.YXY Image_type.LCH x;\n\n\t/* convert Yxy colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.YXY Image_type.UCS x;\n\n\t/* convert Yxy colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.YXY Image_type.RGB x;\n\n\t/* convert Yxy colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.YXY Image_type.sRGB x;\n\n\t/* convert Yxy colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.YXY Image_type.LABQ x;\n\n\t/* convert Yxy colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.YXY Image_type.LABS x;\n}\n\n/* convert Lab to various formats\n */\nLab_to = class {\n\t/* convert Lab colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.LAB Image_type.B_W x;\n\n\t/* convert Lab colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.LAB Image_type.XYZ x;\n\n\t/* convert Lab colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.LAB Image_type.YXY x;\n\n\t/* convert Lab colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.LAB Image_type.LAB x;\n\n\t/* convert Lab colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.LAB Image_type.LCH x;\n\n\t/* convert Lab colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.LAB Image_type.UCS x;\n\n\t/* convert Lab colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.LAB Image_type.RGB x;\n\n\t/* convert Lab colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.LAB Image_type.sRGB x;\n\n\t/* convert Lab colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.LAB Image_type.LABQ x;\n\n\t/* convert Lab colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.LAB Image_type.LABS x;\n}\n\n/* convert LCh to various formats\n */\nLCh_to = class {\n\t/* convert LCh colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.LCH Image_type.B_W x;\n\n\t/* convert LCh colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.LCH Image_type.XYZ x;\n\n\t/* convert LCh colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.LCH Image_type.YXY x;\n\n\t/* convert LCh colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.LCH Image_type.LAB x;\n\n\t/* convert LCh colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.LCH Image_type.LCH x;\n\n\t/* convert LCh colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.LCH Image_type.UCS x;\n\n\t/* convert LCh colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.LCH Image_type.RGB x;\n\n\t/* convert LCh colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.LCH Image_type.sRGB x;\n\n\t/* convert LCh colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.LCH Image_type.LABQ x;\n\n\t/* convert LCh colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.LCH Image_type.LABS x;\n}\n\n/* convert UCS to various formats\n */\nUCS_to = class {\n\t/* convert UCS colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.UCS Image_type.B_W x;\n\n\t/* convert UCS colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.UCS Image_type.XYZ x;\n\n\t/* convert UCS colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.UCS Image_type.YXY x;\n\n\t/* convert UCS colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.UCS Image_type.LAB x;\n\n\t/* convert UCS colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.UCS Image_type.LCH x;\n\n\t/* convert UCS colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.UCS Image_type.UCS x;\n\n\t/* convert UCS colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.UCS Image_type.RGB x;\n\n\t/* convert UCS colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.UCS Image_type.sRGB x;\n\n\t/* convert UCS colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.UCS Image_type.LABQ x;\n\n\t/* convert UCS colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.UCS Image_type.LABS x;\n}\n\n/* convert RGB to various formats\n */\nRGB_to = class {\n\t/* convert RGB colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.RGB Image_type.B_W x;\n\n\t/* convert RGB colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.RGB Image_type.XYZ x;\n\n\t/* convert RGB colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.RGB Image_type.YXY x;\n\n\t/* convert RGB colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.RGB Image_type.LAB x;\n\n\t/* convert RGB colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.RGB Image_type.LCH x;\n\n\t/* convert RGB colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.RGB Image_type.UCS x;\n\n\t/* convert RGB colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.RGB Image_type.RGB x;\n\n\t/* convert RGB colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.RGB Image_type.sRGB x;\n\n\t/* convert RGB colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.RGB Image_type.LABQ x;\n\n\t/* convert RGB colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.RGB Image_type.LABS x;\n}\n\n/* convert sRGB to various formats\n */\nsRGB_to = class {\n\t/* convert sRGB colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.sRGB Image_type.B_W x;\n\n\t/* convert sRGB colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.sRGB Image_type.XYZ x;\n\n\t/* convert sRGB colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.sRGB Image_type.YXY x;\n\n\t/* convert sRGB colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.sRGB Image_type.LAB x;\n\n\t/* convert sRGB colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.sRGB Image_type.LCH x;\n\n\t/* convert sRGB colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.sRGB Image_type.UCS x;\n\n\t/* convert sRGB colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.sRGB Image_type.RGB x;\n\n\t/* convert sRGB colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.sRGB Image_type.sRGB x;\n\n\t/* convert sRGB colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.sRGB Image_type.LABQ x;\n\n\t/* convert sRGB colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.sRGB Image_type.LABS x;\n}\n\n/* convert LabQ to various formats\n */\nLabQ_to = class {\n\t/* convert LabQ colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.LABQ Image_type.B_W x;\n\n\t/* convert LabQ colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.LABQ Image_type.XYZ x;\n\n\t/* convert LabQ colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.LABQ Image_type.YXY x;\n\n\t/* convert LabQ colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.LABQ Image_type.LAB x;\n\n\t/* convert LabQ colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.LABQ Image_type.LCH x;\n\n\t/* convert LabQ colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.LABQ Image_type.UCS x;\n\n\t/* convert LabQ colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.LABQ Image_type.RGB x;\n\n\t/* convert LabQ colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.LABQ Image_type.sRGB x;\n\n\t/* convert LabQ colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.LABQ Image_type.LABQ x;\n\n\t/* convert LabQ colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.LABQ Image_type.LABS x;\n}\n\n/* convert LabS to various formats\n */\nLabS_to = class {\n\t/* convert LabS colourspace to mono colourspace\n\t */\n\tMono x = _colour_conv Image_type.LABS Image_type.B_W x;\n\n\t/* convert LabS colourspace to XYZ colourspace\n\t */\n\tXYZ x = _colour_conv Image_type.LABS Image_type.XYZ x;\n\n\t/* convert LabS colourspace to Yxy colourspace\n\t */\n\tYxy x = _colour_conv Image_type.LABS Image_type.YXY x;\n\n\t/* convert LabS colourspace to Lab colourspace\n\t */\n\tLab x = _colour_conv Image_type.LABS Image_type.LAB x;\n\n\t/* convert LabS colourspace to LCh colourspace\n\t */\n\tLCh x = _colour_conv Image_type.LABS Image_type.LCH x;\n\n\t/* convert LabS colourspace to UCS colourspace\n\t */\n\tUCS x = _colour_conv Image_type.LABS Image_type.UCS x;\n\n\t/* convert LabS colourspace to RGB colourspace\n\t */\n\tRGB x = _colour_conv Image_type.LABS Image_type.RGB x;\n\n\t/* convert LabS colourspace to sRGB colourspace\n\t */\n\tsRGB x = _colour_conv Image_type.LABS Image_type.sRGB x;\n\n\t/* convert LabS colourspace to LabQ colourspace\n\t */\n\tLabQ x = _colour_conv Image_type.LABS Image_type.LABQ x;\n\n\t/* convert LabS colourspace to LabS colourspace\n\t */\n\tLabS x = _colour_conv Image_type.LABS Image_type.LABS x;\n}\n\n#separator\n\n/* recombine image bands with an editable matrix\n */\nColour_recombination in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tmatrix = Matrix_rec (identity_matrix image.bands);\n\n\t\tvalue = recomb matrix image.value;\n\t}\n}\n\n/* colour temperature conversions\n */\nColour_temperature = class {\n\t/* convert XYZ from D65 to D50 ... use the Bradford approximation\n\t */\n\tD65XYZ_to_D50XYZ in = map_unary (colour_unary im_D652D50) in;\n\n\t/* convert XYZ from D50 to D65 ... use the Bradford approximation\n\t */\n\tD50XYZ_to_D65XYZ in = map_unary (colour_unary im_D502D65) in;\n}\n\n/* various colour difference metrics \n */\ndE_ = class {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\t_apply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_instanceof \"Image\" x || is_instanceof \"Colour\" x || \n\t\t\tis_image x\n\t\t= x;\n\n\t_diff cvt in1 in2 = abs_vec (_apply_cvt cvt in1 - _apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\t_lab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\t_ucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\t/* calculate delta-E CIE76 for two objects\n\t */\n\tCIE76 in1 in2 = map_binary (_diff _lab_cvt) in1 in2;\n\n\t/* calculate delta-E00 (CIEDE2000) for two objects\n\t */\n\tCIE00 in1 in2 = map_binary \n\t\t(colour_binary \"im_dE00_fromLab\" im_dE00_fromLab) in1 in2;\n\n\t/* calculate delta-E CMC(1:1) for two objects\n\t */\n\tUCS in1 in2 = map_binary (_diff _ucs_cvt) in1 in2;\n}\n\n#separator\n\n/* apply a coloured tint to a monochrome image\n */\nTint_mono_image in \n\t= map_unary apply_tint in\n{\n\tapply_tint in = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\ttint = Colour \"Lab\" [50, 0, 0];\n\n\t\tvalue = image_set_type Image_type.LAB \n\t\t\t(fancytint inp l_tint a_tint b_tint)\n\t\t{\n\t\t\t// input image ... to L only\n\t\t\tinp_lab = colour_transform_to Image_type.LAB in.value;\n\t\t\tinp = inp_lab?0;\n\n\t\t\t// make sure tint is LAB (might be edited)\n\t\t\tlab_tint = colour_transform_to Image_type.LAB tint;\n\n\t\t\t// selected lab\n\t\t\tl_tint = lab_tint.value?0;\n\t\t\ta_tint = lab_tint.value?1;\n\t\t\tb_tint = lab_tint.value?2;\n\n\t\t\t// fancy tint function ... don't tint black and white\n\t\t\tfancytint im l a b\n\t\t\t\t= im ++ ima ++ imb\n\t\t\t{\n\t\t\t\tmod \n\t\t\t\t\t= (100 - im) / (100 - l), im > l\n\t\t\t\t\t= im / l;\n\n\t\t\t\tbackgr = image_new in.width in.height 1\n\t\t\t\t\tImage_format.FLOAT \n\t\t\t\t\tImage_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\n\t\t\t\tima = mod * (backgr + a);\n\t\t\t\timb = mod * (backgr + b);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/* displace neutral axis in LAB colourspace\n */\nAdjust_cast image\n\t= map_unary widget image\n{\n\twidget image = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tgreen_red = Slider (-20) 20 0;\n\t\tblue_yellow = Slider (-20) 20 0;\n\n\t\tvalue\n\t\t\t= (colour_transform_to (get_type image) image'').value\n\t\t{\n\t\t\timage' = colour_transform_to Image_type.LAB image;\n\t\t\timage'' = image' + \n\t\t\t\tVector [0, green_red.value, blue_yellow.value];\n\t\t}\n\t}\n}\n\n/* displace h, scale LC in LCh colourspace\n */\nAdjust_hue_saturation_brightness image\n\t= map_unary widget image\n{\n\twidget image = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\thue = Slider 0 360 0;\n\t\tsaturation = Slider 0.01 5 1;\n\t\tbrightness = Slider 0.01 5 1;\n\n\t\tvalue\n\t\t\t= (colour_transform_to (get_type image) image'').value\n\t\t{\n\t\t\timage' = colour_transform_to Image_type.LCH image;\n\t\t\timage'' = \n\t\t\t\timage' * Vector [bv, sv, 1] + Vector [0, 0, hv];\n\t\t\tbv = brightness.value;\n\t\t\tsv = saturation.value;\n\t\t\thv = hue.value;\n\t\t}\n\t}\n}\n\n/* find pixels with a similar colour\n */\nSimilar_colour image\n\t= map_unary match image\n{\n\tmatch image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\ttarget_patch = Region image \n\t\t\t(20 - image.xoffset) \n\t\t\t(20 - image.yoffset)\n\t\t\t10 10;\n\t\ttarget_colour = Colour_from_image target_patch;\n\t\tdE_threshold = Slider 0 100 10;\n\n\t\tvalue = (dE_.CIE76 image target_colour < dE_threshold).value;\n\t}\n}\n\n/* plot an ab scatter histogram\n */\nPlot_ab_scatter image\n\t= map_unary widget image\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tbins = 8;\n\n\t\tvalue \n\t\t\t= bg * (((90 / mx) * hist) ++ blk)\n\t\t{\n\t\t\tlab = colour_transform_to Image_type.LAB image.value;\n\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\thist = hist_find_nD bins ab;\n\t\t\tmx = max hist;\n\t\t\tbg = lab_slice bins 1;\n\t\t\tblk = 1 + im_black bins bins 2;\n\t\t}\n\t}\n}\n\n\n\n\n"
  },
  {
    "path": "share/nip2/compat/7.9/Filter.def",
    "content": "/* Some useful masks.\n */\n_filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n_filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n_filter_laplacian = Matrix_con 1 128 [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n_filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n_filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n_filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\n/* 3x3 blur of image\n */\nBlur x = map_unary (conv _filter_blur) x;\n\n/* 3x3 sharpen of image\n */\nSharpen x = map_unary (conv _filter_sharp) x;\n\n/* 1-pixel displacement emboss\n */\nEmboss x = map_unary (conv _filter_emboss) x;\n\n/* 3x3 median filter of image\n */\nMedian x = map_unary (rank 3 3 5) x;\n\n/* 3x3 laplacian of image\n */\nLaplacian x = map_unary (conv _filter_laplacian) x;\n\n/* 3x3 Sobel edge detect of image\n */\nSobel x\n        = map_unary sobel x\n{ \n\tsobel im\n\t\t= abs (a - 128) + abs (b - 128)\n\t{\n\t\ta = conv _filter_sobel im;\n\t\tb = conv (rot270 _filter_sobel) im;\n\t}\n}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\nLinedet x\n        = map_unary lindet x\n{ \n\tlindet im\n\t\t= foldr1 max_pair images\n\t{\n\t\tmasks = take 4 (iterate rot45 _filter_lindet);\n\t\timages = map (converse conv im) masks;\n        }\n}\n\n#separator\n\n/* custom convolution of an image\n */\nCustom_convolution in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\tseparable \n\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t= false;\n\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\t\tborder = Toggle \"Output image matches input image in size\" true;\n\n\t\tvalue \n\t\t\t= im_embed image' 0 off off image.width image.height,\n\t\t\t\tborder\n\t\t\t= image'\n\t\t{\n\t\t\tconv_op \n\t\t\t\t= im_conv_raw, !separable && type == 0\n\t\t\t\t= im_convsep_raw, separable && type == 0\n\t\t\t\t= im_convf_raw, !separable && type == 1\n\t\t\t\t= im_convsepf_raw, separable && type == 1\n\t\t\t\t= error \"boink!\";\n\n\t\t\timage' = conv_op image.value matrix;\n\n\t\t\toff = (matrix.width + 1) / 2;\n\t\t}\n\t}\n}\n\n/* blur with a radius and shape\n */\nCustom_blur in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tradius = Slider 1 50 1;\n\t\tshape = Option \"Mask shape\" [\n\t\t\t\"Square\",\n\t\t\t\"Gaussian\"\n\t\t] 0;\n\n\t\tvalue \n\t\t\t= im_convsep in.value mask\n\t\t{\n\t\t\t/* Make a square mask.\n\t\t\t */\n\t\t\tmask_sq_line = map (const 1) \n\t\t\t\t[1 .. 2 * radius.value - 1];\n\t\t\tmask_sq_sum = foldr1 add mask_sq_line;\n\t\t\tmask_sq_sep = Matrix_con mask_sq_sum 0 [mask_sq_line];\n\n\t\t\t/* Make a gaussian mask. sigma is not really related\n\t\t\t * to radius very well, sort-of bodge it.\n\t\t\t */\n\t\t\tmask_g = im_gauss_imask (radius.value / 2) 0.2;\n\t\t\tmask_g_line = mask_g.value ? (mask_g.height / 2);\n\t\t\tmask_g_sum = foldr1 add mask_g_line;\n\t\t\tmask_g_sep = Matrix_con mask_g_sum 0 [mask_g_line];\n\n\t\t\tmask\n\t\t\t\t= mask_sq_sep, shape.value == 0\n\t\t\t\t= mask_g_sep;\n\t\t}\n\t}\n}\n\n/* cored sharpen of L only in LAB image\n */\nCustom_sharpen in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tsize = Option \"Mask size\" [\n\t\t\t\"3 x 3\",\n\t\t\t\"5 x 5\",\n\t\t\t\"7 x 7\",\n\t\t\t\"9 x 9\",\n\t\t\t\"11 x 11\"\n\t\t] 0;\n\n\t\tsmooth_threshold = Slider 0 5 1.5;\n\t\tbrighten_max = Slider 1 50 10;\n\t\tdarken_max = Slider 1 50 50;\n\t\tflat_sharp = Slider (-2) 5 1;\n\t\tjaggy_sharp = Slider (-2) 5 2;\n\n\t\tvalue = im_sharpen in.value \n\t\t\t[3, 5, 7, 9, 11]?size\n\t\t\tsmooth_threshold.value \n\t\t\tbrighten_max.value \n\t\t\tdarken_max.value\n\t\t\tflat_sharp.value\n\t\t\tjaggy_sharp.value;\n\t}\n}\n\n/* custom rank filter of an image\n */\nCustom_rank in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\twindow_size_hint = \"Length of side of window to pass \" ++ \n\t\t\t\"over image:\";\n\t\twindow_size = 3;\n\t\trank = (int) ((window_size * window_size + 1) / 2);\n\t\tborder = Toggle \"Output image matches input image in size\" true;\n\n\t\tvalue \n\t\t\t= im_embed image' 0 off off image.width image.height,\n\t\t\t\tborder\n\t\t\t= image'\n\t\t{\n\t\t\timage' = im_rank_raw image.value \n\t\t\t\twindow_size window_size rank;\n\n\t\t\toff = (window_size + 1) / 2;\n\t\t}\n\t}\n}\n\n/* statistical difference of an image\n */\nStatistical_difference in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\twindow_size_hint = \"Length of side of window to pass \" ++ \n\t\t\t\"over image:\";\n\t\twindow_size = 11;\n\t\ttarget_mean = 128;\n\t\ttarget_mean_weight = Slider 0 1 0.8;\n\t\ttarget_deviation = 50;\n\t\ttarget_deviation_weight = Slider 0 1 0.8;\n\t\tborder = Toggle \"Output image matches input image in size\" true;\n\n\t\tvalue \n\t\t\t= im_embed image' 0 off off image.width image.height,\n\t\t\t\tborder\n\t\t\t= image'\n\t\t{\n\t\t\timage' = im_stdif_raw image.value \n\t\t\t\ttarget_mean_weight.value target_mean\n\t\t\t\ttarget_deviation_weight.value target_deviation\n\t\t\t\twindow_size window_size;\n\n\t\t\toff = (window_size + 1) / 2;\n\t\t}\n\t}\n}\n\n#separator\n\n/* various ideal fourier filters\n */\nIdeal_filter = class {\n\t_preview_size = 64;\n\n\t_high_low image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"High or low\" [\"High pass\", \"Low pass\"] 0;\n\n\t\t_type = type.value;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\tfrequency_cutoff.value 0 0 0 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\tfrequency_cutoff.value 0 0 0 0;\n\t}\n\n\t_ring image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tring_width = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Ring pass\", \"Ring reject\"] 0;\n\n\t\t_type = type.value + 6;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\tfrequency_cutoff.value ring_width.value 0 0 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\tfrequency_cutoff.value ring_width.value 0 0 0;\n\t}\n\n\t_band image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\tradius = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Band pass\", \"Band reject\"] 0;\n\n\t\t_type = type.value + 12;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\tfrequency_cutoff_x.value\n\t\t\t\tfrequency_cutoff_y.value\n\t\t\t\tradius.value 0 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\tfrequency_cutoff_x.value frequency_cutoff_y.value\n\t\t\tradius.value 0 0;\n\t}\n\n\t/* high or low pass ideal filter\n\t */\n\tHigh_low x = map_unary _high_low x;\n\n\t/* ring pass or reject ideal filter\n\t */\n\tRing x = map_unary _ring x;\n\n\t/* band pass or reject ideal filter\n\t */\n\tBand x = map_unary _band x;\n}\n\n/* Gaussian fourier filters\n */\nGaussian_filter = class {\n\t_preview_size = 64;\n\n\t_high_low image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"High or low\" [\"High pass\", \"Low pass\"] 0;\n\n\t\t_type = type.value + 4;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\tfrequency_cutoff.value \n\t\t\t\tamplitude_cutoff.value 0 0 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\tfrequency_cutoff.value amplitude_cutoff.value 0 0 0;\n\t}\n\n\t_ring image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tring_width = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Ring pass\", \"Ring reject\"] 0;\n\n\t\t_type = type.value + 10;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\tfrequency_cutoff.value\n\t\t\t\tring_width.value amplitude_cutoff.value 0 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\tfrequency_cutoff.value\n\t\t\tring_width.value amplitude_cutoff.value 0 0;\n\t}\n\n\t_band image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\tradius = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Band pass\", \"Band reject\"] 0;\n\n\t\t_type = type.value + 16;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\tfrequency_cutoff_x.value\n\t\t\t\tfrequency_cutoff_y.value\n\t\t\t\tradius.value amplitude_cutoff.value 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\tfrequency_cutoff_x.value\n\t\t\tfrequency_cutoff_y.value\n\t\t\tradius.value amplitude_cutoff.value 0;\n\t}\n\n\t/* high or low pass Gaussian filter\n\t */\n\tHigh_low x = map_unary _high_low x;\n\n\t/* ring pass or reject Gaussian filter\n\t */\n\tRing x = map_unary _ring x;\n\n\t/* band pass or reject Gaussian filter\n\t */\n\tBand x = map_unary _band x;\n}\n\n/* various Butterworth fourier filters\n */\nButterworth_filter = class {\n\t_preview_size = 64;\n\n\t_high_low image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\torder = Slider 1 10 2;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"High or low\" [\"High pass\", \"Low pass\"] 0;\n\n\t\t_type = type.value + 2;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\torder.value frequency_cutoff.value\n\t\t\t\tamplitude_cutoff.value 0 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\torder.value frequency_cutoff.value\n\t\t\tamplitude_cutoff.value 0 0;\n\t}\n\n\t_ring image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\torder = Slider 1 10 2;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tring_width = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Ring pass\", \"Ring reject\"] 0;\n\n\t\t_type = type.value + 8;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\torder.value frequency_cutoff.value\n\t\t\t\tring_width.value amplitude_cutoff.value 0;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\torder.value frequency_cutoff.value\n\t\t\tring_width.value amplitude_cutoff.value 0;\n\t}\n\n\t_band image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\torder = Slider 1 10 2;\n\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\tradius = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Band pass\", \"Band reject\"] 0;\n\n\t\t_type = type.value + 14;\n\n\t\tvisualize_mask\n\t\t\t= Image vis\n\t\t{\n\t\t\tvis = image_set_type Image_type.FOURIER (rotquad mask);\n\t\t\tmask = im_create_fmask \n\t\t\t\t_preview_size _preview_size _type\n\t\t\t\torder.value frequency_cutoff_x.value\n\t\t\t\tfrequency_cutoff_y.value\n\t\t\t\tradius.value amplitude_cutoff.value;\n\t\t}\n\n\t\tvalue = im_flt_image_freq image.value _type \n\t\t\torder.value frequency_cutoff_x.value\n\t\t\tfrequency_cutoff_y.value\n\t\t\tradius.value amplitude_cutoff.value;\n\t}\n\n\t/* high or low pass Butterworth filter\n\t */\n\tHigh_low x = map_unary _high_low x;\n\n\t/* ring pass or reject Butterworth filter\n\t */\n\tRing x = map_unary _ring x;\n\n\t/* band pass or reject Butterworth filter\n\t */\n\tBand x = map_unary _band x;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.9/Format.def",
    "content": "/* various operations to convert numeric precision\n */\nConvert_format_to = class {\n\t/* convert to unsigned 8 bit [0, 255]\n\t */\n\tunsigned_8bit x = map_unary cast_unsigned_char x;\n\n\t/* convert to signed 8 bit [-128, 127]\n\t */\n\tsigned_8bit x = map_unary cast_signed_char x;\n\n\t/* convert to unsigned 16 bit [0, 65535]\n\t */\n\tunsigned_16bit x = map_unary cast_unsigned_short x;\n\n\t/* convert to signed 16 bit [-32768, 32767]\n\t */\n\tsigned_16bit x = map_unary cast_signed_short x;\n\n\t/* convert to unsigned 32 bit [0, 4294967295]\n\t */\n\tunsigned_32bit x = map_unary cast_unsigned_int x;\n\n\t/* convert to signed 32 bit [-2147483648, 2147483647]\n\t */\n\tsigned_32bit x = map_unary cast_signed_int x;\n\n\t/* convert to IEEE 32 bit floating point\n\t */\n\tfloat_32bit x = map_unary cast_float x;\n\n\t/* convert to IEEE 64 bit floating point\n\t */\n\tfloat_64bit x = map_unary cast_double x;\n\n\t/* convert to 64 bit complex (2 x IEEE 32 bit floating point)\n\t */\n\tcomplex_64bit x = map_unary cast_complex x;\n\n\t/* convert to 128 bit complex (2 x IEEE 64 bit floating point)\n\t */\n\tcomplex_128bit x = map_unary cast_double_complex x;\n}\n\n/* linear scale of pixel values to fit range 0-255\n */\nScale_to_byte x = map_unary scale x;\n\n#separator\n\n/* try to make a matrix out of an object\n */\nConvert_to_matrix in = map_unary to_matrix in;\n\n/* try to make an image out of an object\n */\nConvert_to_image in = map_unary to_image in;\n\n#separator\n\n/* measure average value of a set of patches\n */\nMatrix_from_colour_chart x\n\t= map_unary chart x\n{\n\tchart image = class \n\t\tMatrix value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\n\t\tpacross = 6;\n\t\tpdown = 4;\n\t\tvalue = (im_measure image.value 0 0 image.width image.height\n\t\t\tpacross pdown).value;\n\n\t\t/* Hmm, not very helpful, we throw edits away.\n\t\t */\n\t\tMatrix_vips_edit value scale offset filename display = \n\t\t\tchart image;\n\t}\n}\n\n/* make a synthetic colour chart image from a matrix\n */\nColour_chart_from_matrix matrix\n\t= map_unary build_chart matrix\n{\n\tbuild_chart matrix = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[matrix, \"matrix\", check_Matrix]\n\t\t] ++ super._check_args;\n\n\t\tpatches_across = 6;\n\t\tpatches_down = 4;\n\t\tpatch_width = 50;\n\t\tpatch_height = 50;\n\t\tborder_width = 0;\n\n\t\tvalue\n\t\t\t= imagearray_assemble overlap overlap patch_table \n\t\t{\n\t\t\toverlap = -border_width;\n\n\t\t\t// patch numbers for row starts\n\t\t\trowstart = map (multiply patches_across) \n\t\t\t\t[0 .. patches_down - 1];\n\n\t\t\t// assemble patches ... each one a pixel value\n\t\t\tpatches = map (take patches_across) \n\t\t\t\t(map (converse drop matrix.value) rowstart);\n\n\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\tpatch v = image_new patch_width patch_height (len v) \n\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t// make an image for each patch\n\t\t\tpatch_table = map (map patch) patches;\n\t\t}\n\t}\n}\n\n#separator\n\n/* make a colour from the average values in an image\n */\nColour_from_image image\n\t= map_unary test image\n{\n\ttest x\n\t\t= build_chart x, is_instanceof \"Image\" x\n\t\t= build_chart (Image pixel), is_instanceof \"Point\" x\n\t\t= error (\"Colour_from_image: arg not Image or Point: \" ++ \n\t\t\tprint x)\n\t{\n\t\tpixel = x.image.extract_area x.left x.top 1 1;\n\t}\n\n\tbuild_chart image = class \n\t\tColour colour_space value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\n\t\tcolour_space \n\t\t\t= table.lookup 1 0 type, table.present 1 type\n\t\t\t= error (\"Colour_from_image: unable to make Colour \" ++\n\t\t\t\t\"from \" ++ \n\t\t\t\tImage_type.type_names.lookup 1 0 type ++\n\t\t\t\t\" image\")\n\t\t{\n\t\t\ttable = Image_type.colour_spaces;\n\t\t\ttype = im_header_int \"Type\" image.value;\n\t\t}\n\n\t\tvalue = map mean (bandsplit image.value);\n\t}\n}\n\n/* make a constant image from a colour patch\n */\nImage_from_colour x\n\t= map_unary build x\n{\n\tbuild c = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[c, \"c\", check_Colour]\n\t\t] ++ super._check_args;\n\n\t\twidth = 64;\n\t\theight = 64;\n\n\t\tvalue = image_new width height 3 Image_format.FLOAT \n\t\t\tImage_coding.NOCODING (get_type c) c 0 0;\n\t}\n}\n\n#separator\n\n/* try to break object in into a list of components\n */\nDecompose in\n\t= map_unary dec in\n{\n\tdec x\n\t\t= bandsplit x, is_instanceof \"Image\" x\n\t\t= map Vector x.value, is_instanceof \"Matrix_base\" x\n\t\t= x.value, is_instanceof \"Vector\" x || is_instanceof \"Real\" x\n\t\t= error \"Decompose: not Image/Matrix/Vector/Real\";\n}\n\n/* try to put a list of objects together into a large single object\n */\nCompose x\n\t= Vector x, is_real_list x\n\t= Matrix x, is_matrix x\n\t= bandjoin x, is_listof (is_instanceof \"Image\") x\n\t= Vector (map get_value x), is_listof (is_instanceof \"Real\") x\n\t= Matrix (map get_value x), is_listof (is_instanceof \"Vector\") x\n\t= map_unary Compose x, is_list x\n\t= error \"Compose: not list of Image/Vector/Real/image/real\"\n{\n\tget_value x = x.value;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.9/Histogram.def",
    "content": "/* find histogram of x\n */\nHist_find x = map_unary hist_find x;\n\n/* find n-dimensional histogram from n-band image\n */\nHist_find_nD in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\t// default to something small-ish\n\t\tbins = 8;\n\n\t\tvalue = hist_find_nD bins image.value;\n\t}\n}\n\n/* map image x through histogram hist\n */\nHist_map hist x = map_binary hist_map hist x;\n\n/* find cumulative histogram of hist\n */\nHist_cumulative x = map_unary hist_cum x;\n\n/* find normalised histogram of hist\n */\nHist_normalise x = map_unary hist_norm x;\n\n/* find LUT which matches hist in to hist ref\n */\nHist_match in ref = map_binary hist_match in ref;\n\n#separator\n\n/* histogram equalisation\n */\nHist_equalise = class {\n\t/* histogram equalise x globally\n\t */\n\tGlobal x = map_unary hist_equalize x;\n\n\t/* local histogram equalisation using region r as window\n\t */\n\tLocal r = map_unary (hist_equalize_local r.width r.height) r.image;\n}\n\n/* slice a line of pixels along a guide line and display as a histogram\n */\nGuide_slice in\n\t= map_unary widget in\n{\n\twidget guide = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[guide, \"Guide\", check_Guide]\n\t\t] ++ super._check_args;\n\n\t\tvalue \n\t\t\t= image_set_type Image_type.HISTOGRAM slice\n\t\t{\n\t\t\tslice\n\t\t\t\t= guide.image.extract_area \n\t\t\t\t\tguide.image.rect.left guide.top \n\t\t\t\t\tguide.width 1,\n\t\t\t\t\tis_instanceof \"HGuide\" guide\n\t\t\t\t= guide.image.extract_area\n\t\t\t\t\tguide.left guide.image.rect.top\n\t\t\t\t\t1 guide.height;\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.9/Image.def",
    "content": "/* take a copy of x\n */\nDuplicate x = map_unary copy x;\n\n/* crop image x\n */\nCrop x \n\t= map_unary build_widget x\n{\n\tbuild_widget image = widget image \n\t\t(image.width * 0.25 - image.xoffset)\n\t\t(image.height * 0.25 - image.yoffset)\n\t\t(image.width * 0.5)\n\t\t(image.height * 0.5);\n\n\twidget image left top width height = class \n\t\tRegion image left top width height {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 4;\n\n\t\tRegion_edit image left top width height \n\t\t\t= widget image left top width height;\n\t}\n}\n\n/* insert image b into image a\n */\nInsert a b = class \n\tImage value {\n\t_check_args = [\n\t\t[a, \"a\", check_Image],\n\t\t[b, \"b\", check_Image]\n\t] ++ super._check_args;\n\t_check_all = [\n\t\t[a.format == b.format && a.coding == b.coding && \n\t\t\ta.bands == b.bands, \n\t\t\t\"a.format == b.format && a.coding == b.coding && \" ++\n\t\t\t\t\"a.bands == b.bands\"],\n\t\t[a.width >= b.width && a.height >= b.height,\n\t\t\t\"First image should be able to enclose second\"]\n\t];\n\t_vislevel = 3;\n\n\tplace = Area a ((a.width - b.width) / 2) ((a.height - b.height) / 2) \n\t\tb.width b.height;\n\n\tvalue\n\t\t= im_insert_noexpand a' b'' place.left place.top\n\t{\n\t\ta' = a.value;\n\t\tb' = b.value;\n\n\t\tb'' = clip2fmt a.format b';\n\t}\n}\n\n/* join two images left/right or up/down\n */\nJoin = class {\n\t_check_ab_args a b = [\n\t\t[a, \"a\", check_Image],\n\t\t[b, \"b\", check_Image]\n\t];\n\t_check_ab_all a b = [\n\t\t[a.format == b.format && a.coding == b.coding && \n\t\t\ta.bands == b.bands,\n\t\t\t\"a.format == b.format && a.coding == b.coding && \" ++\n\t\t\t\t\"a.bands == b.bands\"]\n\t];\n\n\t/* join two images left-right\n\t */\n\tLeft_right a b = class \n\t\tImage value {\n\t\t_check_args = _check_ab_args a b ++ super._check_args;\n\t\t_check_all = _check_ab_all a b ++ super._check_all;\n\n\t\tshim = Slider 0 100 0;\n\t\tbackground_colour = 0;\n\t\talign = Option \"Alignment\" [\"Top\", \"Centre\", \"Bottom\"] 1;\n\n\t\tvalue = im2\n\t\t{\n\t\t\tw = a.width + b.width + shim.value;\n\t\t\th = max_pair a.height b.height;\n\n\t\t\tbg = image_new w h a.bands\n\t\t\t\ta.format a.coding a.type\n\t\t\t\tbackground_colour\n\t\t\t\t0 0;\n\n\t\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\t\tmax_pair 0 (a.height - b.height)]; \n\n\t\t\tim1 = im_insert_noexpand bg a.value \n\t\t\t\t0 (ya?align);\n\t\t\tim2 = im_insert_noexpand im1 b.value \n\t\t\t\t(a.width + shim.value) (yb?align);\n\t\t}\n\t}\n\n\t/* join two images top-bottom\n\t */\n\tTop_bottom a b = class Image value {\n\t\t_check_args = _check_ab_args a b ++ super._check_args;\n\t\t_check_all = _check_ab_all a b ++ super._check_all;\n\n\t\tshim = Slider 0 100 0;\n\t\tbackground_colour = 0;\n\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 1;\n\n\t\tvalue = im2\n\t\t{\n\t\t\tw = max_pair a.width b.width;\n\t\t\th = a.height + b.height + shim.value;\n\n\t\t\tbg = image_new w h a.bands\n\t\t\t\ta.format a.coding a.type\n\t\t\t\tbackground_colour\n\t\t\t\t0 0;\n\n\t\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\t\tmax_pair 0 (a.width - b.width)]; \n\n\t\t\tim1 = im_insert_noexpand bg a.value \n\t\t\t\t(xa?align) 0;\n\t\t\tim2 = im_insert_noexpand im1 b.value \n\t\t\t\t(xb?align) (a.height + shim.value);\n\t\t}\n\t}\n\n\t/* join a 2-D array of images\n\t */\n\tArray x = class Image value {\n\t\thspacing = Slider (-100) (100) 0;\n\t\tvspacing = Slider (-100) (100) 0;\n\t\tvalue \n\t\t\t= imagearray_assemble \n\t\t\t\t(-hspacing.value) (-vspacing.value) x'\n\t\t{\n\t\t\tx' = map (map getval) x;\n\t\t\tgetval x \n\t\t\t\t= x.value, is_class x\n\t\t\t\t= x;\n\t\t}\n\t}\n}\n\n/* morph images to match (needs the rubbersheet plugin)\n */\nRubber = class {\n\t_rubber_interp = Option \"Interpolation\"\n\t\t(map (extract 0) Interpolate.names.value)\n\t\tInterpolate.bilinear;\n\t_rubber_order = Option \"order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t_rubber_edges = Toggle \"Wrap image edges\" false;\n\n\t/* find a transform which will turn sample image into reference image\n\t */\n\tRubber_find reference sample = class\n\t\tMatrix transformation {\n\t\t_vislevel = 3;\n\n\t\t// controls\n\t\torder = _rubber_order;\n\t\tinterp = _rubber_interp;\n\t\tedges = _rubber_edges;\n\t\tmax_error = 0.3;\n\t\tmax_iterations = 10;\n\n\t\t// transform\n\t\t_result = resample sample.value reference.value \n\t\t\tmax_error max_iterations order.value \n\t\t\tinterp.value edges.value;\n\n\t\t// results\n\t\ttransformed_image = Image (_result?0);\n\t\ttransformation = (_result?1).value;\n\t\tfinal_error = _result?2;\n\t}\n\n\t/* apply a transform to an image\n\t */\n\tRubber_apply transform image = class\n\t\tImage value {\n\t\t// controls\n\t\tinterp = _rubber_interp;\n\t\tedges = _rubber_edges;\n\n\t\tvalue = im_transform image.value transform \n\t\t\tinterp.value edges.value;\n\t}\n\n\t/* change a transformation's scale factor\n\t */\n\tRubber_scale transform = class \n\t\tMatrix scaled_transform {\n\t\tfactor_hint = \"scale transform by this factor\";\n\t\tfactor_x = 1;\n\t\tfactor_y = 1;\n\n\t\t// pairwise multiply\n\t\tscaled_transform \n\t\t\t= map2 (map2 multiply) transform.value facs\n\t\t{\n\t\t\tfacs = [[ factor_x, factor_y ],\n\t\t\t\t[ 1, 1 ],\n\t\t\t\t[ 1, 1 ],\n\t\t\t\t[ 1 / factor_x, 1 / factor_y ],\n\t\t\t\t[ 1 / factor_x, 1 / factor_y ],\n\t\t\t\t[ 1 / factor_x, 1 / factor_y ]];\n\t\t}\n\t}\n}\n\n#separator\n\n/* set pixels to 255 - x\n */\nPhotographic_negative x \n\t= map_unary invert x\n{\n\tinvert x\n\t\t= oo_unary_function neg_op x, is_class x\n\t\t= im_invert x, is_image x\n\t\t= 255 - x, is_number x \n\t\t= error (errors.badargs ++ \"invert\");\n\n\tneg_op = Operator \"photographic_negative\" \n\t\tinvert Operator_type.ARITHMETIC false;\n}\n\n/* falsecolour a mono image\n */\nFalsecolour x = map_unary falsecolour x;\n\n#separator\n\n/* adjust brightness and contrast of image x\n */\nAdjust_scale_offset x\n\t= map_unary widget x\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tscale = Slider 0.001 255 1;\n\t\toffset = Slider (-128) 128 0;\n\n\t\tvalue = clip2fmt image.format (image * scale + offset).value;\n\t}\n}\n\n/* adjust gamma of image x\n */\nAdjust_gamma x\n\t= map_unary widget x\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tgamma = Slider 0.001 4 1;\n\t\timage_maximum_hint = \"Change image_maximum if this is \" ++\n\t\t\t\"not an 8 bit image\";\n\t\timage_maximum = 255;\n\n\t\tvalue = clip2fmt image.format gammaed.value \n\t\t{\n\t\t\tgammaed = (image_maximum / image_maximum ** gamma) * \n\t\t\t\timage ** gamma;\n\t\t}\n\t}\n}\n\n/* change advisory header fields of image x\n */\nEdit_header x\n\t= map_unary widget x\n{\n\ttype_names = Image_type.type_names;\n\tnames = sort (map (extract 0) type_names.value);\n\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\txres = image.xres;\n\t\tyres = image.yres;\n\t\txoffset = image.xoffset;\n\t\tyoffset = image.yoffset;\n\n\t\ttype_option \n\t\t\t= Option \"Image type\" names pos\n\t\t{\n\t\t\tname = type_names.lookup 1 0 image.type;\n\t\t\tpos = index (equal name) names;\n\t\t}\n\n\t\tvalue = im_copy_set image.value \n\t\t\ttype xres yres xoffset yoffset\n\t\t{\n\t\t\ttype = type_names.lookup 0 1 names?type_option;\n\t\t}\n\t}\n}\n\n#separator\n\n/* rotate and scale one image to match another\n */\nMatch a b = class \n\tImage value {\n\t_check_args = [\n\t\t[a, \"a\", check_Image],\n\t\t[b, \"b\", check_Image]\n\t] ++ super._check_args;\n\t_vislevel = 3;\n\n\tap1 = Point_relative a 0.5 0.25;\n\tbp1 = Point_relative b 0.5 0.25;\n\tap2 = Point_relative a 0.5 0.75;\n\tbp2 = Point_relative b 0.5 0.75;\n\n\trefine = Toggle \"Refine selected tie-points\" false;\n\n\tvalue\n\t\t= b'''\n\t{\n\t\t_prefs = Workspaces.Preferences;\n\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\ta' = a.value;\n\t\tb' = b.value;\n\n\t\tb'' = clip2fmt a.format b';\n\n\t\tap1' = ap1.image_rect;\n\t\tap2' = ap2.image_rect;\n\t\tbp1' = bp1.image_rect;\n\t\tbp2' = bp2.image_rect;\n\n\t\tb''' \n\t\t\t= im_match_linear_search a' b''\n\t\t\t\tap1'.left ap1'.top bp1'.left bp1'.top\n\t\t\t\tap2'.left ap2'.top bp2'.left bp2'.top\n\t\t\t\tobject window,\n\t\t\t\t\trefine \n\t\t\t= im_match_linear a' b''\n\t\t\t\tap1'.left ap1'.top bp1'.left bp1'.top\n\t\t\t\tap2'.left ap2'.top bp2'.left bp2'.top;\n\t}\n}\n\n/* make a colour overlay of two mono images\n */\nOverlay a b = class \n\tImage value {\n\t_check_args = [\n\t\t[a, \"a\", check_Image],\n\t\t[b, \"b\", check_Image]\n\t] ++ super._check_args;\n\t_check_all = [\n\t\t[a.bands == 1 && b.bands == 1,\n\t\t\t\"a.bands == 1 && b.bands == 1\"]\n\t] ++ super._check_all;\n\t_vislevel = 3;\n\n\tap1 = Point_relative a 0.5 0.25;\n\tbp1 = Point_relative b 0.5 0.25;\n\tap2 = Point_relative a 0.5 0.75;\n\tbp2 = Point_relative b 0.5 0.75;\n\n\trefine = Toggle \"Refine selected tie-points\" false;\n\tlock = Toggle \"No resize\" false;\n\tcolour = Option \"Colour overlay as\" [\n\t\t\"Green over Red\",\n\t\t\"Blue over Red\",\n\t\t\"Red over Green\",\n\t\t\"Red over Blue\",\n\t\t\"Blue over Green\",\n\t\t\"Green over Blue\"\n\t] 0;\n\n\tvalue\n\t\t= [(a' ++ b''' ++ black), \n\t\t\t(a' ++ black ++ b'''), \n\t\t\t(b''' ++ a' ++ black), \n\t\t\t(b''' ++ black ++ a'), \n\t\t\t(black ++ a' ++ b'''), \n\t\t\t(black ++ b''' ++ a')]?colour\n\t{\n\t\t_prefs = Workspaces.Preferences;\n\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\ta' = a.value;\n\t\tb' = b.value;\n\n\t\tb'' = clip2fmt a.format b';\n\n\t\tap1' = ap1.image_rect;\n\t\tap2' = ap2.image_rect;\n\t\tbp1' = bp1.image_rect;\n\t\tbp2' = bp2.image_rect;\n\n\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t// distance along the vector joining p1 and p2\n\t\tnorm p1 p2\n\t\t\t= Rect left' top' 0 0, lock\n\t\t\t= p2\n\t\t{\n\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t// 100000 to give precision since we pass points as\n\t\t\t// ints to match\n\t\t\tn = 100000 * sign v;\n\t\t\tleft' = p1.left + re n;\n\t\t\ttop' = p1.top + im n;\n\t\t}\n\n\t\tap2'' = norm ap1' ap2';\n\t\tbp2'' = norm bp1' bp2';\n\n\t\tb''' \n\t\t\t= im_match_linear_search a' b''\n\t\t\t\tap1'.left ap1'.top bp1'.left bp1'.top\n\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\tobject window,\n\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\trefine && !lock\n\t\t\t= im_match_linear a' b''\n\t\t\t\tap1'.left ap1'.top bp1'.left bp1'.top\n\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\n\t\tblack = image_new a.width a.height \n\t\t\ta.bands a.format a.coding a.type \n\t\t\t0 0 0;\n\t}\n}\n\n/* browse through the bands of a multiband image with a slider\n */\nBrowse_multiband image = class\n        Image value {\n\t_vislevel = 3;\n\n        band = Slider 0 (image.bands - 1) 0;\n        display = Option \"Display as\" [\n            \"Grey\",\n            \"Green over Red\",\n            \"Blue over Red\",\n            \"Red over Green\",\n            \"Red over Blue\",\n            \"Blue over Green\",\n            \"Green over Blue\"\n\t] 0;\n\n        value \n\t\t= output\n\t{\n\n                down = (int) band.value;\n                up = (int) (band.value + 1);\n                remainder = band.value - down;\n\n                a = (image.value ? up) * remainder;\n                b = (image.value ? down) * (1 - remainder);\n\t\tc = image_new image.width image.height 1\n\t\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W\n\t\t\t0 0 0;\n\n                output = [  \n\t\t\ta + b, \n\t\t\ta ++ b ++ c, \n\t\t\ta ++ c ++ b, \n\t\t\tb ++ a ++ c,\n\t\t\tb ++ c ++ a, \n\t\t\tc ++ a ++ b, \n\t\t\tc ++ b ++ a\n\t\t] ? display;\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.9/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/7.9\n\nstart_DATA = \\\n\tMath.def \\\n\tImage.def \\\n\tMosaic.def \\\n\tColour.def \\\n\tResize.def \\\n\tCapture.def \\\n\tFormat.def \\\n\tFilter.def \\\n\tMorphology.def \\\n\tNew.def \\\n\tHistogram.def \\\n\tPrint.def \\\n\tRotate.def \\\n\tStatistics.def \\\n\tX_ray.def \\\n\t_convert.def \\\n\t_errors.def \\\n\t_generate.def \\\n\t_list.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\t_types.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/7.9/Math.def",
    "content": "/* basic arithmetic for objects\n */\nArithmetic = class {\n\t/* add a and b\n\t */\n\tAdd a b = map_binary add a b;\n\n\t/* subtract b from a \n\t */\n\tSubtract a b = map_binary subtract a b;\n\n\t/* multiply a by b\n\t */\n\tMultiply a b = map_binary multiply a b;\n\n\t/* divide a by b\n\t */\n\tDivide a b = map_binary divide a b;\n\n\t/* remainder after dividing a by b\n\t */\n\tRemainder a b = map_binary remainder a b;\n\n\tsep1 = Separator;\n\n\t/* absolute value of x\n\t */\n\tAbsolute_value x = map_unary abs x;\n\n\t/* like Absolute_value, but treat pixels as vectors\n\t */\n\tAbsolute_value_vector x = map_unary abs_vec x;\n\n\t/* calculate unit vector for band elements\n\t */\n\tSign x = map_unary sign x;\n\n\t/* multiply by -1\n\t */\n\tNegate x = map_unary unary_minus x;\n}\n\n/* trigonometry operations (all in degrees)\n */\nTrig = class {\n\t/* calculate sine x\n\t */\n\tSin x = map_unary sin x;\n\n\t/* calculate cosine x\n\t */\n\tCos x = map_unary cos x;\n\n\t/* calculate tangent x\n\t */\n\tTan x = map_unary tan x;\n\n\tsep1 = Separator;\n\n\t/* calculate arc sine x\n\t */\n\tAsin x = map_unary asin x;\n\n\t/* calculate arc cosine x\n\t */\n\tAcos x = map_unary acos x;\n\n\t/* calculate arc tangent x\n\t */\n\tAtan x = map_unary atan x;\n\n\tsep2 = Separator;\n\n\t/* convert degrees to radians\n\t */\n\tRad x = map_unary rad x;\n\n\t/* convert radians to degrees\n\t */\n\tDeg x = map_unary deg x;\n\n\tsep3 = Separator;\n\n\t/* is angle within t degrees of r, mod 360\n\t */\n\tAngle_range t r angle\n\t      =\tclock (max - angle) < 2*r\n\t{\n\t\tmax = clock (t + r);\n\n\t\tclock a \n\t\t      =\ta + 360, a < 0;\n\t\t      =\ta - 360, a >= 360;\n\t\t      = a;\n\t}\n}\n\n/* logarithms and anti-logs\n */\nLog = class {\n\t/* calculate e ** x\n\t */\n\tExponential x = map_unary (power e) x;\n\n\t/* log base e of x\n\t */\n\tLog_natural x = map_unary log x;\n\n\tsep1 = Separator;\n\n\t/* log base 10 of x\n\t */\n\tLog10 x = map_unary log10 x;\n\n\t/* calculate 10 ** x\n\t */\n\tExponential10 x = map_unary (power 10) x;\n\n\tsep2 = Separator;\n\n\t/* calculate x ** y\n\t */\n\tRaise_to_power x y = map_binary power x y;\n}\n\n/* operations on complex numbers and images\n */\nComplex = class {\n\t/* extract fields from complex\n\t */\n\tComplex_extract = class {\n\t\t/* extract real part of complex\n\t\t */\n\t\tReal in = map_unary re in;\n\n\t\t/* extract imaginary part of complex\n\t\t */\n\t\tImaginary in = map_unary im in;\n\t}\n\n\t/* join a and b to make a complex \n\t */\n\tComplex_build a b = map_binary comma a b;\n\n\tsep1 = Separator;\n\n\t/* convert real and imag to amplitude and phase\n\t */\n\tPolar a = map_unary polar a;\n\n\t/* convert (amplitude, phase) image to rectangular coordinates\n\t */\n\tRectangular x = map_unary rectangular x;\n\n\tsep2 = Separator;\n\n\t/* invert imaginary part\n\t */\n\tConjugate x = map_unary conj x;\n}\n\n/* bitwise boolean operations for integer objects\n */\nBoolean = class {\n\t/* bitwise and of a and b\n\t */\n\tAnd a b = map_binary bitwise_and a b;\n\n\t/* bitwise or of a and b\n\t */\n\tOr a b = map_binary bitwise_or a b;\n\n\t/* bitwise exclusive or of a and b\n\t */\n\tEor a b = map_binary eor a b;\n\n\t/* invert a\n\t */\n\tNot a = map_unary not a;\n\n\tsep1 = Separator;\n\n\t/* shift a right by b bits\n\t */\n\tRight_shift a b = map_binary right_shift a b;\n\n\t/* shift a left by b bits\n\t */\n\tLeft_shift a b = map_binary left_shift a b;\n\n\tsep2 = Separator;\n\n\t/* b where a is non-zero, c elsewhere\n\t */\n\tIf_then_else a b c = map_trinary if_then_else a b c;\n\n\t/* or the bands of an image together\n\t */\n\tBand_or im = foldr1 bitwise_or (bandsplit im);\n\n\t/* and the bands of an image together\n\t */\n\tBand_and im = foldr1 bitwise_and (bandsplit im);\n}\n\n/* all comparison operations\n */\nRelational = class {\n\t/* find points at which a is equal to b\n\t */\n\tEqual a b = map_binary equal a b;\n\n\t/* find points at which a is not equal to b\n\t */\n\tNot_equal a b = map_binary not_equal a b;\n\n\t/* find points at which a is greater than b\n\t */\n\tMore a b = map_binary more a b;\n\n\t/* find points at which a is less than b\n\t */\n\tLess a b = map_binary less a b;\n\n\t/* find points at which a is greater than or equal to b\n\t */\n\tMore_equal a b = map_binary more_equal a b;\n\n\t/* find points at which a is less than or equal to b\n\t */\n\tLess_equal a b = map_binary less_equal a b;\n}\n\n/* operations on lists\n */\nList = class {\n\t/* take first element of list\n\t */\n\tHead x = hd x;\n\n\t/* drop the first element of list \n\t */\n\tTail x = tl x;\n\n\t/* drop the last element of list\n\t */\n\tInit x = init x;\n\n\t/* take the last element of list\n\t */\n\tLast x = last x;\n\n\tsep1 = Separator;\n\n\t/* reverse order of elements in list \n\t */\n\tReverse x = reverse x;\n\n\t/* sort elements of list into ascending order\n\t */\n\tSort x = sort x;\n\n\t/* remove duplicates from list\n\t */\n\tMake_set x = mkset equal x;\n\n\t/* exchange rows and columns in a list of lists\n\t */\n\tTranspose_list x = transpose x;\n\n\t/* flatten a list of lists into a single list\n\t */\n\tConcat l = concat l;\n\n\tsep2 = Separator;\n\n\t/* find the length of list \n\t */\n\tLength x = len x;\n\n\t/* return element n from list (index from zero)\n\t */\n\tSubscript n x = n ? x;\n\n\t/* take the first n elements of list x\n\t */\n\tTake n x = take n x;\n\n\t/* drop the first n elements of list x\n\t */\n\tDrop n x = drop n x;\n\n\tsep3 = Separator;\n\n\t/* join two lists end to end\n\t */\n\tJoin a b = a ++ b;\n\n\t/* put element a on the front of list x\n\t */\n\tCons a x = a : x;\n\n\t/* join two lists, pairwise\n\t */\n\tZip a b = zip2 a b;\n}\n\n/* various rounding operations\n */\nRound = class {\n\t/* smallest integral value not less than x \n\t */\n\tCeil x = map_unary ceil x;\n\n\t/* largest integral value not greater than x \n\t */\n\tFloor x = map_unary floor x;\n\n\t/* round to nearest integer\n\t */\n\tRint x = map_unary rint x;\n}\n\n/* forward and reverse fourier transforms\n */\nFourier = class {\n\t/* find fourier transform of image\n\t */\n\tForward a = map_unary (rotquad @ fwfft) a;\n\n\t/* find inverse fourier transform of image\n\t */\n\tReverse a = map_unary (invfft @ rotquad) a;\n\n\t/* rotate quadrants \n\t */\n\tRotate_quadrants a = map_unary rotquad a;\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.9/Morphology.def",
    "content": "/* Some useful masks.\n */\n_morph_mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n_morph_mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n_morph_mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n_morph_thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n/* dilate x with 8-connected mask\n */\nDilate8 x = map_unary (dilate _morph_mask8) x;\n\n/* dilate x with 4-connected mask\n */\nDilate4 x = map_unary (dilate _morph_mask4) x;\n\n/* erode x with 8-connected mask\n */\nErode8 x = map_unary (erode _morph_mask8) x;\n\n/* erode x with 4-connected mask\n */\nErode4 x = map_unary (erode _morph_mask4) x;\n\n#separator\n\n/* open with 8-connected mask\n */\nOpen x = map_unary (dilate _morph_mask8 @ erode _morph_mask8) x;\n\n/* close with 8-connected mask\n */\nClose x = map_unary (erode _morph_mask8 @ dilate _morph_mask8) x;\n\n/* remove single points \n */\nClean x \n\t= map_unary clean x\n{\n\tclean x = x ^ erode _morph_mask1 x;\n}\n\n/* thin once\n */\nThin x \n\t= map_unary thinall x\n{\n\tmasks = take 8 (iterate rot45 _morph_thin);\n\tthin1 m x = x ^ erode m x;\n\tthinall x = foldr thin1 x masks;\n}\n\n#separator\n\n/* dilate object x with mask m\n */\nDilate m x = map_unary (dilate m) x;\n\n/* erode object x with mask m\n */\nErode m x = map_unary (erode m) x;\n\n/* dilate mask m with itself n times\n */\nDilate_multiple m n = (iterate (dilate m) m)?n;\n\n/* erode mask m with itself n times\n */\nErode_multiple m n = (iterate (erode m) m)?n;\n\n#separator\n\n/* morph with a mask you can edit\n */\nCustom_morphology in\n\t= map_unary morph in\n{\n\tmorph image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tmask = _morph_mask8;\n\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\thint_apply_n_times = \"Number of times to apply mask:\";\n\t\tapply_n_times = 1;\n\t\tborder = Toggle \"Output image matches input image in size\" true;\n\n\t\tvalue \n\t\t\t= im_embed image' 0 xoff yoff image.width image.height,\n\t\t\t\tborder\n\t\t\t= image'\n\t\t{\n\t\t\tfatmask = (iterate (dilate mask) mask) ? \n\t\t\t\t(apply_n_times - 1);\n\n\t\t\timage'\n\t\t\t\t= im_erode_raw image.value fatmask, \n\t\t\t\t\ttype.value == 0\n\t\t\t\t= im_dilate_raw image.value fatmask;\n\n\t\t\txoff = (fatmask.width + 1) / 2;\n\t\t\tyoff = (fatmask.height + 1) / 2;\n\t\t}\n\t}\n}\n\n/* search in from the edges of an image for the first non-zero pixel\n */\nFind_profile in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\tvalue = image_set_type Image_type.HISTOGRAM [\n\t\t\tim_profile image.value 0,\n\t\t\trot270 (im_profile image.value 1),\n\t\t\tim_profile (flipud image.value) 0,\n\t\t\trot270 (im_profile (fliplr image.value) 1)\n\t\t]?edge;\n\t}\n}\n\n/* count the average number of black-to-white transitions across an image\n */\nCount_lines in\n\t= map_unary widget in\n{\n\twidget image = class \n\t\tReal value {\n\t\t_check_args = [\n\t\t\t[image, \"Image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Count\" [\n\t\t\t\"Horizontal lines\", \n\t\t\t\"Vertical lines\"\n\t\t] 0;\n\n\t\tvalue = im_cntlines image.value edge.value;\n\t}\n}\n\n\n\n"
  },
  {
    "path": "share/nip2/compat/7.9/Mosaic.def",
    "content": "\n/* Check and group a point list by image.\n */\n_mosaic_sort_test l\n\t= error \"mosaic: not all points\",\n\t\t!is_listof (is_instanceof \"Point\") l\n\t= error \"mosaic: points not on two images\",\n\t\tlen images != 2 \n\t= error \"mosaic: images do not match in format and coding\",\n\t\t!all_equal (map get_format l) ||\n\t\t!all_equal (map get_coding l)\n\t= error \"mosaic: not same number of points on each image\",\n\t\t!foldr1 equal (map len l') \n\t= l'\n{\n\t// test for all elements of a list equal\n\tall_equal l = land (map (equal (hd l)) (tl l));\n\n\tget_format x = x.image.format;\n\tget_coding x = x.image.coding;\n\n\t// all the different images\n\tget_image x = x.image;\n\timages = mkset pointer_equal (map get_image l);\n\n\t// find all points defined on image\n\ttest_image image p = p.image === image;\n\tfind l image = filter (test_image image) l;\n\n\t// group point list by image\n\tl' = map (find l) images;\n}\n\n/* Sort a point group to get right before left, and within each group to get \n * above before below.\n */\n_mosaic_sort_lr l\n\t= l''\n{\n\t// sort to get upper point first\n\tabove a b = a.top < b.top;\n\tl' = map (sortc above) l;\n\n\t// sort to get right group before left group\n\tright a b = (a?0).left > (b?0).left;\n\tl'' = sortc right l';\n}\n\n/* Sort a point group to get top before bottom, and within each group to get \n * left before right.\n */\n_mosaic_sort_tb l\n\t= l''\n{\n\t// sort to get upper point first\n\tleft a b = a.left < b.left;\n\tl' = map (sortc left) l;\n\n\t// sort to get right group before left group\n\tbelow a b = (a?0).top > (b?0).top;\n\tl'' = sortc below l';\n}\n\n/* Put 'em together! Group by image, sort vertically (or horizontally) with\n * one of the above, transpose to get pairs matched up, and flatten again.\n */\n_mosaic_sort fn = concat @ transpose @ fn @ _mosaic_sort_test;\n\n/* translate and blend two images together left/right or up/down\n */\nMosaic_translate = class {\n\t_check_ab_args a b = [\n\t\t[a, \"a\", check_Point],\n\t\t[b, \"b\", check_Point]\n\t];\n\n\t// shortcut to prefs\n\t_prefs = Workspaces.Preferences;\n\t_search_area = _prefs.MOSAIC_WINDOW_SIZE;\n\t_object_size = _prefs.MOSAIC_OBJECT_SIZE;\n\t_blend_width = Slider 0 100 _prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t_refine = Toggle \"Refine selected tie-points\" _prefs.MOSAIC_REFINE;\n\n\t/* translate and blend two images left/right\n\t */\n\tLeft_right a b = class \n\t\tImage value {\n\t\t_check_args = _check_ab_args a b ++ super._check_args;\n\n\t\tblend_width = _blend_width;\n\t\trefine = _refine;\n\n\t\tvalue \n\t\t\t= im_lrmosaic a'.image.value b'.image.value\n\t\t\t\t0\n\t\t\t\tra'.left ra'.top\n\t\t\t\trb'.left rb'.top\n\t\t\t\t(_object_size / 2) (_search_area / 2)\n\t\t\t\t0\n\t\t\t\tblend_width.value,\n\t\t\t\t\trefine\n\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t(rb'.left - ra'.left)\n\t\t\t\t(rb'.top - ra'.top)\n\t\t\t\tblend_width.value\n\t\t{\n\t\t\tsorted = _mosaic_sort _mosaic_sort_lr [a, b];\n\t\t\ta' = sorted?0;\n\t\t\tb' = sorted?1;\n\t\t\tra' = a'.image_rect;\n\t\t\trb' = b'.image_rect;\n\t\t}\n\t}\n\n\t/* translate and blend two images top/bottom\n\t */\n\tTop_bottom a b = class \n\t\tImage value {\n\t\t_check_args = _check_ab_args a b ++ super._check_args;\n\n\t\tblend_width = _blend_width;\n\t\trefine = _refine;\n\n\t\tvalue \n\t\t\t= im_tbmosaic a'.image.value b'.image.value\n\t\t\t\t0\n\t\t\t\tra'.left ra'.top\n\t\t\t\trb'.left rb'.top\n\t\t\t\t(_object_size / 2) (_search_area / 2)\n\t\t\t\t0\n\t\t\t\tblend_width.value,\n\t\t\t\t\trefine\n\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t(rb'.left - ra'.left)\n\t\t\t\t(rb'.top - ra'.top)\n\t\t\t\tblend_width.value\n\t\t{\n\t\t\tsorted = _mosaic_sort _mosaic_sort_tb [a, b];\n\t\t\ta' = sorted?0;\n\t\t\tb' = sorted?1;\n\t\t\tra' = a'.image_rect;\n\t\t\trb' = b'.image_rect;\n\t\t}\n\t}\n}\n\n/* forcibly translate and blend two images together left/right or up/down\n */\nMosaic_force = class {\n\t_check_ab_args a b = [\n\t\t[a, \"a\", check_Point],\n\t\t[b, \"b\", check_Point]\n\t];\n\n\t// shortcut to prefs\n\t_prefs = Workspaces.Preferences;\n\t_blend_width = Slider 0 100 _prefs.MOSAIC_MAX_BLEND_WIDTH;\n\n\t/* forcibly translate and blend two images left/right\n\t */\n\tLeft_right a b = class \n\t\tImage value {\n\t\t_check_args = _check_ab_args a b ++ super._check_args;\n\n\t\tblend_width = _blend_width;\n\n\t\tvalue \n\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t(rb'.left - ra'.left)\n\t\t\t\t(rb'.top - ra'.top)\n\t\t\t\tblend_width.value\n\t\t{\n\t\t\tsorted = _mosaic_sort _mosaic_sort_lr [a, b];\n\t\t\ta' = sorted?0;\n\t\t\tb' = sorted?1;\n\t\t\tra' = a'.image_rect;\n\t\t\trb' = b'.image_rect;\n\t\t}\n\t}\n\n\t/* forcibly translate and blend two images top/bottom\n\t */\n\tTop_bottom a b = class \n\t\tImage value {\n\t\t_check_args = _check_ab_args a b ++ super._check_args;\n\n\t\tblend_width = _blend_width;\n\n\t\tvalue \n\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t(rb'.left - ra'.left)\n\t\t\t\t(rb'.top - ra'.top)\n\t\t\t\tblend_width.value\n\t\t{\n\t\t\tsorted = _mosaic_sort _mosaic_sort_tb [a, b];\n\t\t\ta' = sorted?0;\n\t\t\tb' = sorted?1;\n\t\t\tra' = a'.image_rect;\n\t\t\trb' = b'.image_rect;\n\t\t}\n\t}\n}\n\n/* translate, rotate, scale and blend two images together left/right or up/down\n */\nMosaic_affine = class {\n\t_check_abcd_args a b c d = [\n\t\t[a, \"a\", check_Point],\n\t\t[b, \"b\", check_Point],\n\t\t[c, \"c\", check_Point],\n\t\t[d, \"d\", check_Point]\n\t];\n\n\t// shortcut to prefs\n\t_prefs = Workspaces.Preferences;\n\t_search_area = _prefs.MOSAIC_WINDOW_SIZE;\n\t_object_size = _prefs.MOSAIC_OBJECT_SIZE;\n\t_blend_width = Slider 0 100 _prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t_refine = Toggle \"Refine selected tie-points\" _prefs.MOSAIC_REFINE;\n\n\t/* translate, rotate, scale and blend two images left/right\n\t */\n\tLeft_right a b c d = class \n\t\tImage value {\n\t\t_check_args = _check_abcd_args a b c d ++ super._check_args;\n\n\t\tblend_width = _blend_width;\n\t\trefine = _refine;\n\n\t\tvalue \n\t\t\t= im_lrmosaic1 a'.image.value b'.image.value\n\t\t\t\t0\n\t\t\t\tra'.left ra'.top\n\t\t\t\trb'.left rb'.top\n\t\t\t\trc'.left rc'.top\n\t\t\t\trd'.left rd'.top\n\t\t\t\t(_object_size / 2) (_search_area / 2)\n\t\t\t\t0\n\t\t\t\tblend_width.value,\n\t\t\t\t\trefine\n\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\tra'.left ra'.top\n\t\t\t\trb'.left rb'.top\n\t\t\t\trc'.left rc'.top\n\t\t\t\trd'.left rd'.top\n\t\t\t\tblend_width.value\n\t\t{\n\t\t\tsorted = _mosaic_sort _mosaic_sort_lr [a, b, c, d];\n\t\t\ta' = sorted?0;\n\t\t\tb' = sorted?1;\n\t\t\tc' = sorted?2;\n\t\t\td' = sorted?3;\n\t\t\tra' = a'.image_rect;\n\t\t\trb' = b'.image_rect;\n\t\t\trc' = c'.image_rect;\n\t\t\trd' = d'.image_rect;\n\t\t}\n\t}\n\n\t/* translate, rotate, scale and blend two images top/bottom\n\t */\n\tTop_bottom a b c d = class \n\t\tImage value {\n\t\t_check_args = _check_abcd_args a b c d ++ super._check_args;\n\n\t\tblend_width = _blend_width;\n\t\trefine = _refine;\n\n\t\tvalue \n\t\t\t= im_tbmosaic1 a'.image.value b'.image.value\n\t\t\t\t0\n\t\t\t\tra'.left ra'.top\n\t\t\t\trb'.left rb'.top\n\t\t\t\trc'.left rc'.top\n\t\t\t\trd'.left rd'.top\n\t\t\t\t(_object_size / 2) (_search_area / 2)\n\t\t\t\t0\n\t\t\t\tblend_width.value,\n\t\t\t\t\trefine\n\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\tra'.left ra'.top\n\t\t\t\trb'.left rb'.top\n\t\t\t\trc'.left rc'.top\n\t\t\t\trd'.left rd'.top\n\t\t\t\tblend_width.value\n\t\t{\n\t\t\tsorted = _mosaic_sort _mosaic_sort_tb [a, b, c, d];\n\t\t\ta' = sorted?0;\n\t\t\tb' = sorted?1;\n\t\t\tc' = sorted?2;\n\t\t\td' = sorted?3;\n\t\t\tra' = a'.image_rect;\n\t\t\trb' = b'.image_rect;\n\t\t\trc' = c'.image_rect;\n\t\t\trd' = d'.image_rect;\n\t\t}\n\t}\n}\n\n#separator\n\n/* disassemble mosaic, adjust brightnesses to match, and reassemble\n */\nMosaic_balance x\n\t= map_unary balance x\n{\n\tbalance x\n\t\t= oo_unary_function balance_op x, is_class x\n\t\t= im_global_balancef x \n\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\tis_image x\n\t\t= error (errors.badargs ++ \"balance\")\n\t{\n\t\tbalance_op = Operator \"balance\" balance \n\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t}\n}\n\n/* brighten along a left/right or up/down axis\n */\nTilt_brightness = class {\n\t/* brighten along a left/right axis\n\t */\n\tLeft_right x \n\t\t= map_unary tilt_lr x\n\t{\n\t\ttilt_lr image = class\n\t\t\tImage value {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t] ++ super._check_args;\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Slider (-1) 1 0;\n\n\t\t\tvalue\n\t\t\t\t= final\n\t\t\t{\n\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\tramp' = bandjoin \n\t\t\t\t\t(map (const ramp) [1..image.bands]);\n\t\t\t\tscale = (ramp' - 0.5) * tilt + 1;\n\t\t\t\tfinal = image.value * scale;\n\t\t\t}\n\t\t}\n\t}\n\n\t/* brighten along a top/bottom axis\n\t */\n\tTop_bottom x \n\t\t= map_unary tilt_tb x\n\t{\n\t\ttilt_tb image = class\n\t\t\tImage value {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t] ++ super._check_args;\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Slider (-1) 1 0;\n\n\t\t\tvalue\n\t\t\t\t= final\n\t\t\t{\n\t\t\t\tramp = rot90 \n\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\tramp' = bandjoin \n\t\t\t\t\t(map (const ramp) [1..image.bands]);\n\t\t\t\tscale = (ramp' - 0.5) * tilt + 1;\n\t\t\t\tfinal = image.value * scale;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\n/* disassemble mosaic, substitute different image files, and reassemble\n */\nMosaic_rebuild x \n\t= map_unary remosaic x\n{\n\tremosaic image = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\told_hint = \"For the name of each file making up the mosaic, \" ++\n\t\t\t\"exchange this string:\";\n\t\told = \"foo\";\n\t\tnew_hint = \"for this string:\";\n\t\tnew = \"bar\";\n\n\t\tvalue = im_remosaic image.value old new;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.9/New.def",
    "content": "\n/* make a new blank image\n */\nNew_image \n\t= widget\n{\n\ttype_names = Image_type.type_names;\n\tnames = sort (map (extract 0) type_names.value);\n\n\tdefault_type_name = type_names.lookup 1 0 Image_type.MULTIBAND;\n\tdefault_type_pos = index (equal default_type_name) names;\n\n\twidget = class \n\t\tImage value {\n\t\twidth = 64;\n\t\theight = 64;\n\t\tbands = 1;\n\n\t\tformat_option = Option \"Image format\" [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t] 0;\n\n\t\ttype_option = Option \"Image type\" names default_type_pos;\n\n\t\tvalue\n\t\t\t= image_new width height bands format\n\t\t\t\tImage_coding.NOCODING type 0 0 0\n\t\t{\n\t\t\tformat = format_option.value;\n\t\t\ttype = type_names.lookup 0 1 names?type_option;\n\t\t}\n\t}\n}\n\n/* pick a colour ... any colour space\n */\nNew_colour\n\t= widget \"Lab\" [50,0,0]\n{\n\twidget default_colour value = class\n\t\tColour colour_space value {\n\t\t_colourspaces = [\n\t\t\t\"XYZ\",         \n\t\t\t\"Yxy\",         \n\t\t\t\"Lab\",         \n\t\t\t\"LCh\",         \n\t\t\t\"UCS\",        \n\t\t\t\"RGB\",       \n\t\t\t\"sRGB\"      \n\t\t];\n\n\t\tcolour_space_option = Option \"Colour space\" _colourspaces\n\t\t\t(index (equal default_colour) _colourspaces);\n\n\t\tcolour_space = colour_space_option.labels?\n\t\t\tcolour_space_option.value;\n\n\t\tColour_edit colour_space value = widget colour_space value;\n\t}\n}\n\n/* make a slider\n */\nNew_slider = Slider 0 255 128;\n\n/* make a toggle widget\n */\nNew_toggle = Toggle \"untitled\" false;\n\n/* make an option widget\n */\nNew_option = Option \"untitled\" [\"option0\", \"option1\"] 0;\n\n/* make a string entry widget\n */\nNew_string = String \"Enter a string\" \"sample text\";\n\n/* make a number entry widget\n */\nNew_number = Number \"Enter a number\" 42;\n\n/* make a file chooser\n */\nNew_filename = Filename \"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n\n/* make a matrix\n */\nNew_matrix = class {\n\t/* make a plain matrix\n\t */\n\tPlain = Matrix (identity_matrix 3);\n\n\t/* make a convolution matrix\n\t */\n\tConvolution = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\n\t/* make a recombination matrix\n\t */\n\tRecombination = Matrix_rec (identity_matrix 3);\n\n\t/* make a morphology matrix\n\t */\n\tMorphology = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n}\n\n/* make a mark on an image\n */\nNew_mark = class {\n\t/* mark a region on an image\n\t */\n\tRegion image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\n\t/* mark a point on an image\n\t */\n\tPoint image = scope.Point_relative image 0.5 0.5;\n\n\t/* mark an arrow on an image\n\t */\n\tArrow image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\n\t/* mark a horizontal guide on an image\n\t */\n\tHGuide image = scope.HGuide_relative image 0.5;\n\n\t/* mark a vertical guide on an image\n\t */\n\tVGuide image = scope.VGuide_relative image 0.5;\n}\n\n#separator\n\n/* make a spatial response pattern image\n */\nNew_eye = class\n\tImage value {\n\twidth = 64;\n\theight = 64;\n\tfactor = Slider 0.001 1 0.2;\n\n\tvalue = im_eye width height factor.value;\n}\n\n/* make a zone plate image\n */\nNew_zone_plate = class\n\tImage value {\n\tsize = 64;\n\n\tvalue = im_zone size;\n}\n\n/* make a grey ramp image\n */\nNew_grey = class\n\tImage value {\n\twidth = 64;\n\theight = 64;\n\torientation = Option \"\" [\"Horizontal\", \"Vertical\"] 0;\n\n\tvalue = [im_grey width height, \n\t\tim_rot90 (im_grey height width)]?orientation;\n}\n\n/* make a two band image whose pixel values are their coordinates\n */\nNew_xy = class\n\tImage value {\n\twidth = 64;\n\theight = 64;\n\n\tvalue = make_xy width height; \n}\n\n/* make a new image of gaussian noise\n */\nNew_gauss_noise = class\n\tImage value {\n\tsize = 64;\n\tmean = Slider 0 255 128;\n\tdeviation = Slider 0 128 50;\n\n\tvalue = im_gaussnoise size size mean.value deviation.value;\n}\n\n/* make a 2d fractal image\n */\nNew_fractal = class\n\tImage value {\n\tsize = 64;\n\tdimension = Slider 2.001 2.999 2.001;\n\n\tvalue = im_fractsurf size dimension.value; \n}\n\n/* make a CRT calibration chart\n */\nNew_CRT_test_chart = class\n\tImage value {\n\tbrightness = Slider 0 255 200;\n\tpatch_size = 32;\n\n\tvalue \n\t\t= imagearray_assemble 0 0 [[green, red], [blue, white]]\n\t{\n\n\t\tblack = image_new patch_size patch_size 1\n\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\tImage_type.B_W 0 0 0;\n\t\tnotblack = black + brightness;\n\n\t\tgreen = black ++ notblack ++ black;\n\t\tred = notblack ++ black ++ black;\n\t\tblue = black ++ black ++ notblack;\n\t\twhite = notblack ++ notblack ++ notblack;\n\t}\n}\n\n/* make a frequency test chart\n */\nNew_frequency_test_chart = class\n\tImage value {\n\twidth = 64;\n\tstrip_height = 10;\n\twavelengths = [64, 32, 16, 8, 4, 2];\n\n\tvalue \n\t\t= join.value\n\t{\n\t\tfreq_slice wave \n\t\t\t= Image (sin ((im_fgrey width strip_height) * 360 * \n\t\t\t\twidth / wave) > 0);\n\t\tstrips = map freq_slice wavelengths;\n\t\tjoin = foldl1 Join.Top_bottom strips;\n\t}\n}\n\n/* make a checkerboard pattern\n */\nNew_checkerboard = class\n\tImage value {\n\twidth = 64;\n\theight = 64;\n\thorizontal_patch_size = 8;\n\tvertical_patch_size = 8;\n\thorizontal_patch_offset = 0;\n\tvertical_patch_offset = 0;\n\n\tvalue\n\t\t= xstripes ^ ystripes\n\t{\n\t\tpixels = make_xy width height;\n\t\txpixels = pixels?0 + horizontal_patch_offset;\n\t\typixels = pixels?1 + vertical_patch_offset;\n\n\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\txstripes = make_stripe xpixels horizontal_patch_size;\n\t\tystripes = make_stripe ypixels vertical_patch_size;\n\t}\n}\n\n/* make a grid pattern\n */\nNew_grid = class\n\tImage value {\n\twidth = 64;\n\theight = 64;\n\thorizontal_line_spacing = 8;\n\tvertical_line_spacing = 8;\n\tline_thickness = 1;\n\thorizontal_grid_offset = 0;\n\tvertical_grid_offset = 0;\n\n\tvalue\n\t\t= xstripes | ystripes\n\t{\n\t\tpixels = make_xy width height;\n\t\txpixels = pixels?0 + horizontal_grid_offset;\n\t\typixels = pixels?1 + vertical_grid_offset;\n\n\t\tmake_stripe pix swidth = pix % swidth < line_thickness;\n\n\t\txstripes = make_stripe xpixels horizontal_line_spacing;\n\t\tystripes = make_stripe ypixels vertical_line_spacing;\n\t}\n}\n\n#separator\n\n/* make a gaussian matrix\n */\nNew_gauss_matrix = class\n\tMatrix_vips _mask.value \n\t\t_mask.scale _mask.offset _mask.filename _mask.display {\n\tsigma = Slider 0.001 10 1;\n\tmin_amplitude = Slider 0 1 0.2;\n\tinteger = Toggle \"Integer\" false;\n\t_mask \n\t\t= fn sigma.value min_amplitude.value\n\t{\n\t\tfn\n\t\t\t= im_gauss_imask, integer\n\t\t\t= im_gauss_dmask;\n\t}\n}\n\n/* make a laplacian of a gaussian mask\n */\nNew_log_matrix = class\n\tMatrix_vips _mask.value \n\t\t_mask.scale _mask.offset _mask.filename _mask.display {\n\tsigma = Slider 0.001 10 1.5;\n\tmin_amplitude = Slider 0 1 0.1;\n\tinteger = Toggle \"Integer\" false;\n\t_mask \n\t\t= fn sigma.value min_amplitude.value\n\t{\n\t\tfn\n\t\t\t= im_log_imask, integer\n\t\t\t= im_log_dmask;\n\t}\n}\n\n#separator\n\n/* make the mask images for various ideal fourier filters\n */\nNew_ideal = class {\n\t/* make a mask image for an ideal highpass/lowpass fourier filter\n\t */\n\tHigh_low = class \n\t\tImage value {\n\t\tsize = 64;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"High or low\" [\"High pass\", \"Low pass\"] 0;\n\n\t\t_type = type.value;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\tfrequency_cutoff.value 0 0 0 0;\n\t\t}\n\t}\n\n\t/* make a mask image for an ideal ring pass/reject fourier filter\n\t */\n\tRing = class \n\t\tImage value {\n\t\tsize = 64;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tring_width = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Ring pass\", \"Ring reject\"] 0;\n\n\t\t_type = type.value + 6;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\tfrequency_cutoff.value ring_width.value 0 0 0;\n\t\t}\n\t}\n\n\t/* make a mask image for an ideal band pass/reject fourier filter\n\t */\n\tBand = class \n\t\tImage value {\n\t\tsize = 64;\n\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\tradius = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Band pass\", \"Band reject\"] 0;\n\n\t\t_type = type.value + 12;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\tfrequency_cutoff_x.value\n\t\t\t\tfrequency_cutoff_y.value\n\t\t\t\tradius.value 0 0;\n\t\t}\n\t}\n}\n\n/* various Gaussian fourier filters\n */\nNew_gaussian = class {\n\t/* make a mask image for a gaussian highpass/lowpass fourier filter\n\t */\n\tHigh_low = class \n\t\tImage value {\n\t\tsize = 64;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"High or low\" [\"High pass\", \"Low pass\"] 0;\n\n\t\t_type = type.value + 4;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\tfrequency_cutoff.value \n\t\t\t\tamplitude_cutoff.value 0 0 0;\n\t\t}\n\t}\n\n\t/* make a mask image for a gaussian ring pass/reject fourier filter\n\t */\n\tRing = class \n\t\tImage value {\n\t\tsize = 64;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tring_width = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Ring pass\", \"Ring reject\"] 0;\n\n\t\t_type = type.value + 10;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\tfrequency_cutoff.value\n\t\t\t\tring_width.value amplitude_cutoff.value 0 0;\n\t\t}\n\t}\n\n\t/* make a mask image for a gaussian band pass/reject fourier filter\n\t */\n\tBand = class \n\t\tImage value {\n\t\tsize = 64;\n\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\tradius = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Band pass\", \"Band reject\"] 0;\n\n\t\t_type = type.value + 16;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\tfrequency_cutoff_x.value\n\t\t\t\tfrequency_cutoff_y.value\n\t\t\t\tradius.value amplitude_cutoff.value 0;\n\t\t}\n\t}\n}\n\n/* various Butterworth fourier filters\n */\nNew_butterworth = class {\n\t/* make a mask image for a Butterworth highpass/lowpass fourier filter\n\t */\n\tHigh_low = class \n\t\tImage value {\n\t\tsize = 64;\n\t\torder = Slider 1 10 2;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"High or low\" [\"High pass\", \"Low pass\"] 0;\n\n\t\t_type = type.value + 2;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\torder.value frequency_cutoff.value\n\t\t\t\tamplitude_cutoff.value 0 0;\n\t\t}\n\t}\n\n\t/* make a mask image for a Butterworth ring pass/reject fourier filter\n\t */\n\tRing = class \n\t\tImage value {\n\t\tsize = 64;\n\t\torder = Slider 1 10 2;\n\t\tfrequency_cutoff = Slider 0.01 0.99 0.5;\n\t\tring_width = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Ring pass\", \"Ring reject\"] 0;\n\n\t\t_type = type.value + 8;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\torder.value frequency_cutoff.value\n\t\t\t\tring_width.value amplitude_cutoff.value 0;\n\t\t}\n\t}\n\n\t/* make a mask image for a Butterworth band pass/reject fourier filter\n\t */\n\tBand = class \n\t\tImage value {\n\t\tsize = 64;\n\t\torder = Slider 1 10 2;\n\t\tfrequency_cutoff_x = Slider 0.01 0.99 0.5;\n\t\tfrequency_cutoff_y = Slider 0.01 0.99 0.5;\n\t\tradius = Slider 0.01 0.99 0.5;\n\t\tamplitude_cutoff = Slider 0.01 0.99 0.5;\n\t\ttype = Option \"Pass or reject\" [\"Band pass\", \"Band reject\"] 0;\n\n\t\t_type = type.value + 14;\n\n\t\tvalue\n\t\t\t= image_set_type Image_type.FOURIER (rotquad mask)\n\t\t{\n\t\t\tmask = im_create_fmask \n\t\t\t\tsize size _type\n\t\t\t\torder.value frequency_cutoff_x.value\n\t\t\t\tfrequency_cutoff_y.value\n\t\t\t\tradius.value amplitude_cutoff.value;\n\t\t}\n\t}\n}\n\n#separator\n\n/* make a slice through CIELAB space\n */\nNew_CIELAB_slice = class\n\tImage value {\n\tsize = 64;\n\tL = Slider 0 100 50;\n\tvalue = lab_slice size L.value;\n}\n\n/* pick a colour in LAB space\n */\nNew_LAB_colour\n\t= widget \"Lab\" [50, 0, 0]\n{\n\t// ab_slice size\n\tsize = 512;\n\n\t// range of values ... +/- 128 for ab\n\trange = 256;\n\n\t// map xy in slice image to ab and back\n\txy2ab x = x / (size / range);\n\tab2xy a = (a * (size / range));\n\n\twidget space default_value = class\n\t\tColour space value {\n\t\tL = default_value?0;\n\t\ta = default_value?1;\n\t\tb = default_value?2;\n\t\tlightness = Slider 0 100 L;\n\t\tab_slice = Image (lab_slice size lightness.value);\n\t\tpoint = Point ab_slice (ab2xy a) (ab2xy b);\n\t\tvalue = [lightness.value, xy2ab point.left, xy2ab point.top];\n\t\tColour_edit colour_space value = widget colour_space value;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.9/Print.def",
    "content": "/* cored sharpen of L only in LAB image ... tuned for typical printers\n */\nSharpen_for_print in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\"300 dpi\",\n\t\t\t\"150 dpi\",\n\t\t\t\"75 dpi\"\n\t\t] 0;\n\n\t\t// sharpen params for 300, 150 and 75 dpi\n\t\t// just change the size of the area we search\n\t\t_param_table = [\n\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t[3, 2.5, 40, 20, 0.5, 1.5]\n\t\t];\n\t\t_params = _param_table?target_dpi;\n\n\t\tvalue = im_sharpen \n\t\t\t(colour_transform_to Image_type.LABQ in.value)\n\t\t\t_params?0 _params?1 _params?2 _params?3 _params?4\n\t\t\t_params?5;\n\t}\n}\n\n/* adjust tone curve on L*\n */\nTone_for_print in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tblack = Slider 0 100 0;\n\t\twhite = Slider 0 100 100;\n\n\t\tshadow_point = Slider 0.1 0.3 0.2;\n\t\tmid_point = Slider 0.4 0.6 0.5;\n\t\thighlight_point = Slider 0.7 0.9 0.8;\n\n\t\tshadow_adjust = Slider (-15) 15 0;\n\t\tmid_adjust = Slider (-30) 30 0;\n\t\thighlight_adjust = Slider (-15) 15 0;\n\n\t\tpreview_curve = Image (im_tone_build \n\t\t\tblack.value white.value\n\t\t\tshadow_point.value mid_point.value highlight_point.value\n\t\t\tshadow_adjust.value mid_adjust.value\n\t\t\thighlight_adjust.value);\n\n\t\tvalue = im_tone_map \n\t\t\t(colour_transform_to Image_type.LABQ in.value) \n\t\t\tpreview_curve.value;\n\t}\n}\n\n/* morph image colours in LAB space ... useful for tweaking colour for print\n */\nMorph_for_print in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tL_scale = 1.15;\n\t\tL_offset = -4.2;\n\t\tab_scale = Slider 1 1.5 1.15;\n\t\ta_offset = Slider (-10) 10 0;\n\t\tb_offset = Slider (-10) 10 5;\n\t\tgrey_correction = Matrix_con 1 0 [\n\t\t\t[5, 5, -1 ],\n\t\t\t[10, 4, -1 ],\n\t\t\t[15, 2, -1 ],\n\t\t\t[20, 1, 1 ],\n\t\t\t[25, 1, 2 ],\n\t\t\t[30, 0, 1 ],\n\t\t\t[35, 0, 1 ],\n\t\t\t[40, 0, 1 ],\n\t\t\t[45, 0, 1 ],\n\t\t\t[50, 0, 1 ],\n\t\t\t[55, 0, 0 ],\n\t\t\t[99, 0, 0 ]\n\t\t];\n\n\t\tvalue = im_lab_morph in.value \n\t\t\t(Vector [0, a_offset.value, b_offset.value] +\n\t\t\t\tgrey_correction)\n\t\t\tL_offset L_scale ab_scale.value ab_scale.value;\n\t}\n}\n\n#separator\n\n_sample_print_profile = \n\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n_sample_monitor_profile = \n\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n_render_intents = Option \"Render intent\" [\n\t\"Perceptual\",\n\t\"Relative\",\n\t\"Saturation\",\n\t\"Absolute\"\n] 3;\n\n/* transform from PCS to device space\n */\nICC_export in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tprofile = Filename _sample_print_profile;\n\t\tintent = _render_intents;\n\t\tdepth = Option \"Output depth\" [\"8 bit\", \"16 bit\"] 0;\n\n\t\tvalue = im_icc_export_depth in.value [8, 16]?depth\n\t\t\t(expand profile.value) intent.value;\n\t}\n}\n\n/* transform from device space to PCS\n */\nICC_import in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_check_all = [\n\t\t\t[in.bands == 3 || in.bands == 4, \n\t\t\t\t\"in.bands == 3 || in.bands == 4\" ]\n\t\t] ++ super._check_all;\n\t\t_vislevel = 3;\n\n\t\tprofile \n\t\t\t= Filename _sample_monitor_profile, in.bands == 3\n\t\t\t= Filename _sample_print_profile;\n\t\tintent = _render_intents;\n\n\t\tvalue = im_icc_import in.value \n\t\t\t(expand profile.value) intent.value;\n\t}\n}\n\n/* transform between two device spaces\n */\nICC_transform in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tin_profile = Filename _sample_monitor_profile;\n\t\tout_profile = Filename _sample_print_profile;\n\t\tintent = _render_intents;\n\n\t\tvalue = im_icc_transform in.value \n\t\t\t(expand in_profile.value) \n\t\t\t(expand out_profile.value) intent.value;\n\t}\n}\n\n/* transform from absolute to relative colorimetry\n */\nICC_ac2rc in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tprofile = Filename _sample_print_profile;\n\n\t\tvalue = im_icc_ac2rc in.value (expand profile.value);\n\t}\n}\n\n#separator\n\n/* convert between XYZ and Lab for D50\n */\nD50XYZ_to_D50Lab in = map_unary (colour_unary im_D50XYZ2Lab) in;\n\n/* convert between XYZ and Lab for D50\n */\nD50Lab_to_D50XYZ in = map_unary (colour_unary im_D50Lab2XYZ) in;\n\n#separator\n\n/* add an editable drop shadow to an image \n */\nDrop_shadow x\n\t= map_unary shadow x\n{\n\tshadow image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tshadow_width = Slider 0 50 5;\n\t\tshadow_height = Slider 0 50 5;\n\t\tshadow_softness = Slider 0 20 5;\n\t\tuse_mask = Toggle \"Use mask to make shadow\" false;\n\t\tmask_image = foldr1 bitwise_and (bandsplit (image > 128));\n\t\tbackground_colour = 255;\n\t\tshadow_colour = 128;\n\n\t\tvalue \n\t\t\t = final\n\t\t{\n\t\t\tblur_size = shadow_softness.value * 2 + 1;\n\n\t\t\t// matrix we blur with to soften shadows\n\t\t\tmask_g = im_gauss_imask (blur_size / 3) 0.2;\n\t\t\tmask_g_line = mask_g.value ? (mask_g.height / 2);\n\t\t\tmask_g_sum = foldr1 add mask_g_line;\n\t\t\tblur_matrix = Matrix_con mask_g_sum 0 [mask_g_line];\n\t\t\tmask_size = mask_g.width;\n\n\t\t\t// size of final image we build\n\t\t\tfinal_width = image.width + 2 * mask_size + \n\t\t\t\tshadow_width.value;\n\t\t\tfinal_height = image.height + 2 * mask_size + \n\t\t\t\tshadow_height.value;\n\n\t\t\t// make a plain image \n\t\t\tmk_background colour = image_new \n\t\t\t\tfinal_width final_height\n\t\t\t\timage.bands image.format \n\t\t\t\tImage_coding.NOCODING image.type\n\t\t\t\tcolour\n\t\t\t\t0 0;\n\n\t\t\t// make a mask image ... place at (x,y) in the final\n\t\t\t// image\n\t\t\tmk_mask x y \n\t\t\t\t= im_insert black mask_image.value x y,\n\t\t\t\t\tuse_mask\n\t\t\t\t= im_insert black white x y\n\t\t\t{\n\t\t\t\tblack = image_new \n\t\t\t\t\tfinal_width final_height\n\t\t\t\t\t1 Image_format.UCHAR\n\t\t\t\t\tImage_coding.NOCODING Image_type.B_W\n\t\t\t\t\t0\n\t\t\t\t\t0 0;\n\t\t\t\twhite = image_new \n\t\t\t\t\timage.width image.height\n\t\t\t\t\t1 Image_format.UCHAR\n\t\t\t\t\tImage_coding.NOCODING Image_type.B_W\n\t\t\t\t\t255\n\t\t\t\t\t0 0;\n\t\t\t}\n\n\t\t\t// make the shadow mask image ... offset mask and\n\t\t\t// soften\n\t\t\tshadow_mask = mk_mask  \n\t\t\t\t(mask_size + shadow_width.value)\n\t\t\t\t(mask_size + shadow_height.value);\n\t\t\tshadow_mask' = im_convsep shadow_mask blur_matrix;\n\n\t\t\t// make underlay ... use shadow mask to blend between\n\t\t\t// background colour and shadow colour\n\t\t\tbackground = mk_background background_colour;\n\t\t\tshadow = mk_background shadow_colour;\n\t\t\tunderlay = im_blend shadow_mask' shadow background;\n\n\t\t\t// overlay ... place image at final position\n\t\t\toverlay = mk_background 0;\n\t\t\toverlay' = im_insert overlay image.value\n\t\t\t\tmask_size mask_size;\n\n\t\t\t// overlay mask\n\t\t\toverlay_mask = mk_mask mask_size mask_size;\n\n\t\t\tfinal = if overlay_mask then overlay' else underlay;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.9/Resize.def",
    "content": "_resize_interp = Option \"Interpolation\" \n\t(map (extract 0) Interpolate.names.value)\n\tInterpolate.bilinear;\n\n/* resize image x by any scale factor\n */\nResize_image x\n\t= map_unary widget x\n{\n\twidget image = class\n\t\tImage value {\n\t\t_vislevel = 3;\n\t\tfactor = 1;\n\t\tinterp = _resize_interp;\n\t\tvalue = resize factor factor interp.value image.value;\n\t}\n}\n\n/* resize image with separate x/y factors\n */\nResize_xy_image x\n\t= map_unary widget x\n{\n\twidget image = class\n\t\tImage value {\n\t\t_vislevel = 3;\n\t\txfactor = 1;\n\t\tyfactor = 1;\n\t\tinterp = _resize_interp;\n\t\tvalue = resize xfactor yfactor interp.value image.value;\n\t}\n}\n\n/* place image x in a larger piece of image\n */\nResize_canvas x\n\t= map_unary widget x\n{\n\twidget image = class\n\t\tImage value {\n\t\t_vislevel = 3;\n\t\tnew_image_width = image.width;\n\t\tnew_image_height = image.height;\n\t\tposition = Option \"Position\" [\n\t\t\t\"North-west\",\n\t\t\t\"North\",\n\t\t\t\"North-east\",\n\t\t\t\"West\",\n\t\t\t\"Centre\",\n\t\t\t\"East\",\n\t\t\t\"South-west\",\n\t\t\t\"South\",\n\t\t\t\"South-east\"\n\t\t] 4;\n\t\tfill = Option \"Fill background with\" [\n\t\t\t\"White\",\n\t\t\t\"Black\"\n\t\t] 0;\n\n\t\tvalue \n\t\t\t= im_insert_noexpand background image.value xp yp\n\t\t{\n\t\t\twidth = image.width;\n\t\t\theight = image.height;\n\t\t\tcoding = image.coding;\n\t\t\tbands \n\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t= image.bands;\n\t\t\tformat \n\t\t\t\t= Image_format.FLOAT, \n\t\t\t\t\tcoding == Image_coding.LABPACK\n\t\t\t\t= image.format;\n\t\t\ttype = image.type;\n\n\t\t\tbackground_colour \n\t\t\t\t= image_white image, fill == 0\n\t\t\t\t= Vector (map (const 0) [1 .. bands]);\n\n\t\t\t// placement vectors ... left, centre, right\n\t\t\txposv = [0, new_image_width / 2 - width / 2, \n\t\t\t\tnew_image_width - width];\n\t\t\typosv = [0, new_image_height / 2 - height / 2, \n\t\t\t\tnew_image_height - height];\n\n\t\t\txp = xposv?((int) (position % 3));\n\t\t\typ = yposv?((int) (position / 3));\n\n\t\t\tbackground = image_new new_image_width new_image_height\n\t\t\t\tbands format coding type background_colour 0 0;\n\t\t}\n\t}\n}\n\n#separator\n\n/* resize image x so that the shortest axis is a certain size\n */\nShrink_to = class {\n\t_shrink_width default_size image = class\n\t\tImage value {\n\t\tsize = default_size;\n\t\tinterp = _resize_interp;\n\t\tvalue \t\n\t\t\t= resize factor factor interp.value image.value\n\t\t{\n\t\t\txfac = size / image.width;\n\t\t\tyfac = size / image.height;\n\t\t\tfactor = max_pair xfac yfac;\n\t\t}\n\t}\n\n\t/* shrink minimum dimension to 400 pixels \n\t */\n\tQuicklook x = map_unary (_shrink_width 400) x;\n\n\t/* shrink minimum dimension to 64 pixels \n\t */\n\tIcon x = map_unary (_shrink_width 64) x;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.9/Rotate.def",
    "content": "/* rotate images and matricies by fixed angles\n */\nRotate_fixed = class {\n        /* rotate image clockwise in 90 degree increments\n         */\n        _rotate_widget default a\n                = map_unary widget a\n        {\n                widget image = class\n                        Image value {\n                        _check_args = [\n                                [image, \"image\", check_Image]\n                        ] ++ super._check_args;\n                        _vislevel = 3;\n\n                        angle = Option \"Rotate by\" [\n                                \"Don't rotate\", \n                                \"90 degrees clockwise\",\n                                \"180 degrees\",\n                                \"90 degrees anticlockwise\"\n                        ] default;\n\n                        value = [\n                                image.value, \n                                rot90 image.value,\n                                rot180 image.value,\n                                rot270 image.value\n                        ] ? angle;\n                }\n        }\n\n        /* clockwise rotate by 90 degrees\n         */\n        R90 x = _rotate_widget 1 x;\n\n        /* rotate by 180 degrees\n         */\n        R180 x = _rotate_widget 2 x;\n\n        /* clockwise rotate by 270 degrees\n         */\n        R270 x = _rotate_widget 3 x;\n\n        /* rotate by 45 degrees ... square, odd-length-sides, matrices only\n         */\n        R45 x = map_unary rot45 x;\n}\n\n/* rotate image anticlockwise by any angle\n */\nRotate_free a\n\t= map_unary widget a\n{\n\twidget image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t] ++ super._check_args;\n\t\t_vislevel = 3;\n\n\t\tangle = Slider 0 360 0;\n\n\t\tvalue = rotate angle image.value;\n\t}\n}\n\n#separator\n\n/* mirror left/right or up/down\n */\nFlip = class {\n\t/* mirror object up/down\n\t */\n\tUp_down x = map_unary flipud x;\n\n\t/* mirror object left/right\n\t */\n\tLeft_right x = map_unary fliplr x;\n}\n\n/* swap rows and columns\n */\nTranspose x = map_unary transpose x;\n\n#separator\n\n/* smallest rotate that gets arrow vertical or horizontal\n */\nStraighten_arrow x\n\t= map_unary straighten x\n{\n\tstraighten arrow\n\t\t= rotate angle'' arrow.image\n\t{\n\t\tx = arrow.width;\n\t\ty = arrow.height;\n\n\t\tangle = im (polar (x, y));\n\n\t\tangle'\n\t\t\t= angle - 360, angle > 315\n\t\t\t= angle - 180, angle > 135\n\t\t\t= angle;\n\n\t\tangle''\n\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t= 90 - angle';\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/7.9/Statistics.def",
    "content": "/* mean value of object\n */\nMean a = map_unary mean a;\n\n/* standard deviation of object\n */\nDeviation a = map_unary deviation a;\n\n/* calculate a large set of stats on an object\n */ \nStats a = map_unary stats a;\n\n#separator\n\n/* maximum of an object\n */\nMax a = map_unary max a;\n\n/* minimum of an object\n */\nMin a = map_unary min a;\n\n/* return complex number (max, min)\n */\nMaxmin a \n\t= map_unary maxmin a\n{\n\tmaxmin x = (Max x, Min x);\n}\n\n/* position of maximum in an image\n */ \nMaximum_position a = map_unary maxpos a;\n\n/* position of minimum in an image \n */ \nMinimum_position a = map_unary minpos a;\n\n#separator\n\n/* count the number of non-zeros in an image \n */\nCount_set a\n\t= map_unary cset a\n{\n\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n}\n\n/* count the number of zeros in an image \n */\nCount_clear a\n\t= map_unary cclear a\n{\n\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n}\n\n#separator\n\n/* plot a scatter graph of a list of [x,y] coordinates\n */\nPlot_scatter x \n\t//= map_unary widget x\n\t= widget x\n{\t\n\twidget data\n\t\t= class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[data, \"data\", check_xy_list]\n\t\t] ++ super._check_args;\n\n\t\twidth = 512;\n\t\theight = 512;\n\t\tplot_colour = Colour \"Lab\" [80, -80, 80];\n\t\txmin = foldr1 min_pair (map (extract 0) data);\n\t\txmax = foldr1 max_pair (map (extract 0) data);\n\t\tymin = foldr1 min_pair (map (extract 1) data);\n\t\tymax = foldr1 max_pair (map (extract 1) data);\n\t\taxies = Toggle \"Draw axies\" true;\n\t\tmark \n\t\t\t= Point this x y\n\t\t{\n\t\t\tp = _to_image data?0;\n\t\t\tx = p?0;\n\t\t\ty = p?1;\n\t\t}\n\t\tmark_position_hint = \"mark is at position:\";\n\t\tmark_position = _from_image [mark.left, mark.top];\n\n\t\t// geometry\n\t\t_xrange = xmax - xmin;\n\t\t_yrange = ymax - ymin;\n\t\t_xscale = width / _xrange;\n\t\t_yscale = height / _yrange;\n\n\t\t// map an [x,y] point into the image coordinates\n\t\t_to_image p = [(p?0 - xmin) * _xscale, \n\t\t\theight - (p?1 - ymin) * _yscale];\n\n\t\t// map an [x,y] point from image cods back to real cods\n\t\t_from_image p = [p?0 / _xscale + xmin, \n\t\t\t(height - p?1) / _yscale + ymin];\n\n\t\tvalue\n\t\t\t= foldr plot background' data\n\t\t{\n\t\t\tplot_image_new width height pixel\n\t\t\t\t= image_new width height 3\n\t\t\t\t\tImage_format.FLOAT \n\t\t\t\t\tImage_coding.NOCODING\n\t\t\t\t\t(Image_type.colour_spaces.lookup \n\t\t\t\t\t\t0 1 plot_colour.colour_space)\n\t\t\t\t\tpixel 0 0;\n\n\t\t\t// background\n\t\t\tbackground = plot_image_new width height 0;\n\n\t\t\t// mark we plot\n\t\t\tmark_width = max_pair 1 (width / 100);\n\t\t\tmark_height = max_pair 1 (height / 100);\n\t\t\tmark = plot_image_new mark_width mark_height \n\t\t\t\t\tplot_colour;\n\n\t\t\t// draw axies on background \n\t\t\tbackground' \n\t\t\t\t= drawxy, axies\n\t\t\t\t= background\n\t\t\t{\n\t\t\t\t// axies\n\t\t\t\txaxis = plot_image_new width 1 \n\t\t\t\t\t(Colour \"Lab\" [100, 0, 0]); \n\t\t\t\tyaxis = plot_image_new 1 height \n\t\t\t\t\t(Colour \"Lab\" [100, 0, 0]);\n\t\t\t\torigin = _to_image [0, 0];\n\n\t\t\t\tdrawx = im_insert_noexpand \n\t\t\t\t\tbackground xaxis 0 origin?1;\n\t\t\t\tdrawxy = im_insert_noexpand \n\t\t\t\t\tdrawx yaxis origin?0 0;\n\t\t\t}\n\n\t\t\t// plot a single point on an image\n\t\t\tplot p im \n\t\t\t\t= im_insert_noexpand im mark \n\t\t\t\t\t(x - mark_width / 2) \n\t\t\t\t\t(y - mark_height / 2)\n\t\t\t{\n\t\t\t\tp' = _to_image p;\n\t\t\t\tx = p'?0;\n\t\t\t\ty = p'?1;\n\t\t\t}\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/7.9/X_ray.def",
    "content": "/* replace dark or light section of im1 with section from im2\n */\nReplace_area im1 im2 = class \n\tImage value \n{\n\t_check_args = [\n\t\t[im1, \"im1\", check_Image],\n\t\t[im2, \"im2\", check_Image]\n\t] ++ super._check_args;\n\t\n\t_vislevel = 3;\n\n\t/* Region on first image placed in the top left hand corner,\n\t * positioned and size relative to the height and width of im1.\n\t */\n\tr1 = Region_relative im1 0.1 0.1 0.1 0.1;\n\n\t/* Point on second image placed in the top left hand corner,\n\t * positioned relative to the height and width of im2. Used to\n\t * define _r2, the region from which the section of image is cloned \n\t * from.\n\t */\n\n\tp2 = Point im2 \n\t\t\t(im2.width * 0.1 - im2.xoffset)\n\t\t\t(im2.height * 0.1 - im2.yoffset);\n\n\t_r2 = Region im2 \n\t\tp2.left\n\t\tp2.top\n\t\tr1.width\n\t\tr1.height;\n\n\t_mask = [r1 <= Options.scale_cutoff, r1 >= Options.scale_cutoff] ? Options.control;\n\tmask = _mask?0;\n\n\tOptions = option_1, format  < 4\n\t\t\t= option_2\n\t\t{\n\t\tformat = im1.format;\n\t\t\n\t\toption_1 = class\n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\t/* Option toggle used to define whether the user is replacing a\n\t \t\t * dark or a light area.\n\t \t\t */\n\t\t\tcontrol = Option \"Removing a\" [\n\t\t\t\t\t\t\t \"Dark Area\",\n\t\t\t\t\t\t\t \"Light Area\"\n\t\t\t\t\t\t\t ] 1;\n\t\t\t\t\n\t\t\t/* Used to select the area to be replaced.\n\t\t\t */\t\t\t \n\t\t\tscale_cutoff = Slider 0.01 mx (mx / 2)\n\t\t\t\t{\n\t\t\t\tmx = Image_format.maxval im1.format;\n\t\t\t\t}\n\t\t\t\n\t\t\t/* Option toggle how the levels in the replacment area are calculated.\n\t \t\t * Replacement with gaussian noise uses the scale&offset balancing.\n\t \t\t */\t\t\t\t\t\t\t \n\t\t\tprocess = Option \"Use\" [\n\t\t\t\t\t\t\t \"Scale&Offset Balancing\",\n\t\t\t\t\t\t\t \"Gaussian noise replacement\",\n\t\t\t\t\t\t\t \"Histogram Balancing\"\n\t\t\t\t\t\t\t ] 0;\n\t\t\t\t\t\t\t \n\t\t\t/* This allows the function to be paused. \n\t\t\t */\t\t\t\t \n\t\t\tpause = Toggle \"Pause function to allow easy adjustment of region r1.\" true;\n\t\t\t}\n\t\toption_2 = class\n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\t/* Option toggle used to define whether the user is replacing a\n\t \t\t * dark or a light area.\n\t \t\t */\n\t\t\tcontrol = Option \"Removing a\" [\n\t\t\t\t\t\t\t \"Dark Area\",\n\t\t\t\t\t\t\t \"Light Area\"\n\t\t\t\t\t\t\t ] 1;\n\t\t\t\t\n\t\t\t/* Used to select the area to be replaced.\n\t\t\t */\t\t\t \n\t\t\tscale_cutoff = Slider 0.01 mx (mx / 2)\n\t\t\t\t{\n\t\t\t\t/* the below function can not cope with floats \n\t\t\t\t * and don't need massive range for 32-bit ints so \n\t\t\t\t * will just define the max as for a 16 bit unsigned.\n\t\t\t\t */\t\t\n\t\t\t\t mx = Image_format.maxval 2; //im1.format;\n\t\t\t\t}\n\t\t\t\n\t\t\t/* Option toggle how the levels in the replacment area are calculated.\n\t \t\t * Replacement with gaussian noise uses the scale&offset balancing.\n\t \t\t */\t\t\t\t\t\t\t \n\t\t\tprocess = Option \"Use\" [\n\t\t\t\t\t\t\t \"Scale&Offset Balancing\",\n\t\t\t\t\t\t\t \"Gaussian noise replacement\"\n\t\t\t\t\t\t\t ] 0;\n\t\t\t\t\t\t\t \n\t\t\t/* This allows the function to be paused. \n\t\t\t */\t\t\t\t \n\t\t\tpause = Toggle \"Pause function to allow easy adjustment of region r1.\" true;\n\t\t\t}\n\t\t}\n\t\t\n\tvalue \n\t\t= im1.value, Options.pause \n\t\t= im_insert im1.value patch r1.left r1.top \n\t{\n\t\tpatch = _so_balance mask r1.value _r2.value false, Options.process == 0;\n\t\t\t  = _so_balance mask r1.value _r2.value true, Options.process == 1;\n\t\t\t  = _hist_balance_2 mask r1.value _r2.value;\n\t}\n};\n\n#separator\n\n/* Balance the effect of secondary structure on an X-ray image\n * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference \n * masks, where the masks are white on a black background.  Then simplifys \n * the original X-ray to reduce  interference from stretchers cradles etc.\n */\n\nBalance_areas im_in m_control m_list = class\n\tImage value \n\t{\n\t_vislevel = 3;\n\t\n\t_format = im_in.format;\n\t\n\tOptions = option_1, format  < 4\n\t\t\t= option_2\n\t\t{\n\t\tformat = im_in.format;\n\t\t\n\t\toption_1 = class\n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\tpause = Toggle \"Pause Process.\" true;\n\t\t\tblur = Slider 0 5 0;\n\t\t\t_blur = rint blur.value;\n\t\t\toption = Toggle \"Use Scale&Offset Balancing rather than Histogram.\" true;\n\t\t\t_option = option;\n\t\t\t}\n\n\t\toption_2 = class\n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\tpause = Toggle \"Pause Process.\" true;\n\t\t\tblur = Slider 0 5 0;\n\t\t\t_blur = rint blur.value;\n\t\t\t_option = true;\n\t\t\t}\n\t\t}\n\n\t_control_im = _section_select2 im_in m_control;\n\t_control_values = _so_values _control_im;\n\n\t/* blur mask over a set number of pixels then histogram match an area\n\t * of the original image defined by m_current to the _control_im\n\t * then blend the matched area back into im_in.\n\t */\n\tprocess m_current im_start \n\t\t= im_out\n\t\t{\n\t\talternative = false;\n\t\tbl_mask    = _mask_blur_2 m_current Options._blur;\n\t\tscaled_im  = _so_convert _control_values im_start m_current, Options._option == true\n\t\t\t\t\t\t= _hist_convert_2 _control_im im_start m_current;\n\t\tfmt_im      = clip2fmt im_start.format scaled_im;\n\t\tblended_im  = im_blend bl_mask scaled_im.value im_start.value;\n\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t}\n\n\tvalue = im_in.value, Options.pause == true\n\t\t  = (foldr process im_in m_list).value;\n};\n\n_so_balance mask im1 im2 gauss \n\t= result\n{\n\t/* Extract the undamaged areas.\n\t */\n\tim1' = if !mask then Image im1 else 0;\n\tim2' = if !mask then Image im2 else 0;\n\n\t/* Find the non_zero means of the undamaged areas.\n\t */\n\tm1 = _mean_fn im1';\n\tm2 = _mean_fn im2';\n\t\n\tim1_mn = im1' - m1;\t\n\tim2_mn = im2' - m2;\n\t\n\tscale = (max im1_mn)/(max im2_mn);\n\t\n\tim2_corrected_a = ((im2 - m2) * scale) + m1;\n\tim2_corrected_b = clip2fmt im1'.format im2_corrected_a;\n\t\n\t/* Option to convert replacement image to scaled gaussian noise\n\t */\t\n\tim2_corrected = im2_corrected_b, gauss == false\n\t\t\t\t   = _gauss_noise im2_corrected_b;\n\n\t/* Blur mask.\n\t */\n\tmask' = _mask_blur_2 mask 5;\n\t//mask' = _feather_mask_2 5 mask.value;\n\n\t/* Blend im2 into im1.\n\t */\n\tresult = im_blend mask' im2_corrected im1;\n};\n\n/* make a new image of gaussian noise\n */\n_gauss_noise im2 = value \n\t{\n\ti = Image (im2);\n\twidth = i.width;\n\theight = i.height;\n\tmean = Mean i;\n\tdeviation = Deviation i;\n\n\tnoise = im_gaussnoise width height mean deviation;\n\tvalue = clip2fmt i.format noise;\n};\n\n/* Dilate and blur a mask by a number of pixels.\n *\n *_feather_mask_2 pixels mask \n *\t= im_convsep (dilate dilate_matrix mask) blur_matrix\n *{\n *\tdilate_matrix = (iterate (dilate _morph_mask8) _morph_mask8) ? pixels;\n *\tblur_matrix = Matrix_con pixels 0 [(map (const 1) [1 .. pixels])];\n *};\n */\n\n/* Mask is 255 to indicate parts of im1 which are damaged: replace these bits\n * with the corresponding parts of im2.\n *\n * Match the histograms of the two images to hide grey-level differences, be\n * careful to only consider undamaged sections.\n *\n * Feather the edges of the blend to hide the join.\n *\n * mask is an Image class. im1, im2 and result are vips images.\n */\n_hist_balance_2 mask im1 im2 \n\t= result\n{\n\tformat = im_header_int \"BandFmt\" im1;\n\tbands = im_header_int \"Bands\" im1;\n\n\t/* checks for 8 or 16 bit signed and converts to unsigned\n\t */\n\tforce_unsigned i \n\t\t= clip2fmt Image_format.UCHAR (i + 128), \n\t\t\tformat == Image_format.CHAR\n\t\t= clip2fmt Image_format.USHORT (i + 32768), \n\t\t\tformat == Image_format.SHORT\n\t\t= i;\n\n\t/* undo any force_unsigned \n\t */\n\tformat_restore i \n\t\t= clip2fmt Image_format.CHAR (i - 128),\n\t\t\tformat == Image_format.CHAR\n\t\t= clip2fmt Image_format.SHORT (i - 32768),\n\t\t\tformat == Image_format.SHORT\n\t\t= i;\n\n\t/* Find histogram and then zap the zero column (0 == background). For\n\t * 16-bit images, the histogram can be smaller than 65535 .... expand\n\t * up to full size.\n\t */\n\tbuild_hist i\n\t\t= im_insert big_black h' 0 0\n\t{\n\t\tmax_value = Image_format.maxval i.format;\n\n\t\th = hist_find i.value;\n\n\t\tblack_1 = image_new 1 1 i.bands \n\t\t\tImage_format.UINT Image_coding.NOCODING i.type 0 0 0;\n\t\tbig_black = image_new max_value 1 i.bands \n\t\t\tImage_format.UINT Image_coding.NOCODING i.type 0 0 0;\n\n\t\th' = im_insert h black_1 0 0;\n\t}\n\n\t/* We can't get hists of signed images :-( go unsigned if we have to.\n\t */\n\tim1' = force_unsigned im1;\n\tim2' = force_unsigned im2;\n\n\t/* Extract the undamaged areas.\n\t */\n\treference = if !mask then Image im1' else 0;\n\tsecondary = if !mask then Image im2' else 0;\n\n\t/* Find the hists of the undamaged areas.\n\t */\n\th1 = build_hist reference;\n\th2 = build_hist secondary;\n\n\t/* Match greylevels of im2 to match im1.\n\t */\n\tim2'' = hist_map (hist_match h1 h2) im2';\n\n\t/* Feather mask.\n\t */\n\tmask' = _mask_blur_2 mask 5;\n\t//mask' = _feather_mask_2 5 mask.value;\n\n\t/* Blend im2 into im1.\n\t */\n\tim1'' = im_blend mask' im2'' im1';\n\n\t/* Undo any signed/unsigned nonsense.\n\t */\n\tresult = format_restore im1'';\n};\n\n// Blurs the edges of an 8 bit mask, over a given number of pixels.\n_mask_blur_2 mask pixel \n\t= value\n{\n\tpixels   = 1, pixel == 0\n\t\t     = pixel;\n\tblack = im_black (mask.width + (2*pixels)) (mask.height + (2*pixels)) 1;\n\tnew_mask = Image (im_insert black mask.value pixels pixels);\n\tblur_matrix = Matrix_con pixels 0 [(map (const 1) [1 .. pixels])];\n\tim_blur = im_convsep new_mask.value blur_matrix;\n\n\tleft = pixels;\n\ttop = pixels;\n\twidth = mask.width;\n\theight = mask.height;\n\n\tvalue = im_extract_area im_blur left top width height;\n};\n\n_so_values im = result\n{\n\tmean_of_im = _mean_fn im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\n\tresult = [mean_of_im, max_of_im];\n};\n\n_so_convert con_values im mask = result\n{\n\tim' = _section_select2 im mask;\n\tim_values = _so_values im';\n\t\n\tmean_of_con = con_values?0; \n\tmean_of_im  = im_values?0;\n\t\n\tmax_of_con = con_values?1; \n\tmax_of_im  = im_values?1;\n\t\n\tscale = (max_of_con)/(max_of_im);\n\t\n\tim_convert = ((im - mean_of_im) * scale) + mean_of_con;\n\tresult = clip2fmt im.format im_convert;\n};\n\n/* Convert the histogram of part of image im_a, depending on the mask im_m,\n * to match the histogram of im_c.\n */\n_hist_convert_2 control_im im adjust_mask\n\t= im_final\n{\n\tmax_value = Image_format.maxval im.format;\n\n\tadjust_im = _section_select2 im adjust_mask;\n\thist_c = hist_fn control_im;\n\thist_a = hist_fn adjust_im;\n\n\t/* Find histogram and then edit out any information related to parts \n\t * of the image with value 0.  Ensure that the histogram represents \n\t * the full scale for the appropriate format. Output corrected \n\t * histograms for the correct parts of the image.\n\t */\n\thist_fn im_in \n\t\t= output\n\t{\n\t\thist_1 = hist_find im_in;\n\t\tblack_1 = clip2fmt hist_1.format (im_black 1 1 1);\n\t\thist_2 = im_insert hist_1.value black_1 0 0;\n\t\tblack_2 = clip2fmt hist_1.format (im_black max_value 1 1);\n\t\toutput = im_insert black_2 hist_2 0 0;\n\t}\n\n\tim_final = hist_map (hist_match hist_a hist_c) im;\n};\n\n//-------------------------------------------------------------------------------\n\n/*Returns a section of im, defined by a mask, on a black background*/\n_section_select2 im_in mask = output\n\t{\n\toutput  \n\t\t= clip2fmt im_in.format (im_black im_in.width im_in.height 1), mask == 0\n\t        = im_in;\n        };\n\n_mean_fn im = no_out\n   {\n   zero_im = (im == 0);\n   zero_mean = mean zero_im;              \n   no_mean = mean im;\n   no_out = no_mean/(1 - (zero_mean/255));\n   } \n\n"
  },
  {
    "path": "share/nip2/compat/7.9/_convert.def",
    "content": "\n/* Convert an image ... just set the Type field.\n */\nimage_set_type type in = im_copy_set in type \n\t(im_header_double \"Xres\" in) (im_header_double \"Yres\" in)\n\t(im_header_int \"Xoffset\" in) (im_header_int \"Yoffset\" in);\n\n/* Convert an image ... just set origin\n */\nimage_set_origin xoff yoff in = im_copy_set in \n\t(im_header_int \"Type\" in) \n\t(im_header_double \"Xres\" in) (im_header_double \"Yres\" in)\n\txoff yoff;\n\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x, is_real x || is_image x \n\t= error (errors.badargs ++ \"to_matrix\")\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (errors.badargs ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i && bands == 1\n\t\t= (im_vips2mask ((double) i'')).value, \n\t\t\tis_image i && bands == 3 && width == 1\n\t\t= error errors.not1band3band\n        {\n\t\twidth = im_header_int \"Xsize\" i;\n\t\tbands = im_header_int \"Bands\" i;\n\n                split = bandsplit i;\n                i' = im_insert (split?0) (split?1) 1 0;\n                i'' = im_insert i' (split?2) 2 0;\n        }\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_instanceof \"Colour\" x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x, is_real x || is_image x \n\t= error (errors.badargs ++ \"to_image\")\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (errors.badargs ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n                        = b1 ++ b2 ++ b3\n                {\n                        b1 = extract_area 0 0 1 height i;\n                        b2 = extract_area 1 0 1 height i;\n                        b3 = extract_area 2 0 1 height i;\n                }\n\t}\n}\n\n/* Try to make a real.\n */\nto_real x\n\t= to_real x.value, is_class x\n\t= x, is_real x\n\t= abs x, is_complex x\n\t= error (errors.badargs ++ \"to_real\");\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n        /* Turn a char digit to a number.\n         */\n        parse_c ch\n                = error \"parse_c: not a digit\", ! is_digit ch\n                = (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n        = error \"parse_number: badly formed number\", len parts != 2\n        = sign * n\n{\n        parts = splitpl [ member \"+-\", is_digit ] l;\n\n        n = parse_pint parts?1;\n        sign\n                = 1, parts?0 == [] || parts?0 == \"+\"\n                = -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n        = err, len parts != 4\n        = (ipart + fpart) * 10 ** exp\n{\n\terr = error \"parse_float: badly formed number\";\n\n        parts = splitpl [\n                member \"+-0123456789\", member \".0123456789\",\n                member \"eE\", member \"+-0123456789\" ] l;\n\n        ipart = parse_int parts?0;\n        fpart\n                = 0, parts?1 == [];\n                = err, parts?1?0 != '.'\n                = parse_pint (tl parts?1) / 10**(len parts?1 - 1);\n        exp\n                = 0, parts?2 == [] && parts?3 == []\n                = err, parts?2 == [] \n                = parse_int parts?3;\n\n}\n\n/* Print integer as hex.\n */\nprint_hex i\n\t= \"0\", chars == []\n\t= \"0x\" ++ reverse chars\n{\n\tdigits = takewhile (not_equal 0)\n\t\t(map (bitwise_and 0xf) \n\t\t\t(iterate (converse right_shift 4) i));\n\tchars = map tohd digits;\n\n\ttohd x\n\t\t= (char) ((int) '0' + x), x < 10\n\t        = (char) ((int) 'a' + (x - 10));\n}\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n        [[ 0.8951,  0.2664, -0.1614],\n         [-0.7502,  1.7135,  0.0367],\n         [ 0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n        = xyz'''\n{\n\t// divide by D50 white point\n        xyz' = xyz / Vector [96.4250, 100.0, 82.4680];\n\n        rgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n        rgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n        xyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * Vector [95.0470, 100.0, 108.8827];\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n        = xyz'''\n{\n\t// divide by D65 white point\n        xyz' = xyz / Vector [95.0470, 100.0, 108.8827];\n\n        rgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n        rgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n        xyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D50\n\txyz''' = xyz'' * Vector [96.4250, 100.0, 82.4680];\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz 96.4250 100 82.4680;\n\n/* Convert D50 Lab to XYZ.\n */\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab 96.4250 100 82.4680;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in = clip2fmt \n\t(im_header_int \"BandFmt\" in)\n\t(im_recomb in (Matrix [[.3, .6, .1]]));\nim_mono2sRGB in = (unsigned char) (in ++ in ++ in);\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= fn x, is_image x\n\t= error (errors.badargs ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= fn x, is_image x\n\t\t= error (errors.badargs ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (errors.badargs ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (errors.badargs ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, LAB, im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, sRGB, im_mono2sRGB],\n\t[B_W, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ im_mono2sRGB],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ \n\t\tim_mono2sRGB],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy],\n\t[XYZ, LAB, im_XYZ2Lab],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS],\n\t[XYZ, RGB, im_XYZ2disp],\n\t[XYZ, sRGB, im_XYZ2sRGB],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ],\n\t[YXY, XYZ, im_Yxy2XYZ],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ],\n\n\t[LAB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ],\n\t[LAB, XYZ, im_Lab2XYZ],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ],\n\t[LAB, LAB, image_set_type LAB],\n\t[LAB, LCH, im_Lab2LCh],\n\t[LAB, UCS, im_Lab2UCS],\n\t[LAB, RGB, im_Lab2disp],\n\t[LAB, sRGB, im_XYZ2sRGB @ im_Lab2XYZ],\n\t[LAB, LABQ, im_Lab2LabQ],\n\t[LAB, LABS, im_Lab2LabS],\n\n\t[LCH, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LCh2Lab],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab],\n\t[LCH, YXY, im_XYZ2Yxy @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LCh2Lab],\n\t[LCH, LAB, im_LCh2Lab],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab],\n\t[LCH, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LCh2Lab],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ],\n\t[UCS, XYZ, im_UCS2XYZ],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab],\n\t[UCS, LAB, im_UCS2Lab],\n\t[UCS, LCH, im_UCS2LCh],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab],\n\t[UCS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_UCS2Lab],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_XYZ2Lab @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_sRGB2XYZ @ \n\t\tim_clip],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Lab2XYZ @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (\"unable to convert \" ++ from_name ++ \" to \" ++ to_name)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n\tfrom_name = Image_type.type_names.lookup 1 0 from;\n\tto_name = Image_type.type_names.lookup 1 0 to;\n}\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x\n\t= is_image x || is_instanceof \"Image\" x || is_instanceof \"Arrow\" x ||\n\t\tis_instanceof \"Colour\" x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_instanceof \"Image\" x\n\t= get_type_im x.image.value, is_instanceof \"Arrow\" x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space,\n\t\tis_instanceof \"Colour\" x\n\t= error (\"get_type: unable to get type from \" ++ print x)\n{\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.B_W, bands == 1\n\t\t= type, bands == 3 && is_colorimetric\n\t\t= Image_type.MULTIBAND, bands != 3 && !is_colorimetric\n\t\t= type\n\t{\n\t\tis_colorimetric = Image_type.colour_spaces.present 1 type;\n\t\ttype = im_header_int \"Type\" im;\n\t\tcoding = im_header_int \"Coding\" im;\n\t\tbands = im_header_int \"Bands\" im;\n\t}\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n"
  },
  {
    "path": "share/nip2/compat/7.9/_errors.def",
    "content": "\n/* Lots of error messages.\n */\n\nerrors = class {\n\tnot1band = \"not 1 band image\";\n\tnot1band8bit = \"not 1 band 8-bit image\";\n\tnot1band3band = \"not 1 band image, or 3 band 1 column image\";\n\tnotodd = \"not odd width|height\";\n\tnotmask = \"not mask\";\n\tnotmaskim = \"not image|mask, mask\";\n\tbadcoding = \"not NOCODING or LABPACK\";\n\tbadlab = \"unable to convert to LAB\";\n\tallreal = \"not all real numbers\";\n\tallreg = \"not all regions\";\n\tbadargs = \"bad arguments to \";\n\tbadbands = \"images have differing numbers of bands\";\n\tbadcolour = \"bad arg to colourspace function\";\n\tbadmatrixmatch = \"matrix arguments do not match\";\n\tbadnum = \"wrong number of real number arguments\";\n\tbandFmt = \"bad BandFmt\";\n\tinternal = \"menu macro sanity failure!\";\n\tlengthdiff = \"list arguments differ in length\";\n\tnoimage = \"no image argument\";\n\tnoregion = \"no region argument\";\n\tnotim = \"not image\";\n\tnotimcmplx = \"not image|complex\";\n\tnotimnotreal = \"non image arguments not all real numbers\";\n\tnotimreg = \"not image|region\";\n\tnotregimreg = \"not region, image|region\";\n\tnotimregnum = \"not image|region|number\";\n\tnotimregstr = \"not image|region|string\";\n\tnotmatnum = \"not real|matrix|mask\";\n\tnotmatrix = \"not matrix|mask\";\n\tnotodd_square_matrix = \"not odd-sided square matrix|mask\";\n\tnotreal = \"not real number\";\n\tnotreglist = \"not region|[region]\";\n\tnotsquare_matrix = \"not square matrix|mask\";\n\tregwrong = \"regions not on two images\";\n\tsfacgt1 = \"shrink factors should be >= 1\";\n\tunknownType = \"unknown type\";\n\tusage = \"usage: \";\n};\n"
  },
  {
    "path": "share/nip2/compat/7.9/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y\n\t= (unsigned int) (h ++ v)\n{\n\th = (x - 1) * im_fgrey x y;\n\tv = (y - 1) * im_rot90 (im_fgrey y x);\n}\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= im''''\n{\n\tim = im_black w h b + pixel;\n\n\tim' = clip2fmt fmt im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n\tL = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W \n\t\tl\n\t\t(size / 2) (size / 2);\n\tA1 = im_fgrey size size;\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = L ++ A2 ++ A4;\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (map (const (max_value.lookup 1 0 format)) [1 .. bands])\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n"
  },
  {
    "path": "share/nip2/compat/7.9/_list.def",
    "content": "/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn (tl l), fn (hd l)\n\t= l;\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* foldl fn st l: fold list l up from the left using function fn and start value st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st (hd l)) (tl l);\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn (hd l) (tl l);\n\n/* foldr fn st l: fold up list l, right to left, with function fn and start \n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn (hd l) (foldr fn st (tl l));\n\n/* foldrl fn l: like foldr, but use the 1st element as the start value\n *\n * foldr1 fn [1,2,3,4] == (2 fn (3 fn (4 fn 1)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= foldr fn (hd l) (tl l);\n\n/* Search a list for an element, returning it's index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn (hd l)\n\t\t= search (tl l) (n + 1);\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= hd l : init (tl l);\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* land l: and all the elements of list l together\n *\n * land (map (==0) list) == true, if every element of list is zero.\n * land :: [bool] -> bool\n */\nland = foldr logical_and true;\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= hd l, tl l == []\n\t= last (tl l);\n\n/* len l: length of list l\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta = l?0;\n\tb = l?1;\n\tx = tl (tl l);\n}\n\n/* lor l: or all the elements of list l together\n *\n * lor (map (equal 0) list) == true, if any element of list is zero.\n * lor :: [bool] -> bool\n */\nlor = foldr logical_or false;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2\n\t= map fn' (zip2 l1 l2)\n{\n\tfn' p = fn p?0 p?1;\n}\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3\n\t= map fn' (zip3 l1 l2 l3)\n{\n\tfn' p = fn p?0 p?1 p?2;\n}\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = lor (map (equal x) l);\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta = hd l;\n\tx = tl l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scan fn st l: apply (fold fn r) to every initial segment of a list\n *\n * scan add 0 [1,2,3] == [1,3,6]\n * scan :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscan fn \n\t= g \n{\n\tg st l\n\t\t= [st], l == []\n\t\t= st : g (fn st (hd l)) (tl l);\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta = hd l1;\n\t\tx = tl l1;\n\t\tb = hd l2;\n\t\ty = tl l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by fn\n *\n * split is_space \"hello world\" == [\"hello\", \"world\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n  \n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together\n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/7.9/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true of character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && land (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, land (map is_obj l)\n\t= true, land (map is_list l) &&\n\t\tland (map (not @ is_obj) l) &&\n\t\tland (map is_rectangular l) &&\n\t\tlen l > 0 &&\n\t\tland (map (equal (hd lengths)) (tl lengths))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n\tlengths = map len l;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n */\nis_matrix l = is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == []\n      = is_matrix l && len l == len (hd l);\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == []\n      = is_matrix l && (len l) % 2 == 1 && (len (l?0)) % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && (len l) % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_Guide x = is_instanceof \"HGuide\" x || is_instanceof \"VGuide\" x;\n\nis_Point x = is_instanceof \"Point\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && land (map xy l)\n{\n\txy l = is_real_list l && len l == 2;\n}\n"
  },
  {
    "path": "share/nip2/compat/7.9/_stdenv.def",
    "content": "/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\njoin a b = a ++ b;\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\nif_then_else a b c = if a then b else c;\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error \"unimplemented vector operation\"\n{\n\tzeros = map (const 0) [1 .. len vec];\n\tones = map (const 1) [1 .. len vec];\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n/* Macbeth chart patch names.\n */\n_macbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (errors.badargs ++ \"bandsplit\")\n{\n\tbands = im_header_int \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= Image (concat (map get_value l)), \n\t\tis_listof (is_instanceof \"Image\") l\n\t= concat l, is_listof is_image l\n\t= error (errors.badargs ++ \"bandjoin\")\n{\n\tget_value x = x.value;\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= error (errors.badargs ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean_object Operator_type.COMPOUND false;\n\n\tmean_object x\n\t\t= im_avg x, is_image x\n\t\t= mean_list x, is_real_list x || is_matrix x\n\t\t= error (errors.badargs ++ \"mean\");\n\n\tmean_list l \n\t\t= s / n\n\t{\n\t\ttotals = sum l;\n\t\tn = totals?0;\n\t\ts = totals?1;\n\t}\n\n\t// return [n, sum] for a list of numbers, or a list of list of num\n\t// etc.\n\tsum x\n\t\t= foldr accumulate [0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s], is_real x\n\t\t\t= [n + n', s + s'], is_list x\n\t\t\t= error \"mean_list: not real or [real]\"\n\t\t{\n\t\t\tn = sofar?0;\n\t\t\ts = sofar?1;\n\n\t\t\tsub_acc = sum x;\n\n\t\t\tn' = sub_acc?0;\n\t\t\ts' = sub_acc?1;\n\t\t}\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= error (errors.badargs ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation_object Operator_type.COMPOUND false;\n\n\tdeviation_object x\n\t\t= im_deviate x, is_image x\n\t\t= deviation_list x, is_real_list x || is_matrix x\n\t\t= error (errors.badargs ++ \"deviation\");\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\ttotals = sum_sum2_list l;\n\t\tn = totals?0;\n\t\ts = totals?1;\n\t\ts2 = totals?2;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\tn = sofar?0;\n\t\t\ts = sofar?1;\n\t\t\ts2 = sofar?2;\n\n\t\t\tsub_acc = sum_sum2_list x;\n\n\t\t\tn' = sub_acc?0;\n\t\t\ts' = sub_acc?1;\n\t\t\ts2' = sub_acc?2;\n\t\t}\n\t}\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= error (errors.badargs ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs_object Operator_type.COMPOUND false;\n\n\tabs_object x\n\t\t= im_abs x, is_image x\n\t\t= abs_cmplx x, is_complex x\n\t\t= abs_num x, is_real x\n\t\t= abs_list x, is_real_list x\n\t\t= abs_list (map abs_list x), is_matrix x\n\t\t= error (errors.badargs ++ \"abs\");\n\n\tabs_list l = (foldr1 add (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= error (errors.badargs ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec_object Operator_type.COMPOUND false;\n\n\tabs_vec_object x\n\t\t= abs_vec_image x, is_image x\n\t\t= abs_vec_cmplx x, is_complex x\n\t\t= abs_vec_num x, is_real x\n\t\t= abs_vec_list x, is_real_list x\n\t\t= mean (Vector (map abs_vec_list x)), is_matrix x\n\t\t= error (errors.badargs ++ \"abs_vec\");\n\n\tabs_vec_list l = (foldr1 add (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (foldr1 add (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_matrix x, is_list x && is_list (hd x)\n\t= error (errors.badargs ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose_object Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_object x\n\t\t= transpose_matrix x, is_matrix x\n\t\t= transpose_image x, is_image x\n\t\t= error (errors.badargs ++ \"transpose\");\n\n\ttranspose_matrix l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_matrix (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (errors.badargs ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (errors.badargs ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\nrot90 x\n\t= oo_unary_function rot90_op x, is_class x\n\t= im_rot90 x, is_image x\n\t= error (errors.badargs ++ \"rot90\")\n{\n\trot90_op = Operator \"rot90\" \n\t\trot90_object Operator_type.COMPOUND_REWRAP false;\n\n\trot90_object x\n\t\t= rot90_matrix x, is_matrix x\n\t\t= im_rot90 x, is_image x\n\t\t= error (errors.badargs ++ \"rot90\");\n\n\t// slow, but what the heck\n\trot90_matrix l = (im_rotate_dmask90 (Matrix l)).value;\n}\n\nrot180 x\n\t= oo_unary_function rot180_op x, is_class x\n\t= im_rot180 x, is_image x\n\t= error (errors.badargs ++ \"rot180\")\n{\n\trot180_op = Operator \"rot180\" \n\t\trot180_object Operator_type.COMPOUND_REWRAP false;\n\n\trot180_object x\n\t\t= rot180_matrix x, is_matrix x\n\t\t= im_rot180 x, is_image x\n\t\t= error (errors.badargs ++ \"rot180\");\n\n\t// slow, but what the heck\n\trot180_matrix l = (im_rotate_dmask90 \n\t\t(im_rotate_dmask90 (Matrix l))).value;\n}\n\nrot270 x\n\t= oo_unary_function rot270_op x, is_class x\n\t= im_rot270 x, is_image x\n\t= error (errors.badargs ++ \"rot270\")\n{\n\trot270_op = Operator \"rot270\" \n\t\trot270_object Operator_type.COMPOUND_REWRAP false;\n\n\trot270_object x\n\t\t= rot270_matrix x, is_matrix x\n\t\t= im_rot270 x, is_image x\n\t\t= error (errors.badargs ++ \"rot270\");\n\n\t// slow, but what the heck\n\trot270_matrix l = (im_rotate_dmask90 (im_rotate_dmask90 \n\t\t(im_rotate_dmask90 (Matrix l)))).value;\n}\n\nrotquad x\n\t= oo_unary_function rotquad_op x, is_class x\n\t= im_rotquad x, is_image x\n\t= error (errors.badargs ++ \"rotquad\")\n{\n\trotquad_op = Operator \"rotquad\" \n\t\trotquad_object Operator_type.COMPOUND_REWRAP false;\n\n\trotquad_object x\n\t\t= rotquad_matrix x, is_matrix x\n\t\t= im_rotquad x, is_image x\n\t\t= error (errors.badargs ++ \"rotquad\");\n\n\trotquad_matrix l = error \"rotquad matrix: not implemented\"; \n}\n\nflipud x\n\t= oo_unary_function flipud_op x, is_class x\n\t= im_flipver x, is_image x\n\t= error (errors.badargs ++ \"flipud\")\n{\n\tflipud_op = Operator \"flipud\" \n\t\tflipud_object Operator_type.COMPOUND_REWRAP false;\n\n\tflipud_object x\n\t\t= flipud_matrix x, is_matrix x\n\t\t= im_flipver x, is_image x\n\t\t= error (errors.badargs ++ \"flipud\");\n\n\tflipud_matrix l = reverse l;\n}\n\nfliplr x\n\t= oo_unary_function fliplr_op x, is_class x\n\t= im_fliphor x, is_image x\n\t= error (errors.badargs ++ \"fliplr\")\n{\n\tfliplr_op = Operator \"fliplr\" \n\t\tfliplr_object Operator_type.COMPOUND_REWRAP false;\n\n\tfliplr_object x\n\t\t= fliplr_matrix x, is_matrix x\n\t\t= im_fliphor x, is_image x\n\t\t= error (errors.badargs ++ \"fliplr\");\n\n\tfliplr_matrix l = map reverse l;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= x, is_number x\n\t= error (errors.badargs ++ \"max\")\n{\n\tmax_op = Operator \"max\" max_list Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_matrix x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= x, is_number x\n\t= error (errors.badargs ++ \"min\")\n{\n\tmin_op = Operator \"min\" min_list Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_matrix x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= error (errors.badargs ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" \n\t\tmaxpos_object Operator_type.COMPOUND false;\n\n\tmaxpos_object x\n\t\t= maxpos_matrix x, is_matrix x\n\t\t= im_maxpos x, is_image x\n\t\t= error (errors.badargs ++ \"maxpos\");\n\n\tmaxpos_matrix m \n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= error (errors.badargs ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" \n\t\tminpos_object Operator_type.COMPOUND false;\n\n\tminpos_object x\n\t\t= minpos_matrix x, is_matrix x\n\t\t= im_minpos x, is_image x\n\t\t= error (errors.badargs ++ \"minpos\");\n\n\tminpos_matrix m \n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= error (errors.badargs ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats_object Operator_type.COMPOUND false;\n\n\tstats_object x\n\t\t= im_stats (to_image x).value, is_matrix x\n\t\t= im_stats x, is_image x\n\t\t= error (errors.badargs ++ \"stats\");\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (errors.badargs ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= rint_value x, is_image x || is_number x \n\t= error (errors.badargs ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint_value Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= scale_prim x\n{\n\tscale_op = Operator \"scale\" \n\t\tscale_prim Operator_type.COMPOUND_REWRAP false;\n\n\tscale_prim x\n\t\t= (unsigned char) x, is_number x \n\t\t= im_scale x, is_image x \n\t\t= scale_list x, is_real_list x || is_matrix x\n\t\t= error (errors.badargs ++ \"scale\");\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (errors.badargs ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (errors.badargs ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (errors.badargs ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= im_falsecolour x, is_image x \n\t= error (errors.badargs ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (errors.badargs ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (errors.badargs ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\nrecomb matrix image\n\t= colour_unary recomb_op image\n{\n\trecomb_op x\n\t\t= im_recomb x matrix, is_image x\n\t\t= error (errors.badargs ++ \"recomb\");\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= extract_area_prim obj\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" \n\t\textract_area_prim \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_area_prim obj\n\t\t= im_extract_area obj x' y' w' h', is_image obj\n\t\t= map (extract_range x' w') (extract_range y' h' obj),\n\t\t\tis_matrix obj\n\t\t= error (errors.badargs ++ \"extract_area\");\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_row_prim obj\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" \n\t\textract_row_prim \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_row_prim obj\n\t\t= im_extract_area obj 0 y' width 1, is_image obj\n\t\t= [obj?y'], is_matrix obj\n\t\t= error (errors.badargs ++ \"extract_row\")\n\t{\n\t\twidth = im_header_int \"Xsize\" obj;\n\t}\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_column_prim obj\n{\n\tx' = to_real x;\n\n\textract_column_op = Operator \"extract_column\" \n\t\textract_column_prim \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_column_prim obj\n\t\t= im_extract_area obj x' 0 1 height, is_image obj\n\t\t= map (converse cons [] @ converse subscript x') obj, \n\t\t\tis_matrix obj\n\t\t= error (errors.badargs ++ \"extract_column\")\n\t{\n\t\theight = im_header_int \"Ysize\" obj;\n\t}\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join_lr_prim a b\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin_lr_prim Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_lr_prim a b\n\t\t= im_extract_area (im_insert a b a_width 0)\n\t\t\t0 0 (a_width + b_width) out_height,\n\t\t\tis_image a && is_image b\n\t\t= map2 join a b,\n\t\t\tis_matrix a && is_matrix b\n\t\t= error (errors.badargs ++ \"join_lr\")\n\t{\n\t\ta_height = im_header_int \"Ysize\" a;\n\t\tb_height = im_header_int \"Ysize\" b;\n\t\ta_width = im_header_int \"Xsize\" a;\n\t\tb_width = im_header_int \"Xsize\" b;\n\t\tout_height = min_pair a_height b_height;\n\t}\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join_tb_prim a b\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin_tb_prim Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_tb_prim a b\n\t\t= im_extract_area (im_insert a b 0 a_height) \n\t\t\t0 0 out_width (a_height + b_height),\n\t\t\tis_image a && is_image b\n\t\t= map (take out_matrix_width) a ++ \n\t\t\tmap (take out_matrix_width) b,\n\t\t\tis_matrix a && is_matrix b\n\t\t= error (errors.badargs ++ \"join_tb\")\n\t{\n\t\ta_height = im_header_int \"Ysize\" a;\n\t\tb_height = im_header_int \"Ysize\" b;\n\t\ta_width = im_header_int \"Xsize\" a;\n\t\tb_width = im_header_int \"Xsize\" b;\n\t\tout_width = min_pair a_width b_width;\n\n\t\tout_matrix_width \n\t\t\t= min_pair a_matrix_width b_matrix_width\n\t\t{\n\t\t\ta_matrix_width = len a?0;\n\t\t\tb_matrix_width = len b?0;\n\t\t}\n\t}\n}\n\ninsert x y small big\n\t= oo_binary_function insert_op small big, is_class small\n\t= oo_binary'_function insert_op small big, is_class big\n\t= im_insert big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (errors.badargs ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n}\n\nmeasure x y w h u v image\n\t= oo_unary_function measure_op image, is_class image\n\t= im_measure image \n\t\t(to_real x) (to_real y) (to_real w) (to_real h)\n\t\t(to_real u) (to_real v), \n\t\t\tis_image image\n\t= error (errors.badargs ++ \"measure\")\n{\n\tmeasure_op = Operator \"measure\" \n\t\t(measure x y w h u v) Operator_type.COMPOUND_REWRAP false;\n}\n\nrotate angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_similarity image (cos angle) (sin angle) 0 0, \n\t\tis_real angle && is_image image \n\t= error (errors.badargs ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\trotate Operator_type.COMPOUND_REWRAP false;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = im_header_int \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\n\nclip2fmt format image\n\t= oo_unary_function (clip2fmt_op format) image, is_class image\n\t= im_clip2fmt image format, is_image image\n\t= error (errors.badargs ++ \"clip2fmt\")\n{\n\tclip2fmt_op format = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\timage = (unsigned char) im_mask2vips (Matrix m2);\n\tm2_width = im_header_int \"Xsize\" image;\n\tm2_height = im_header_int \"Ysize\" image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = im_embed image 0 (m1.width - 1) (m1.height - 1) \n\t\t(m2_width + 2 * (m1.width - 1))\n\t\t(m2_height + 2 * (m1.height - 1));\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image mask, is_image image\n\t= error (errors.badargs ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image mask, is_image image\n\t= error (errors.badargs ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image mask, is_image image\n\t= error (errors.badargs ++ \"conv\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image w h n, is_image image\n\t= error (errors.badargs ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find image\n\t= oo_unary_function hist_find_op image, is_class image\n\t= im_histgr image (-1), is_image image\n\t= error (errors.badargs ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\thist_find Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image bins, is_image image\n\t= error (errors.badargs ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\thist_find_nD Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (errors.badargs ++ \"hist_map\")\n{\n\thist_map_op = Operator \"hist_map\" \n\t\thist_map Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (errors.badargs ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (errors.badargs ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (errors.badargs ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= im_lhisteq image w h, is_image image\n\t= error (errors.badargs ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n}\n\nresize xfac yfac interp image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (errors.badargs ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac yfac, \n\t\t\tis_int xfac && is_int yfac && xfac >= 1 && yfac >= 1 &&\n\t\t\tinterp == Interpolate.nearest_neighbour\n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.nearest_neighbour\n\n\t\t// upscale by any factor, nearest neighbour \n\t\t// can't really do this right ... upscale by integer part, then\n\t\t// bilinear to exact size\n\t\t= scale (break xfac)?1 (break yfac)?1\n\t\t\t(im_zoom im (break xfac)?0 (break yfac)?0),\n\t\t\txfac >= 1 && yfac >= 1 &&\n\t\t\tinterp == Interpolate.nearest_neighbour\n\n\t\t// downscale by any factor, nearest neighbour \n\t\t// can't really do this right ... downscale by integer part, \n\t\t// then bilinear to exact size\n\t\t= scale (1 / (break xfac')?1) (1 / (break yfac')?1)\n\t\t\t(im_subsample im (break xfac')?0 (break yfac')?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.nearest_neighbour\n\n\t\t// upscale by any factor, bilinear\n\t\t= scale xfac yfac im,\n\t\t\txfac >= 1 && yfac >= 1 &&\n\t\t\tinterp == Interpolate.bilinear\n\n\t\t// downscale by any factor, bilinear\n\t\t// block shrink by integer factor, then bilinear resample to \n\t\t// exact\n\t\t= scale (1 / (break xfac')?1) (1 / (break yfac')?1)\n\t\t\t(im_shrink im (break xfac')?0 (break yfac')?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tinterp == Interpolate.bilinear\n\n\t\t= error (\"resize: unimplemented argument combination:\\n\" ++ \n\t\t\t\"  xfac = \" ++ print xfac ++ \"\\n\" ++\n\t\t\t\"  yfac = \" ++ print yfac ++ \"\\n\" ++\n\t\t\t\"  interp = \" ++ print interp ++ \" (\" ++\n\t\t\t\tInterpolate.names.lookup 1 0 interp ++ \")\")\n\t{\n\t\txfac' = 1 / xfac;\n\t\tyfac' = 1 / yfac;\n\n\t\t// convert a float scale to integer plus fraction\n\t\t// eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25)\n\t\tbreak f = [floor f, f / floor f];\n\n\t\t// binlinear resize\n\t\tscale xfac yfac im\n\t\t\t= im_affine im \n\t\t\t\txfac 0 0 yfac \n\t\t\t\t0 0 \n\t\t\t\t0 0 (width * xfac) (height * yfac)\n\t\t{\n\t\t\twidth = im_header_int \"Xsize\" im;\n\t\t\theight = im_header_int \"Ysize\" im;\n\t\t}\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c\n\t= map3 (map_trinary fn) a b c, is_list a && is_list b && is_list c\n\n\t= map2 (map_trinary fn a) b c, is_list b && is_list c\n\t= map2 (map_trinary (converse31 fn) b) a c, is_list a && is_list c\n\t= map2 (map_trinary (converse32 fn) c) a b, is_list a && is_list b\n\n\t= map (map_trinary fn a b) c, is_list c\n\t= map (map_trinary (converse32 fn) a c) b, is_list b\n\t= map (map_trinary (converse34 fn) b c) a, is_list a\n\n\t= fn a b c\n{\n\tconverse31 fn a b c = fn b a c;\n\tconverse32 fn a b c = fn c a b;\n\tconverse33 fn a b c = fn a c b;\n\tconverse34 fn a b c = fn b c a;\n}\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b\n\t= map2 (map_binary fn) a b, is_list a && is_list b\n\t= map (map_binary fn a) b, is_list b\n\t= map (map_binary (converse fn) b) a, is_list a\n\t= fn a b;\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a \n\t= map (map_unary fn) a, is_list a\n\t= fn a;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop block_size overlap i\n\t= map chop' [0, step .. height]\n{\n\twidth = im_header_int \"Xsize\" i;\n\theight = im_header_int \"Ysize\" i;\n\tbands = im_header_int \"Bands\" i;\n\tformat = im_header_int \"BandFmt\" i;\n\ttype = im_header_int \"Type\" i;\n\n\t/* Unique pixels per tile.\n\t */\n\tstep = block_size - overlap;\n\n\t/* Calculate padding ... pad up to block_size pixel boundary.\n\t */\n\tsx = block_size + (width - width % step);\n\tsy = block_size + (height - height % step);\n\n\t/* Expand image with black to pad size.\n\t */\n\tbackground = image_new sx sy bands format Image_coding.NOCODING type \n\t\t0 0 0;\n\tpad = im_insert background i 0 0;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, step .. width]\n\t{\n\t\tchop'' x = im_extract_area pad x y block_size block_size;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= vjoin (map hjoin il)\n{\n\t/* Join a list of tiles horizontally.\n\t */\n\thjoin l \n\t\t= foldl1 lrj l\n\t{\n\t\tlrj l r = im_lrmerge l r \n\t\t\t(hoverlap - im_header_int \"Xsize\" l) 0 10;\n\t}\n\n\t/* Join a list of tiles vertically.\n\t */\n\tvjoin l \n\t\t= foldl1 tbj l\n\t{\n\t\ttbj t b = im_tbmerge t b \n\t\t\t0 (voverlap - im_header_int \"Ysize\" t) 10;\n\t}\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n"
  },
  {
    "path": "share/nip2/compat/7.9/_types.def",
    "content": "\n/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), \"any\"];\ncheck_bool = [is_bool, \"boolean\"];\ncheck_real = [is_real, \"real\"];\ncheck_ureal = [is_ureal, \"unsigned real\"];\ncheck_preal = [is_preal, \"positive real\"];\ncheck_real_list = [is_real_list, \"list of real\"];\ncheck_string = [is_string, \"string\"];\ncheck_string_list = [is_string_list, \"list of string\"];\ncheck_int = [is_int, \"integer\"];\ncheck_uint = [is_uint, \"unsigned integer\"];\ncheck_pint = [is_pint, \"positive integer\"];\ncheck_matrix = [is_matrix, \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, \"0, 1, 2 or 3\"];\ncheck_image = [is_image, \"image\"];\ncheck_xy_list = [is_xy_list, \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_instanceof \"Matrix_base\", \"Matrix\"];\ncheck_colour_space = [is_colour_space, \"colour_space\"];\ncheck_rectangular = [is_rectangular, \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, \"HGuide or VGuide\"];\ncheck_Point = check_instance \"Point\";\ncheck_Colour = check_instance \"Colour\";\n\n/* Check a set of args. Grab _check_table. It's a list of two check\n * lists: the first checks each arg, and the second checks all args \n * together. \n *\n * - each line in argcheck is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in allcheck is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down a bit.\n */\ncheck_args x\n\t= x, badargs == [] && badalls == []\n\t= error message\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// join two strings up with a separator string\n\tjoin_sep j a b = a ++ j ++ b;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = errors.badargs ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++\n\t\t\"\\nusage\\n\" ++ indent ++ usage ++ \"\\nwhere\\n\" ++ \n\t\targ_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t\" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t\"you passed \" ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t\"you passed\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = \"condition failed: \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make usage note\n\tusage = x.name ++ \" \" ++ \n\t\tfoldr (join_sep \" \") [] (map (extract 1) argcheck);\n\n\t// make arg type notes\n\targ_types = foldr (join_sep \"\\n\") [] (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"and\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = foldr (join_sep \"\\n\") [] all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t// eg. add\n\tRELATIONAL = 2;\t\t// eg. less\n\tCOMPOUND = 3;\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (\"unknown binary operator: \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (\"unknown unary operator: \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n        \tOperator \"cast_signed_char\" cast_signed_char \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_signed_short\" cast_signed_short \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_signed_int\" cast_signed_int \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_float\" cast_float \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_double\" cast_double \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_complex\" cast_complex \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"cast_double_complex\" cast_double_complex \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"unary_minus\" unary_minus \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"negate\" negate \n\t\t\tOperator_type.RELATIONAL false,\n        \tOperator \"complement\" complement \n\t\t\tOperator_type.ARITHMETIC false,\n        \tOperator \"unary_plus\" unary_plus \n\t\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n        \tOperator \"re\" re Operator_type.ARITHMETIC false,\n        \tOperator \"im\" im Operator_type.ARITHMETIC false,\n        \tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n        \tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n        \tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n        \tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n        \tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n        \tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n        \tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n        \tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n        \tOperator \"log\" log Operator_type.ARITHMETIC false,\n        \tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n        \tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n        \tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n        \tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n        \tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= error (\"No method found for binary operator.\\n\" ++\n\t\t\"left = \" ++ print a ++ \"\\n\" ++\n\t\t\"operator = \" ++ op.op_name ++ \"\\n\" ++\n\t\t\"right = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n */\noo_binary'_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\top.symmetric && matches2 != []\n\t= error (\"No method found for binary operator.\\n\" ++\n\t\t\"left = \" ++ print a ++ \"\\n\" ++\n\t\t\"operator = \" ++ op.op_name ++ \"\\n\" ++\n\t\t\"right = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0,\n\t\tmatches != []\n\t= error (\"No method found for unary operator.\\n\" ++ \n\t\t\"operator = \" ++ op.op_name ++ \"\\n\" ++\n\t\t\"argument = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t/* Default: no checks ... override in subclasses.\n\t */\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x \n\t\t= oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x \n\t\t= oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op \n\t\t= oo_unary_function (oo_unary_lookup op) this;\n\n\t/* Provide a fallback for class == thing ... just use pointer\n\t * equality.\n\t */\n\too_binary_table op x = [\n\t\t[ pointer_equal this x,\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\" ],\n\t\t[ not_pointer_equal this x,\n\t\t\top.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\" ]\n\t];\n\too_unary_table op = [];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t] ++ super._check_args;\n\n\t// methods\n        oo_binary_table op x = [ \n\t\t[ this.Real (op.fn this.value x.value), \n\t\t\tis_instanceof \"Real\" x &&\n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ op.fn this.value x.value, \n\t\t\tis_instanceof \"Real\" x && \n\t\t\top.type == Operator_type.RELATIONAL ],\n\t\t[ op.fn this.value x, \n\t\t\t!is_class x ]\n\t] ++ super.oo_binary_table op x;\n\n        oo_unary_table op = [\n\t\t[ this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ op.fn this.value,\n\t\t\ttrue ]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t] ++ super._check_args;\n\n\t// methods\n        oo_binary_table op x = [ \n\t\t[ if value then x?0 else x?1,\n\t\t\top.op_name == \"if_then_else\" ],\n\t\t[ this.Bool (op.fn this.value x.value), \n\t\t\tis_instanceof \"Bool\" x ],\n\t\t[ this.Bool (op.fn this.value x), \n\t\t\tis_bool x ]\n\t] ++ super.oo_binary_table op x;\n\n        oo_unary_table op = [\n\t\t[ this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL ]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t] ++ super._check_args;\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t] ++ super._check_args;\n\n\tReal value = Number caption value;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t] ++ super._check_args;\n}\n\n// the old name\nFilename = Pathname \"Pick a file\";\n\n/* Vector type ... just a finite list of real ... handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t] ++ super._check_args;\n\n\tbands = len value;\n\n\t// methods\n        oo_binary_table op x = [ \n\t\t// Vector ++ Vector means bandwise join\n\t\t[ this.Vector (op.fn this.value x.value), \n\t\t\tis_instanceof \"Vector\" x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\") ],\n\t\t// extra check for lengths equal\n\t\t[ this.Vector (map_binary op.fn this.value x.value), \n\t\t\tis_instanceof \"Vector\" x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ this.Vector (map_binary op.fn this.value x.value), \n\t\t\tis_instanceof \"Real\" x &&\n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ this.Vector (map_binary op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC ],\n\n\t\t// need extra length check\n\t\t[ this.Vector (map bool_to_real \n\t\t\t(map_binary op.fn this.value x.value)), \n\t\t\tis_instanceof \"Vector\" x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL ],\n\t\t[ this.Vector (map bool_to_real \n\t\t\t(map_binary op.fn this.value x.value)), \n\t\t\tis_instanceof \"Real\" x &&\n\t\t\top.type == Operator_type.RELATIONAL ],\n\t\t[ this.Vector (map bool_to_real\n\t\t\t(map_binary op.fn this.value x)), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.RELATIONAL ],\n\t\t[ this.Vector (op.fn this.value x.value),\n\t\t\tis_instanceof \"Vector\" x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP ],\n\t\t[ x.Image (vec op'.op_name x.value value),\n\t\t\tis_instanceof \"Image\" x ],\n\t\t[ vec op'.op_name x value,\n\t\t\tis_image x ],\n\t\t[ op.fn this.value x, \n\t\t\tis_real x ]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n        oo_unary_table op = [\n\t\t[ this.Vector (map_unary op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ this.Vector (map bool_to_real\n\t\t\t(map_unary op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL ],\n\t\t[ this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP ],\n\t\t[ op.fn this.value,\n\t\t\ttrue ]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t] ++ super._check_args;\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// methods\n        oo_binary_table op x = [\n\t\t// mat multiply is special\n                [ this.Matrix_base mul.value,\n\t\t\tis_instanceof \"Matrix_base\" x &&\n\t\t\top.op_name == \"multiply\" ],\n                [ this.Matrix_base mul'.value,\n\t\t\tis_instanceof \"Matrix_base\" x &&\n\t\t\top.op_name == \"multiply'\" ],\n\n\t\t// mat divide is also special\n                [ this.Matrix_base div.value,\n\t\t\tis_instanceof \"Matrix_base\" x &&\n\t\t\top.op_name == \"divide\" ],\n                [ this.Matrix_base div'.value,\n\t\t\tis_instanceof \"Matrix_base\" x &&\n\t\t\top.op_name == \"divide'\" ],\n\n\t\t// power -1 means invert\n                [ this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\" ],\n                [ this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\" ],\n                [ error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\" ],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n                [ this.Matrix_base (map (map_binary op'.fn x.value) this.value),\n\t\t\tis_instanceof \"Vector\" x &&\n\t\t\top.type == Operator_type.ARITHMETIC ],\n                [ this.Matrix_base (map_binary op.fn this.value x.value),\n\t\t\t(is_instanceof \"Matrix_base\" x || \n\t\t\t is_instanceof \"Real\" x) && \n\t\t\top.type == Operator_type.ARITHMETIC ],\n\n                [ this.Matrix_base (map_binary op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC ],\n\n\t\t// compound ... don't do iteration\n                [ this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_instanceof \"Matrix_base\" x || \n\t\t\t is_instanceof \"Real\" x || \n\t\t\t is_instanceof \"Vector\" x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP ]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n        oo_unary_table op = [\n                [ this.Matrix_base (map_unary op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ],\n                [ this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP ],\n                [ op.fn this.value,\n\t\t\ttrue ]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t] ++ super._check_args;\n\n\tMatrix_base value = Matrix_vips value scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {};\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = im_read_dmask (expand filename);\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t] ++ super._check_args;\n\t_check_all = [\n\t\t[len value == 3, \"len value == 3\"]\n\t] ++ super._check_all;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = im_header_int \"Type\" im;\n\t\tbands = im_header_int \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n        oo_binary_table op x = [\n\t\t[ itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP ]\n\t] ++ super.oo_binary_table op x;\n\n        oo_unary_table op = [\n\t\t[ itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP ]\n\t] ++ super.oo_unary_table op;\n\n\tVector value = Colour colour_space value;\n}\n\n/* Base slider type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t] ++ super._check_args;\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t] ++ super._check_all;\n\n\t// methods\n        oo_binary_table op x = [ \n\t\t[ this.Scale (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_instanceof \"Scale\" x &&\n\t\t\top.type == Operator_type.ARITHMETIC ],\n\t\t[ this.Scale (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC ]\n\t] ++ super.oo_binary_table op x;\n\n\tReal value = Scale from to value;\n}\n\n/* Base slider type.\n */\nSlider f t v = Scale \"\" f t v;\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t] ++ super._check_args;\n\n\tBool value = Toggle caption value;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tReal value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t] ++ super._check_args;\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t] ++ super._check_args;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (map (extract col) value) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (\"item \" ++ print x ++ \" not in table\")\n\t{\n\t\tn = index (equal x) (map (extract from) value);\n\t}\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t] ++ super._check_args;\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// equal to another rect\n\tequal r = left == r.left && top == r.top && \n\t\twidth == r.width && height == r.height;\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n\n\t// operator overloading\n\t// just define equal and not equal\n        oo_binary_table op x = [ \n\t\t[ equal x, \n\t\t\tis_instanceof \"Rect\" x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\") ],\n\t\t[ !equal x, \n\t\t\tis_instanceof \"Rect\" x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\") ]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647\t// INT\n\t\t  ] ? fmt, fmt >= 0 && fmt <= INT\n\t\t= error errors.bandFmt;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tFOURIER = 24;\n\tYXY = 23;\n\tsRGB = 22;\n\tLABS = 21;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tLABQ = 16;\n\tCMYK = 15;\n\tCMC = 14;\n\tLAB = 13;\n\tXYZ = 12;\n\tLUT = 11;\n\tHISTOGRAM = 10;\n\tPOWER_SPECTRUM = 9;\n\tBLUE_ONLY = 8;\n\tGREEN_ONLY = 7;\n\tRED_ONLY = 6;\n\tYUV = 5;\n\tIR = 4;\n\tXRAY = 3;\n\tLUMINACE = 2;\n\tB_W = 1;\n\tMULTIBAND = 0;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Table [\n\t\t[ \"FOURIER\", FOURIER ],\n\t\t[ \"YXY\", YXY ],\n\t\t[ \"sRGB\", sRGB ],\n\t\t[ \"LABS\", LABS ],\n\t\t[ \"LCH\", LCH ],\n\t\t[ \"UCS\", UCS ],\n\t\t[ \"RGB\", RGB ],\n\t\t[ \"LABQ\", LABQ ],\n\t\t[ \"CMYK\", CMYK ],\n\t\t[ \"CMC\", CMC ],\n\t\t[ \"LAB\", LAB ],\n\t\t[ \"XYZ\", XYZ ],\n\t\t[ \"LUT\", LUT ],\n\t\t[ \"HISTOGRAM\", HISTOGRAM ],\n\t\t[ \"POWER_SPECTRUM\", POWER_SPECTRUM ],\n\t\t[ \"BLUE_ONLY\", BLUE_ONLY ],\n\t\t[ \"GREEN_ONLY\", GREEN_ONLY ],\n\t\t[ \"RED_ONLY\", RED_ONLY ],\n\t\t[ \"YUV\", YUV ],\n\t\t[ \"IR\", IR ],\n\t\t[ \"XRAY\", XRAY ],\n\t\t[ \"LUMINACE\", LUMINACE ],\n\t\t[ \"B_W\", B_W ],\n\t\t[ \"MULTIBAND\", MULTIBAND ]\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t */\n\tcolour_spaces = Table [\n\t\t[ \"XYZ\", Image_type.XYZ ],\n\t\t[ \"Yxy\", Image_type.YXY ],\n\t\t[ \"Lab\", Image_type.LAB ],\n\t\t[ \"LCh\", Image_type.LCH ],\n\t\t[ \"UCS\", Image_type.UCS ],\n\t\t[ \"RGB\", Image_type.RGB ],\n\t\t[ \"sRGB\", Image_type.sRGB ]\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t] ++ super._check_args;\n\n\t// fields from VIPS header\n\twidth = im_header_int \"Xsize\" value;\n\theight = im_header_int \"Ysize\" value;\n\tbands = im_header_int \"Bands\" value;\n\tformat = im_header_int \"BandFmt\" value;\n\tcoding = im_header_int \"Coding\" value;\n\ttype = im_header_int \"Type\" value;\n\txres = im_header_double \"Xres\" value;\n\tyres = im_header_double \"Yres\" value;\n\txoffset = im_header_int \"Xoffset\" value;\n\tyoffset = im_header_int \"Yoffset\" value;\n\tfilename = im_header_string \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy as a rect\n\trect = Rect (-xoffset) (-yoffset) width height;\n\n\t// extract an area, addressed in nip cordinates\n\textract_area left top width height = im_extract_area value \n\t\t(left + xoffset) (top + yoffset) width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n        oo_binary_table op x = [\n                [ this.Image (op.fn this.value x.value),\n\t\t\tis_instanceof \"Image\" x ||\n\t\t\tis_instanceof \"Real\" x ],\n                [ this.Image result_image,\n\t\t\top.op_name == \"if_then_else\" ],\n\t\t[ this.Image (vec op.op_name value x.value),\n\t\t\tis_instanceof \"Vector\" x ],\n                [ this.Image (op.fn this.value x),\n\t\t\tis_number x || is_image x ]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tto_image x\n\t\t\t= x, is_image x\n\t\t\t= x.value, is_instanceof \"Image\" x\n\t\t\t= black + x\n\t\t{\n\t\t\tblack = im_black width height target_bands;\n\t\t}\n\n\t\t// get a member from the first of a list of objects to have it\n\t\tget_property has get objects\n\t\t\t= hd members, members != []\n\t\t\t= error \"unable to get property\"\n\t\t{\n\t\t\tmembers = map get (filter has objects);\n\t\t}\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\tthen_part = x?0;\n\t\telse_part = x?1;\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_property \n\t\t\t(has_member \"bands\") (get_member \"bands\") objects;\n\t\ttarget_format = get_property \n\t\t\t(has_member \"format\") (get_member \"format\") objects;\n\t\ttarget_type = get_property has_type get_type objects;\n\n\t\tthen_image = to_image then_part;\n\t\telse_image = to_image else_part;\n\n\t\tthen_image' = clip2fmt target_format then_image;\n\t\telse_image' = clip2fmt target_format else_image;\n\n\t\tresult_image = image_set_type target_type\n\t\t\t(if value then then_image' else else_image');\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n        oo_unary_table op = [\n                [ this.Image result,\n\t\t\tis_image result ],\n                [ result,\n\t\t\ttrue ]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file str = class \n\tImage value {\n\t_check_args = [\n\t\t[str, \"str\", check_string]\n\t] ++ super._check_args;\n\n\tfile = Filename str;\n\n\tvalue = vips_image file.value;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t] ++ super._check_args;\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= image.extract_area left top width height,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height = Area image left top width height;\n}\n\nArrow image left top width height = class \n\tRect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t] ++ super._check_args;\n\t_check_all = [\n\t\t[image.rect.includes_rect this,\n\t\t\t\"image.rect.includes_rect this\"]\n\t] ++ super._check_all;\n\n\t// our rect, translated to image cods (ie. offset by origin)\n\timage_rect = Rect \n\t\t(left + image.xoffset) (top + image.yoffset) width height;\n\n\t// methods\n        oo_binary_table op x = [\n                [ this.Arrow this.image left' top' width' height',\n\t\t\tis_instanceof \"Arrow\" x && \n\t\t\top.type == Operator_type.ARITHMETIC ]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn this.left x.left;\n\t\ttop' = op.fn this.top x.top;\n\t\twidth' = op.fn this.width x.width;\n\t\theight' = op.fn this.height x.height;\n\t}\n\n        oo_unary_search op = [\n                [ this.Arrow this.image left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC ]\n\t] ++ super.oo_unary_table op \n\t{\n\t\tleft' = op.fn this.left;\n\t\ttop' = op.fn this.top;\n\t\twidth' = op.fn this.width;\n\t\theight' = op.fn this.height;\n\t}\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = VGuide image left;\n}\n\nPoint image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = Point image left top;\n}\n\n// Mark is the name nip2 expects for Point\nMark = Point;\n\n// convenience functions: make relative on an image ... subtract origin \n// offset, ie. make in pixel coordinates\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u - image.xoffset)\n\t\t(image.height * v - image.yoffset)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u - image.xoffset)\n\t\t(image.height * v - image.yoffset)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u - image.xoffset)\n\t\t(image.height * v - image.yoffset)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v - image.yoffset);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u - image.xoffset);\n\nPoint_relative image u v\n\t= Point image \n\t\t(image.width * u - image.xoffset)\n\t\t(image.height * v - image.yoffset);\n\nInterpolate = class {\n\tnearest_neighbour = 0;\n\tbilinear = 1;\n\tbicubic = 2;\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tnames = Table [\n\t\t[ \"Nearest neighbour\", nearest_neighbour ],\n\t\t[ \"Bilinear\", bilinear ],\n\t\t[ \"Bicubic\", bicubic ]\n\t];\n}\n\nSeparator = class {}\n\n// renamed in 7.9\nestpar = im_estpar;\nresample = im_transform_search;\n"
  },
  {
    "path": "share/nip2/compat/8.2/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t[_L, _a, _b] = default_value;\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n\n\tCCT_colour = class\n\t\tMenuaction (_ \"Colour from CCT\") (_ \"pick colour by CCT\") {\n\t\taction = widget 6500;\n\n\t\twidget x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tT = Scale \"CCT\" 1800 25000 x;\n\n\t\t\t_result = colour_from_temp (to_real T);\n\n\t\t\tColour_edit space value \n\t\t\t\t= widget (temp_from_colour (Colour space value));\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Convert to\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Tag as\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum (_ \"Old whitepoint\") Whitepoints \"D65\";\n\t\t\tnew_white = Option_enum (_ \"New whitepoint\") Whitepoints \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCCT_item = class\n\t\tMenuaction (_ \"Calculate temperature\")\n\t\t\t(_ \"estimate CCT using the McCamy approximation\") {\n\t\taction z = map_unary temp_from_colour z;\n\t}\n\n\tColour_item = Colour_new_item.CCT_colour;\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= print_profile, \n\t\t\thas_type image && \n\t\t\tget_type image == Image_type.CMYK &&\n\t\t\thas_bands image && \n\t\t\tget_bands image >= 4\n\t\t= monitor_profile;\n\trender_intents = Option_enum (_ \"Render intent\") Render_intent.names\n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_rad_item = class\n\tMenupullright (_ \"_Radiance\") (_ \"convert to and from Radiance packed format\") {\n\tUnpack_item = class\n\t\tMenuaction (_ \"Unpack\") \n\t\t\t(_ \"unpack Radiance format to float\") {\n\t\taction x = map_unary rad2float x;\n\t}\n\n\tPack_item = class\n\t\tMenuaction (_ \"Pack\") \n\t\t\t(_ \"pack 3-band float to Radiance format\") {\n\t\taction x = map_unary float2rad x;\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n        // get a representative image from an arg\n        get_image x\n            = get_image x.value?0, is_Group x\n            = x;\n\n        _im = get_image x; \n\t\tsample = measure_draw (to_real pacross) (to_real pdown) \n\t\t\t\t(to_real measure) _im;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure_sample (to_real pacross) (to_real pdown) \n\t\t\t\t\t(to_real measure) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.2/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 2;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 20;\n\t\t\tfs = Scale \"Sharpen flat areas by\" 0 5 0.5;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" 0 5 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tlayers = Scale \"Layers\" 1 100 10;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\", \"Approximate\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf, aconvsep layers]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\t\t\trotate = Option \"Rotate\" [\n\t\t\t\t\"Don't rotate\", \n\t\t\t\t\"4 x 45 degrees\", \n\t\t\t\t\"8 x 45 degrees\", \n\t\t\t\t\"2 x 90 degrees\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_lindetect, !separable && type == 0 && rotate == 1\n\t\t\t\t\t\t= im_compass, !separable && type == 0 && rotate == 2\n\t\t\t\t\t\t= im_gradient, !separable && type == 0 && rotate == 3\n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_conv_f, !separable && type == 1\n\t\t\t\t\t\t= im_convsep_f, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 4) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width.expr window_height.expr in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\nFilter_hough_item = class\n\tMenupullright \"_Hough Transform\" \"transform to parameter space\" {\n\tLine_item = class\n\t\tMenuaction \"_Line\" \"find straight line Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpspace_width = Expression \"Parameter space width\" 64;\n\t\t\tpspace_height = Expression \"Parameter space height\" 64;\n\n\t\t\t_result \n\t\t\t\t= map_unary line a \n\t\t\t{\n\t\t\t\tline a \n\t\t\t\t\t= hough_line \n\t\t\t\t\t\t(to_real pspace_width) (to_real pspace_height) a;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class\n\t\tMenuaction \"_Circle\" \"find circle Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Expression \"Scale down parameter space by\" 10;\n\t\t\tmin_radius = Expression \"Minimum radius\" 10;\n\t\t\tmax_radius = Expression \"Maximum radius\" 30;\n\n\t\t\t_result \n\t\t\t\t= map_unary circle a \n\t\t\t{\n\t\t\t\tcircle a \n\t\t\t\t\t= hough_circle (to_real scale) (to_real min_radius)\n\t\t\t\t\t\t(to_real max_radius) a;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_coordinate_item = class\n\tMenupullright \"_Coordinate Transform\" \"various coordinate transforms\" {\n\t// run a function which wants a complex arg on a non-complex two-band\n\t// image\n\trun_cmplx fn x\n\t\t= re x' ++ im x'\n\t{\n\t\tx' = fn (x?0, x?1);\n\t}\n\n\tPolar_item = class\n\t\tMenuaction \"_Polar\" \"transform to polar coordinates\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result \n\t\t\t\t= map_unary to_polar a \n\t\t\t{\n\t\t\t\tto_polar im \n\t\t\t\t\t= mapim interp.value map' im\n\t\t\t\t{\n\t\t\t\t\t// xy image, origin in the centre, scaled to fit image to\n\t\t\t\t\t// a circle\n\t\t\t\t\txy = make_xy im.width im.height;\n\t\t\t\t\txy' = xy - Vector [im.width / 2, im.height / 2];\n\t\t\t\t\tscale = min [im.width, im.height] / im.width;\n\t\t\t\t\txy'' = 2 * xy' / scale;\n\n\t\t\t\t\t// to polar, scale vertical axis to 360 degrees\n\t\t\t\t\tmap = run_cmplx polar xy'';\n\t\t\t\t\tmap' = map * Vector [1, im.height / 360];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tRectangular_item = class\n\t\tMenuaction \"_Rectangular\" \"transform to rectangular coordinates\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result \n\t\t\t\t= map_unary to_rect a \n\t\t\t{\n\t\t\t\tto_rect im \n\t\t\t\t\t= mapim interp.value map'' im\n\t\t\t\t{\n\t\t\t\t\t// xy image, vertical scaled to 360 degrees\n\t\t\t\t\txy = make_xy im.width im.height;\n\t\t\t\t\txy' = xy * Vector [1, 360 / im.height];\n\n\t\t\t\t\t// to rect, scale to image rect\n\t\t\t\t\tmap = run_cmplx rectangular xy';\n\t\t\t\t\tscale = min [im.width, im.height] / im.width;\n\t\t\t\t\tmap' = map * scale / 2;\n\n\t\t\t\t\tmap'' = map' + Vector [im.width / 2, im.height / 2];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image\" \"use an image to blend two objects\" {\n\t\taction a b c = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ti = Toggle \"Invert mask\" false;\n\n\t\t\t_result \n\t\t\t\t= map_trinary process a b c\n\t\t\t{\n\t\t\t\tprocess a b c \n\t\t\t\t\t= blend condition in1 in2, !i\n\t\t\t\t\t= blend (invert condition) in1 in2\n\t\t\t\t{\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t\t= false,\n\t\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t\t= true;\n\t\t\t\t\t[condition, in1, in2] = sortc compare [a, b, c];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"_Alpha\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t_ \"Normal\" => NORMAL,\n\t\t\t_ \"If Lighter\" => IFLIGHTER,\n\t\t\t_ \"If Darker\" => IFDARKER,\n\t\t\t_ \"Multiply\" => MULTIPLY,\n\t\t\t_ \"Add\" => ADD,\n\t\t\t_ \"Subtract\" => SUBTRACT,\n\t\t\t_ \"Screen\" => SCREEN,\n\t\t\t_ \"Burn\" => BURN,\n\t\t\t_ \"Soft Light\" => SOFTLIGHT,\n\t\t\t_ \"Hard Light\" => HARDLIGHT,\n\t\t\t_ \"Lighten\" => LIGHTEN,\n\t\t\t_ \"Darken\" => DARKEN,\n\t\t\t_ \"Dodge\" => DODGE,\n\t\t\t_ \"Reflect\" => REFLECT,\n\t\t\t_ \"Freeze\" => FREEZE,\n\t\t\t_ \"Bitwise OR\" => OR,\n\t\t\t_ \"Bitwise AND\" => AND\n\t\t];\n\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum \"Blend mode\" names \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\t[mono, colour] = \n\t\t\t\t\tsortc (const (is_colour_type @ get_type)) [a, b];\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t_ \"Grey\",\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t_ \"North-west\",\n\t\t\t\t_ \"North\",\n\t\t\t\t_ \"North-east\",\n\t\t\t\t_ \"West\",\n\t\t\t\t_ \"Centre\",\n\t\t\t\t_ \"East\",\n\t\t\t\t_ \"South-west\",\n\t\t\t\t_ \"South\",\n\t\t\t\t_ \"South-east\",\n\t\t\t\t_ \"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.2/Histogram.def",
    "content": "Hist_new_item = class\n\tMenupullright \"_New\" \"new histogram\" {\n\tHist_item = class\n\t\tMenuaction \"_Identity\" \"make an identity histogram\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\t_result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d);\n\t\t}\n\t}\n\n\tHist_new_from_matrix = Matrix_buildlut_item; \n\n\tHist_from_image_item = class\n\t\tMenuaction \"Ta_g Image As Histogram\" \"set image Type to Histogram\" {\n\t\taction x = hist_tag x;\n\t}\n\n\tTone_item = class \n\t\tMenuaction \"_Tone Curve\" \"make a new tone mapping curve\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\t_result \n\t\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t\t{\n\t\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_convert_to_hist_item = class \n\tMenuaction \"Con_vert to Histogram\" \"convert anything to a histogram\" {\n\taction x = hist_tag (to_image x);\n}\n\nHist_find_item = class \n\tMenupullright \"_Find\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n\n\tIndexed_item = class\n\t\tMenuaction \"_Indexed\" \n\t\t\t\"use a 1-band index image to pick bins for an n-band image\" {\n\t\taction x y \n\t\t\t= map_binary map x y\n\t\t{\n\t\t\tmap a b\n\t\t\t\t= hist_find_indexed index im\n\t\t\t{\n\t\t\t\t[im, index] = sortc (const is_index) [a, b];\n\n\t\t\t\tis_index x\n\t\t\t\t\t= has_image x && b == 1 && \n\t\t\t\t\t\t(f == Image_format.UCHAR || f == Image_format.USHORT)\n\t\t\t\t{\n\t\t\t\t\tim = get_image x;\n\t\t\t\t\tb = get_bands x;\n\t\t\t\t\tf = get_format x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\t[im, hist] = sortc (const is_hist) [a, b];\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Integrate\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate\" \n\t\t\"find point-to-point differences (inverse of Integrate)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_inv_item = class \n\tMenuaction \"In_vert\" \"invert a histogram\" {\n\taction x = map_unary hist_inv x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\tarea = extract_arrow \n\t\t\t\t\tdisplace.value vdisplace.value width.value arrow;\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize Interpolate_bilinear 1 (1 / width.value) area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary (extract_arrow \n\t\t\t\tdisplace.value vdisplace.value width.value) x;\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcaption = Expression \"Chart caption\" \"none\";\n\t\tformat = Option_enum \"Format\" Plot_format.names \"YYYY\";\n\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\t\txcaption = Expression \"X axis caption\" \"none\";\n\t\tycaption = Expression \"Y axis caption\" \"none\";\n\t\tseries_captions = Expression \"Series captions\" [\"Band 0\"];\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => style.value, $format => format.value] ++ \n\t\t\t\t\trange ++ captions;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\tcaptions \n\t\t\t\t= concat (map test caption_options) ++ \n\t\t\t\t  [$series_captions => series_captions.expr]\n\t\t\t{\n\t\t\t\tcaption_options = [\n\t\t\t\t\t$caption => caption.expr,\n\t\t\t\t\t$xcaption => xcaption.expr,\n\t\t\t\t\t$ycaption => ycaption.expr\n\t\t\t\t];\n\t\t\t\ttest x\n\t\t\t\t\t= [], value == \"none\"\n\t\t\t\t\t= [option_name => value]\n\t\t\t\t{\n\t\t\t\t\t[option_name, value] = x;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow 0 0 1 x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.2/Image.def",
    "content": "Image_new_item = class Menupullright \"_New\" \"make new things\" {\n\tImage_black_item = class Menuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \"Image type\"\n\t\t\t\tImage_type.type_names \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region on image using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\t[target, x] = sortc compare [a, b];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\nImage_number_format_item = class\n\tMenupullright \"_Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_header_item = class \n\tMenupullright \"_Header\" \"do stuff to the image header\" {\n\n\tImage_get_item = class\n\t\tMenupullright \"_Get\" \"get header fields\" {\n\n\t\t// the header fields we can get\n\t\tfields = class {\n\t\t\ttype = 0;\n\t\t\twidth = 1;\n\t\t\theight = 2;\n\t\t\tformat = 3;\n\t\t\tbands = 4;\n\t\t\txres = 5;\n\t\t\tyres = 6;\n\t\t\txoffset = 7;\n\t\t\tyoffset = 8;\n\t\t\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t$width => width,\n\t\t\t\t$height => height,\n\t\t\t\t$bands => bands,\n\t\t\t\t$format => format,\n\t\t\t\t$type => type,\n\t\t\t\t$xres => xres,\n\t\t\t\t$yres => yres,\n\t\t\t\t$xoffset => xoffset,\n\t\t\t\t$yoffset => yoffset,\n\t\t\t\t$coding => coding\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum (_ \"Field\") field_names name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tCustom_item = class\n\t\t\tMenuaction \"C_ustom\" \"get any header field\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tfield = String \"Field\" \"Xsize\";\n\t\t\t\tparse = Option \"Parse\" [\n\t\t\t\t\t\"No parsing\",\n\t\t\t\t\t\"Parse string as integer\",\n\t\t\t\t\t\"Parse string as real\",\n\t\t\t\t\t\"Parse string as hh:mm:ss\"\n\t\t\t\t] 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary (wrap @ process @ get_header field.value) x\n\t\t\t\t{\n\t\t\t\t\tparse_str parse str = parse (split is_space str)?0;\n\n\t\t\t\t\tparse_field name cast parse x\n\t\t\t\t\t\t= cast x, is_number x\n\t\t\t\t\t\t= parse_str parse x, is_string x\n\t\t\t\t\t\t= error (\"not \" ++ name);\n\n\t\t\t\t\tget_int = parse_field \"int\" \n\t\t\t\t\t\tcast_signed_int parse_int;\n\t\t\t\t\tget_float = parse_field \"float\" \n\t\t\t\t\t\tcast_float parse_float;\n\t\t\t\t\tget_time = parse_field \"hh:mm:ss\" \n\t\t\t\t\t\tcast_signed_int parse_time;\n\n\t\t\t\t\twrap x\n\t\t\t\t\t\t= Real x, is_real x\n\t\t\t\t\t\t= Vector x, is_real_list x\n\t\t\t\t\t\t= Image x, is_image x\n\t\t\t\t\t\t= Bool x, is_bool x\n\t\t\t\t\t\t= Matrix x, is_matrix x\n\t\t\t\t\t\t= String \"String\" x, is_string x\n\t\t\t\t\t\t= List x, is_list x\n\t\t\t\t\t\t= x;\n\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tget_int, \n\t\t\t\t\t\tget_float,\n\t\t\t\t\t\tget_time\n\t\t\t\t\t]?parse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum \"Image type\" Image_type.type_names \n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_cache_item = class\n\tMenuaction \"C_ache\" \"cache calculated image pixels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttile_width = Number \"Tile width\" 128;\n\t\ttile_height = Number \"Tile height\" 128;\n\t\tmax_tiles = Number \"Maximum number of tiles to cache\" (-1);\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= cache (to_real tile_width) (to_real tile_height) \n\t\t\t\t\t(to_real max_tiles) image;\n\t\t}\n\t}\n}\n\n#separator\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\t// we can't use id here since we want to \"declass\"\n\t\t\t\t\t\t// the members of x ... consider if x is a crop class,\n\t\t\t\t\t\t// for example, we don't want to inherit from crop, we\n\t\t\t\t\t\t// want to make a new image class\n\t\t\t\t\t\trot180 @ rot180,\n\t\t\t\t\t\trot90,\n\t\t\t\t\t\trot180,\n\t\t\t\t\t\trot270\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate interp angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary straighten x\n\t\t\t\t{\n\t\t\t\t\tstraighten arrow\n\t\t\t\t\t\t= rotate interp angle'' arrow.image\n\t\t\t\t\t{\n\t\t\t\t\t\tx = arrow.width;\n\t\t\t\t\t\ty = arrow.height;\n\t\t\n\t\t\t\t\t\tangle = im (polar (x, y));\n\t\t\n\t\t\t\t\t\tangle'\n\t\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t\t= angle;\n\t\t\n\t\t\t\t\t\tangle''\n\t\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize interp xfactor yfactor image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\taspect = Toggle \"Break aspect ratio\" false;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize interp h v image, aspect\n\t\t\t\t\t\t= resize interp fac fac image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac > yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\tmin_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac < yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\t[h, v] = [\n\t\t\t\t\t\t\tmax_factor, \n\t\t\t\t\t\t\tmin_factor, \n\t\t\t\t\t\t\t[xfac, 1], \n\t\t\t\t\t\t\t[1, yfac]]?which;\n\n\t\t\t\t\t\tfac \n\t\t\t\t\t\t\t= h, v == 1\n\t\t\t\t\t\t\t= v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_within_item = class\n\t\t\tMenuaction \"Size _Within\" \"size to fit within a rectangle\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\t// the rects we size to fit within\n\t\t\t\t_rects = [\n\t\t\t\t\t[2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], \n\t\t\t\t\t[1280, 1024], [1024, 768], [800, 600], [640, 480] \n\t\t\t\t];\n\n\t\t\t\twithin = Option \"Fit within (pixels)\" (\n\t\t\t\t\t[print w ++ \" x \" ++ print h :: [w, h] <- _rects] ++\n\t\t\t\t\t[\"Custom\"]\n\t\t\t\t) 4;\n\t\t\t\tcustom_width = Expression \"Custom width\" 1000;\n\t\t\t\tcustom_height = Expression \"Custom height\" 1000;\n\t\t\t    size = Option \"Page size\" [\n\t\t\t\t\t\"Full page\", \"Half page\", \"Quarter page\" \n\t\t\t\t] 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t \t_result\n\t\t\t\t \t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\txdiv = [1, 2, 2]?size;\n\t\t\t\t\tydiv = [1, 1, 2]?size;\n\t\t\t\t\tallrect = _rects ++ [\n\t\t\t\t\t\t[custom_width.expr, custom_height.expr]\n\t\t\t\t\t];\n\t\t\t\t\t[width, height] = allrect?within;\n\n\t\t\t\t\tprocess x\n\t\t\t\t\t\t= resize interp fac fac x, fac < 1\n\t\t\t\t\t\t= x\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = (width / xdiv) / x.width;\n\t\t\t\t\t\tyfac = (height / ydiv) / x.height;\n\t\t\t\t\t\tfac = min_pair xfac yfac;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_map_item = class\n\t\tMenuaction \"_Map\" \"map an image through a 2D transform image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result\n\t\t\t\t= map_binary trans a b\n\t\t\t{\n\t\t\t\ttrans a b\n\t\t\t\t\t= mapim interp.value in index\n\t\t\t\t{\n\t\t\t\t\t// get the index image first\n\t\t\t\t\t[index, in] = sortc (const is_twocomponent) [a, b];\n\n\t\t\t\t\t// is a two-component image, ie. one band complex, or\n\t\t\t\t\t// two-band non-complex\n\t\t\t\t\tis_twocomponent x\n\t\t\t\t\t\t= is_nonc x || is_c x;\n\t\t\t\t\tis_nonc x\n\t\t\t\t\t\t= has_bands x && get_bands x == 2 && \n\t\t\t\t\t\t\thas_format x && !is_complex_format (get_format x);\n\t\t\t\t\tis_c x\n\t\t\t\t\t\t= has_bands x && get_bands x == 1 && \n\t\t\t\t\t\t\thas_format x && is_complex_format (get_format x);\n\t\t\t\t\tis_complex_format f\n\t\t\t\t\t\t= f == Image_format.COMPLEX || \n\t\t\t\t\t\t\tf == Image_format.DPCOMPLEX;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\" [\"Nearest\", \"Bilinear\"] 1;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_trn {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t[sample', trn, err] = transform_search \n\t\t\t\t\tmax_err max_iter order interp wrap\n\t\t\t\t\tsample reference;\n\t\t\t\ttransformed_image = Image sample';\n\t\t\t\t_trn = Transform trn reference.width reference.height;\n\t\t\t\tfinal_error = err;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\t[i, t] = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tBandwise_item = Image_join_item.Bandwise_item;\n\n    sep1 = Menuseparator;\n\n\tBandand_item = class\n\t\tMenuaction \"Bitwise Band AND\" \"bitwise AND of image bands\" {\n\t\taction x = bandand x;\n\t}\n\n\tBandor_item = class\n\t\tMenuaction \"Bitwise Band OR\" \"bitwise OR of image bands\" {\n\t\taction x = bandor x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldl1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x \n\t\t= crop x [l, t, w, h]\n\t{\n\t\tfields = [\n\t\t\t[has_left, get_left, 0],\n\t\t\t[has_top, get_top, 0],\n\t\t\t[has_width, get_width, 100],\n\t\t\t[has_height, get_height, 100]\n\t\t];\n\n\t\t[l, t, w, h] \n\t\t\t= map get_default fields\n\t\t{\n\t\t\tget_default line\n\t\t\t\t= get x, has x\n\t\t\t\t= default\n\t\t\t{\n\t\t\t\t[has, get, default] = line;\n\t\t\t}\n\t\t}\n\t}\n\n\tcrop x geo = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tl = Expression \"Crop left\" ((int) (geo?0 + geo?2 / 4));\n\t\tt = Expression \"Crop top\" ((int) (geo?1 + geo?3 / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (geo?2 / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (geo?3 / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t[_a', _b'] = sortc _pred [a, b];\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_draw_item = class \n\tMenupullright \"_Draw\" \"draw lines, circles, rectangles, floods\" {\n\tLine_item = class Menuaction \"_Line\" \"draw line on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tx1 = Expression \"Start x\" 0;\n\t\t\ty1 = Expression \"Start y\" 0;\n\t\t\tx2 = Expression \"End x\" 100;\n\t\t\ty2 = Expression \"End y\" 100;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary line x\n\t\t\t{\n\t\t\t\tline im \n\t\t\t\t\t= draw_line x1 y1 x2 y2 i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tRect_item = class Menuaction \"_Rectangle\" \"draw rectangle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\trx = Expression \"Left\" 50;\n\t\t\try = Expression \"Top\" 50;\n\t\t\trw = Expression \"Width\" 100;\n\t\t\trh = Expression \"Height\" 100;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\tt = Scale \"Line thickness\" 1 50 3;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary rect x\n\t\t\t{\n\t\t\t\trect im \n\t\t\t\t\t= draw_rect_width rx ry rw rh f t i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class Menuaction \"_Circle\" \"draw circle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcx = Expression \"Centre x\" 100;\n\t\t\tcy = Expression \"Centre y\" 100;\n\t\t\tr = Expression \"Radius\" 50;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary circle x\n\t\t\t{\n\t\t\t\tcircle im \n\t\t\t\t\t= draw_circle cx cy r f i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tFlood_item = class Menuaction \"_Flood\" \"flood bounded area of image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsx = Expression \"Start x\" 100;\n\t\t\tsy = Expression \"Start y\" 100;\n\n\t\t\te = Option \"Flood while\" [\n\t\t\t\t\"Not equal to ink\",\n\t\t\t\t\"Equal to start point\"\n\t\t\t] 0;\n\n\t\t\t// pick a default ink that won't flood, if we can\n\t\t\ti \n\t\t\t\t= Expression \"Ink\" default_ink\n\t\t\t{\n\t\t\t\tdefault_ink\n\t\t\t\t\t= [0], ! has_image x\n\t\t\t\t\t= pixel;\n\t\t\t\tpixel = map mean (bandsplit (extract_area sx sy 1 1 im));\n\t\t\t\tim = get_image x;\n\t\t\t}\n\n\t\t\t_result \n\t\t\t\t= map_unary flood x\n\t\t\t{\n\t\t\t\tflood im \n\t\t\t\t\t= draw_flood sx sy i.expr im, e == 0\n\t\t\t\t\t= draw_flood_blob sx sy i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tDraw_scalebar_item = class Menuaction \"_Scale\" \"draw scale bar\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpx = Expression \"Left\" 50;\n\t\t\tpy = Expression \"Top\" 50;\n\t\t\twid = Expression \"Width\" 100;\n\t\t\tthick = Scale \"Line thickness\" 1 50 3;\n\t\t\ttext = String \"Dimension text\" \"50μm\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\tpos = Option \"Position Text\" [\"Above\", \"Below\"] 1;\n\t\t\tvp = Option \"Dimension by\" [\n\t\t\t\t\"Inner Vertical Edge\", \n\t\t\t\t\"Centre of Vertical\", \n\t\t\t\t\"Outer Vertical Edge\"\n\t\t\t] 1;\n            dpi = Expression \"DPI\" 100;\n            ink = Colour \"Lab\" [50,0,0];\n      \n            _result\n                = map_unary process x\n            {\n                process im\n                    = blend (Image scale) ink' im\n                {\n                    // make an ink compatible with the image\n                    ink' = colour_transform_to (get_type im) ink;\n\n                    x = to_real px;\n                    y = to_real py;\n                    w = to_real wid;\n                    d = to_real dpi;\n\n                    t = floor thick;\n\n                    bg = image_new (get_width im) (get_height im) (get_bands im)\n                        (get_format im) (get_coding im) (get_type im) 0 0 0;\n                    draw_block x y w t im =\n                        draw_rect_width x y w t true 1 [255] im;\n                    label = im_text text.value font.value w 1 d;\n                    lw = get_width label;\n                    lh = get_height label;\n                    ly = [y - lh - t, y + 2 * t]?pos;\n                    vx = [\n\t\t\t\t\t\t[x - t, x + w],\n\t\t\t\t\t\t[x - t / 2, x + w - t / 2],\n\t\t\t\t\t\t[x, x + w - t]\n\t\t\t\t\t]?vp;\n\n\t\t\t\t\tscale = (draw_block x y w t @\n\t\t\t\t\t\tdraw_block vx?0 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tdraw_block vx?1 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tinsert_noexpand (x + w / 2 - lw / 2) ly label)\n\t\t\t\t\t\tbg;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise Join\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t// we can't use map_unary since chop-into-tiles returns a group of\n\t\t\t// groups and we want to be able to reassemble that\n\t\t\t// TODO: chop-into-tiles should return an array class which\n\t\t\t// displays as group but does not have the looping behaviour?\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n\n\tArrayFL_item = class\n\t\tMenuaction \"_Array from List\"\n\t\t\t\"join a list of images into a single image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tncol = Number \"Max. Number of Columns\" 1;\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t_l \n\t\t\t\t= split_lines ncol.value x.value, is_Group x\n\t\t\t\t= split_lines ncol.value x;\n\n\t\t\t_result\n\t\t\t\t= (image_set_origin 0 0 @\n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value\n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list _l));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tGaussian_item = class \n\t\tMenuaction \"Gaussian _Noise\" \"make an image of gaussian noise\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t_result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) \n\t\t\t\tmean.value deviation.value);\n\t\t}\n\t}\n\n\tFractal_item = class \n\t\tMenuaction \"_Fractal\" \"make a fractal image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t}\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n\tColour_atlas_item = class\n\tMenuaction \"_Colour Atlas\"\n\t\t\"make a grid of patches grouped around a colour\" {\n\t\taction = class \n\t\t\t_result {   \n\t\t\t_vislevel = 3;\n       \n\t\t\tstart = Colour_picker \"Lab\" [50,0,0];\n\t\t\tnstep = Expression \"Number of steps\" 9;\n\t\t\tssize = Expression \"Step size\" 10; \n\t\t\tpsize = Expression \"Patch size\" 32;\n\t\t\tsepsize = Expression \"Separator size\" 4;\n\t\n\t\t\t_result\n\t\t\t\t= colour_transform_to (get_type start) blocks'''\n\t\t\t{\n\t\t\t\tsize = (to_real nstep * 2 + 1) * to_real psize - \n\t\t\t\t\tto_real sepsize;\n\t\t\t\txy = make_xy size size; \n\n\t\t\t\txy_grid = (xy % to_real psize) < \n\t\t\t\t\t(to_real psize - to_real sepsize);\n\t\t\t\tgrid = xy_grid?0 & xy_grid?1;\n\n\t\t\t\tblocks = (int) (to_real ssize * ((int) (xy / to_real psize)));\n\t\t\t\tlab_start = colour_transform_to Image_type.LAB start;\n\t\t\t\tblocks' = blocks - to_real nstep * to_real ssize + \n\t\t\t\t\tVector (tl lab_start.value);\n\t\t\t\tblocks'' = hd lab_start.value ++ Image blocks';\n\t\t\t\tblocks''' \n\t\t\t\t\t= image_set_type Image_type.LAB blocks'', Image grid\n\t\t\t\t\t= 0;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.2/Magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate Magick.def\n   13-Apr-2014 snibgo\n     Put \"new image\" items into sub-menu.\n     New class VirtualPixlBack.\n   17-Apr-2014 snibgo\n     Many small changes.\n     A few new menu options.\n     Created sub-menu for multi-input operations.\n   3-May-2014 jcupitt\n     Put quotes around ( in shadow to help unix\n\n   Last update: 17-Apr-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n*/\n\n// We don't need Noop.\n/*===\nMagick_noop_item = class\n\tMenuaction \"_Noop\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_testPar_item = class\n\tMenuaction \"_TestPar\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"( +clone ) +append \",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/* Removed Read_item and Write_item, much better to use nip2 load/save image.\n * Plus they can load all libMagick formats anyway.\n */\n\n\n// Put \"new image\" items into sub-menu\nMagick_NewImageMenu_item = class\n\tMenupullright \"_New image\" \"make a new image\" {\n\n\tMagick_newcanvas_item = class\n\t\tMenuaction \"_Solid colour\" \"make image of solid colour\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tcolour = Magick.generalcol_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"\\\"canvas:\" ++ colour._flag ++ \"\\\"\", \n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_builtin_item = class\n\t\tMenuaction \"_Built-in image\" \"create a built-in image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbuiltin = Magick.builtin_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tbuiltin._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_gradient_item = class\n\t\tMenuaction \"_Gradient\" \"make a linear gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\ttopColour = Magick.generalcol_widget;\n\t\t\tbottomColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"gradient:\", \n\t\t\t\t\ttopColour._flag, \"-\", bottomColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_hald_item = class\n\t\tMenuaction \"_Hald-clut image\" \"create an identity hald-clut image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torder = Expression \"order\" 8;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"hald:\" ++ print order.expr,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_pattern_item = class\n\t\tMenuaction \"_Pattern\" \"create pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tpattern = Magick.pattern_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tpattern._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_plasma_item = class\n\t\tMenuaction \"_Plasma image\" \"create plasma image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\t// FIXME? ColourA-ColourB.\n\t\t\t// FIXME? Allow plasma:fractal?\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"plasma:\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_radialgradient_item = class\n\t\tMenuaction \"_Radial gradient\" \n\t\t\t\"make a radial gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tinnerColour = Magick.generalcol_widget;\n\t\t\touterColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"radial-gradient:\", \n\t\t\t\t\tinnerColour._flag, \"-\", outerColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n}  // end Magick_NewImageMenu_item\n\n\nMagick_MultiMenu_item = class\n\tMenupullright \"_Multiple inputs\" \"make an image from multiple images\" {\n\n\tMagick_composite_item = class\n\t\tMenuaction \"_Composite\" \"composite two images (without mask)\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag,\n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_compositeMask_item = class\n\t\tMenuaction \"_Composite masked\" \"composite two images (with mask)\" {\n\t\taction x y z = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag, \n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system3 command x y z; \n\t\t}\n\t}\n\n\t// FIXME: other operations like remap that take another image as arguments are:\n\t// mask (pointless?), texture, tile (pointless?)\n\n\t// FIXME: operations that take a filename that isn't an image:\n\t// cdl, profile\n\n\tMagick_clut_item = class\n\t\tMenuaction \"_Clut\" \"replace values using second image as colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// FIXME: uses -intensity \"when mapping greyscale CLUT image to alpha channel if set by -channels\"\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_haldclut_item = class\n\t\tMenuaction \"_Hald clut\" \"replace values using second image as Hald colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-hald-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\n\t// Encipher and decipher: key files can be text or image files.\n\n\tMagick_encipher_item = class\n\t\tMenuaction \"_Encipher/Decipher\" \"encipher or decipher an image image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname = Pathname \"Read key file\" \"\";\n\t\t\tisDecipher = Toggle \"Decipher\" false;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname.value == \"\" then \"\" else (\n\t\t\t\t\t( if isDecipher then \"-decipher \" else \"-encipher \") ++\n\t\t\t\t\t( \"\\\"\" ++ pathname.value ++ \"\\\"\" )\n\t\t\t\t),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_profile_item = class\n\t\tMenuaction \"_Profile\" \"assigns/applies an ICC profile\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname1 = Pathname \"Read profile file\" \"\";\n\t\t\tpathname2 = Pathname \"Read profile file\" \"\";\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname1.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname1.value ++ \"\\\"\"),\n\t\t\t\tif pathname2.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname2.value ++ \"\\\"\"),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_remap_item = class\n\t\tMenuaction \"_Remap\" \"reduce colours to those in another image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-remap\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n}  // end Magick_MultiMenu_item\n\n\nMagick_image_type_item = class\n\tMenuaction \"_Image Type\" \"change image type\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\timagetype = Magick.imagetype_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\timagetype._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nsep2 = Menuseparator;\n\nMagick_alpha_item = class\n\tMenuaction \"_Alpha\" \"add/remove alpha channel\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\talpha = Magick.alpha_widget; \n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\talpha._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_annotate_item = class\n\tMenuaction \"_Annotate\" \"add text annotation\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttext = Magick.text_widget;\n\t\tfont = Magick.Font_widget;\n\t\tgeometry = Magick.AnnotGeometry_widget; \n\t\tgravity = Magick.gravity_widget; \n\t\tforeground = Magick.foreground_widget;\n\t\tundercol = Magick.undercol_widget;\n\t\tantialias = Magick.antialias_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfont._flag,\n\t\t\tantialias._flag,\n\t\t\tgravity._flag,\n\t\t\tforeground._flag,\n\t\t\tundercol._flag,\n\t\t\t\"-annotate\", \n\t\t\tgeometry._flag, \n\t\t\t\"\\\"\" ++ text.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoGamma_item = class\n\tMenuaction \"_AutoGamma\" \"automatic gamma\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-gamma\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoLevel_item = class\n\tMenuaction \"_AutoLevel\" \"automatic level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-level\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_blurSharpMenu_item = class\n\tMenupullright \"_Blur/Sharpen\" \"blur and sharpen\" {\n\n\tMagick_adaptive_blur_item = class\n\t\tMenuaction \"_Adaptive Blur\" \"blur less near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\t// note: adaptive-blur doesn't regard VP.\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-adaptive-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blur_item = class\n\t\tMenuaction \"_Blur\" \"blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_gaussianBlur_item = class\n\t\tMenuaction \"_Gaussian Blur\" \"blur with a Gaussian operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-gaussian-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_motionBlur_item = class\n\t\tMenuaction \"_Motion Blur\" \"simulate motion blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tangle = Scale \"angle\" (-360) 360 0;\n\t\t\tchannels = Magick.ch_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-motion-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_rotationalBlur_item = class\n\t\tMenuaction \"_RotationalBlur\" \"blur around the centre\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-radial-blur\", \n\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_selectiveBlur_item = class\n\t\tMenuaction \"_Selective Blur\" \"blur where contrast is less than or equal to threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-selective-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++  \"+\" ++\n\t\t\t\t\tprint threshold.value ++ \"%%\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMagick_adaptive_sharpen_item = class\n\t\tMenuaction \"_Adaptive Sharpen\" \"sharpen more near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\t\"-adaptive-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_sharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"sharpen\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_unsharpen_item = class\n\t\tMenuaction \"_Unsharp\" \"sharpen with unsharp mask\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tgain = Scale \"Gain\" (-10) 10 1;\n\t\t\tthreshold = Scale \"Threshold\" 0 1 0.05;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-unsharp\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint gain.value ++ \"+\" ++\n\t\t\t\t\tprint threshold.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end BlurSharpMenu_item\n\n\nMagick_border_item = class\n\tMenuaction \"_Border\" \"add border of given colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcompose = Magick.compose_widget;\n\t\twidth = Expression \"Width\" 3;\n\t\tbordercol = Magick.bordercol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag,\n\t\t\tbordercol._flag,\n\t\t\t\"-border\", \n\t\t\tprint width.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_brightCont_item = class\n\tMenuaction \"_Brightness-contrast\" \"adjust the brightness and/or contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbri = Scale \"brightness\" (-100) 100 0;\n\t\tcon = Scale \"contrast\" (-100) 100 0;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-brightness-contrast\", \n\t\t\tprint bri.value ++ \"x\" ++ print con.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// Note: canny requires ImageMagick 6.8.9-0 or later.\n\nMagick_canny_item = class\n\tMenuaction \"_Canny\" \"detect a wide range of edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tlowPc = Scale \"lower percent\" 0 100 10;\n\t\thighPc = Scale \"lower percent\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-canny\", \n\t\t\tconcat [\"\\\"\",\n\t\t\t\tprint radius.value ++ \"x\" ++ \n\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\tprint lowPc.value ++ \"%%+\" ++\n\t\t\t\tprint highPc.value ++ \"%%\" ++ \"\\\"\"\n\t\t\t],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_charcoal_item = class\n\tMenuaction \"_Charcoal\" \"simulate a charcoal drawing\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tfactor = Scale \"factor\" 0 50 1;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-charcoal\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_chop_item = class\n\tMenuaction \"_Chop\" \"remove pixels from the interior\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-chop\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorize_item = class\n\tMenuaction \"_Colorize\" \"colorize by given amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tval = Scale \"value\" 0 100 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-colorize\", \n\t\t\tprint val.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colors_item = class\n\tMenuaction \"_Colors\" \"reduce number of colors\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\t\tquantize = Magick.colorspace_widget;\n\t\tcolors = Expression \"Colours\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-quantize\", quantize._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\tdither._flag,\n\t\t\t\"-colors\", \n\t\t\tprint colors.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: color-matrix?\n\nMagick_colorspace_item = class\n\tMenuaction \"_Colourspace\" \"convert to arbitrary colourspace\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolsp = Magick.colorspace_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-colorspace\",\n\t\t\tcolsp._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorspaceGray_item = class\n\tMenuaction \"_Colourspace gray\" \"convert to gray using given intensity method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-colorspace gray\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrast_item = class\n\tMenuaction \"_Contrast\" \"increase or reduce the contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tisReduce = Toggle \"reduce contrast\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t(if isReduce then \"+\" else \"-\") ++ \"contrast\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrastStretch_item = class\n\tMenuaction \"_Contrast stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-contrast-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: convolve (bias, kernel)\n\nMagick_crop_item = class\n\tMenuaction \"_Crop\" \"cut out a rectangular region\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-crop\",\n\t\t\tgeometry._flag,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_deskew_item = class\n\tMenuaction \"_Deskew\" \"straighten the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\t// FIXME: toggle auto-crop?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-deskew\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_despeckle_item = class\n\tMenuaction \"_Despeckle\" \"reduce the speckles\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-despeckle\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_distort_item = class\n\tMenuaction \"_Distort\" \"distort using a method and arguments\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tdistort = Magick.distort_widget;\n\t\targs = String \"Arguments\" \"1,0\";\n\t\tisPlus = Toggle \"Extend to show entire image\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t(if isPlus then \"+\" else \"-\") ++ \"distort\",\n\t\t\tdistort._flag,\n\t\t\targs.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_draw_item = class\n\tMenuaction \"_Draw\" \"annotate with one or more graphic primitives\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\targs = String \"Arguments\" \"line 0,0 9,9 rectangle 10,10 20,20\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-draw\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_edge_item = class\n\tMenuaction \"_Edge\" \"detect edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-edge\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_emboss_item = class\n\tMenuaction \"_Emboss\" \"emboss\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-emboss\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_enhance_item = class\n\tMenuaction \"_Enhance\" \"enhance a noisy image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-enhance\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_equalize_item = class\n\tMenuaction \"_Equalize\" \"equalize the histogram\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-equalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_evaluate_item = class\n\tMenuaction \"_Evaluate\" \"evaluate an expression on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\toperation = Magick.evaluate_widget;\n\t\tval = Expression \"value\" 5;\n\t\tisPc = Toggle \"Value is percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag, \n\t\t\toperation._flag, \n\t\t\tprint val.expr ++ if isPc then \"%%\" else \"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_extent_item = class\n\tMenuaction \"_Extent\" \"set the image size and offset\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-extent\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_FlipFlopMenu_item = class\n\tMenupullright \"_Flip/flop\" \"flip/flop/transverse/transpose\" {\n\n\tMagick_flip_item = class\n\t\tMenuaction \"_Flip vertically\" \"mirror upside-down\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flip\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_flop_item = class\n\t\tMenuaction \"_Flop horizontally\" \"mirror left-right\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flop\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transpose_item = class\n\t\tMenuaction \"_Transpose\" \"mirror along the top-left to bottom-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transpose +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transverse_item = class\n\t\tMenuaction \"_Transverse\" \"mirror along the bottom-left to top-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transverse +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end Magick_FlipFlopMenu_item\n\n\nMagick_floodfill_item = class\n\tMenuaction \"_Floodfill\" \"recolour neighbours that match\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tfuzz = Magick.fuzz_widget;\n\t\tcoordinate = Magick.coordinate_widget;\n\n\t\t// -draw \"color x,y floodfill\"\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-draw \\\" color\",\n\t\t\tcoordinate._flag,\n\t\t\t\"floodfill \\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_frame_item = class\n\tMenuaction \"_Frame\" \"surround with border or beveled frame\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tborder = Magick.bordercol_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tmatte = Magick.mattecol_widget;\n\t\tgeometry = Magick.FrameGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tborder._flag, \n\t\t\tmatte._flag, \n\t\t\t\"-frame\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_function_item = class\n\tMenuaction \"_Function\" \"evaluate a function on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfunction = Magick.function_widget;\n\t\t// FIXME: explain values; use sensible defaults.\n\t\tvalues = String \"values\" \"0,0,0,0\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-function\", \n\t\t\tfunction._flag, \n\t\t\tvalues.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_fx_item = class\n\tMenuaction \"_Fx\" \"apply a mathematical expression\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\targs = String \"Expression\" \"u*1/2\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\tinterpolate._flag,\n\t\t\tvirtpixback._flag,\n\t\t\t\"-fx\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gamma_item = class\n\tMenuaction \"_Gamma\" \"apply a gamma correction\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tgamma = Magick.gamma_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-gamma\",\n\t\t\tprint gamma.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradient_item = class\n\tMenuaction \"_Gradient\" \"apply a linear gradient\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolourA = Magick.generalcol_widget;\n\t\tcolourB = Magick.generalcol_widget;\n\n\t\tposition = Option \"colourA is at\" [\n\t\t\t\t\"top\", \"bottom\", \n\t\t\t\t\"left\", \"right\", \n\t\t\t\t\"top-left\", \"top-right\", \n\t\t\t\t\"bottom-left\", \"bottom-right\"] 0;\n\t\t_baryArg\n\t\t\t= concat [\"0,0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 0\n\t\t\t= concat [\"0,0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 1\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],0,\", colourB._flag], position.value == 2\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],0,\", colourA._flag], position.value == 3\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourB._flag], position.value == 4\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 5\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 6\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourA._flag], position.value == 7\n\t\t\t= \"dunno\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color barycentric \\\"\" ++ _baryArg ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradientCorn_item = class\n\tMenuaction \"_Gradient corners\" \n\t\t\"apply a bilinear gradient between the corners\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour_top_left = Magick.generalcol_widget;\n\t\tcolour_top_right = Magick.generalcol_widget;\n\t\tcolour_bottom_left = Magick.generalcol_widget;\n\t\tcolour_bottom_right = Magick.generalcol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color bilinear \\\"\" ++\n\t\t\t\t\"0,0,\" ++ colour_top_left._flag ++\n\t\t\t\t\",%%[fx:w-1],0\" ++ colour_top_right._flag ++\n\t\t\t\t\",0,%%[fx:h-1]\" ++ colour_bottom_left._flag ++\n\t\t\t\t\",%%[fx:w-1],%%[fx:h-1]\" ++ colour_bottom_right._flag ++ \"\\\"\",\n\t\t\t\"+depth\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_histogram_item = class\n\tMenuaction \"_Histogram\" \"make a histogram image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-define histogram:unique-colors=false histogram:\" ++\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_implode_item = class\n\tMenuaction \"_Implode\" \"implode pixels about the center\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfactor = Scale \"factor\" 0 20 1;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\t// FIXME: virtual-pixel?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tinterpolate._flag,\n\t\t\t\"-implode\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_level_item = class\n\tMenuaction \"_Level\" \"adjust the level of channels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"black point\" (-100) 200 0;\n\t\twht = Scale \"white point\" (-100) 200 100;\n\t\tgam = Scale \"gamma\" 0 30 1;\n\t\tisPc = Toggle \"Levels are percent\" true;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \",\" ++ \n\t\t\t\tprint wht.value ++ (if isPc then \"%%\" else \"\") ++ \",\" ++ \n\t\t\t\tprint gam.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_levelCols_item = class\n\tMenuaction \"_Level colors\" \"adjust levels to given colours\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcolour_black = Magick.generalcol_widget;\n\t\tcolour_white = Magick.generalcol_widget;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level-colors\",\n\t\t\t\"\\\"\" ++ colour_black._flag ++ \",\" ++ colour_white._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_linearStretch_item = class\n\tMenuaction \"_Linear stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-linear-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_magnify_item = class\n\tMenuaction \"_Magnify\" \"double the size of the image with pixel art scaling\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-magnify\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_modulate_item = class\n\tMenuaction \"_Modulate\" \"modulate brightness, saturation and hue\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmodcolsp = Magick.ModColSp_widget;\n\t\tbright = Scale \"brightness\" 0 200 100;\n\t\tsat = Scale \"saturation\" 0 200 100;\n\t\thue = Scale \"hue\" 0 200 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tmodcolsp._flag,\n\t\t\t\"-modulate\",\n\t\t\tprint bright.value ++ \",\" ++ print sat.value ++ \",\" ++ \n\t\t\t\tprint hue.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_monochrome_item = class\n\tMenuaction \"_Monochrome\" \"transform to black and white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// FIXME: also intensity?\n\n\t\tintensity = Magick.intensity_widget;\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tdither._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\t\"-monochrome\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_morphology_item = class\n\t// See http://www.imagemagick.org/Usage/morphology/\n\tMenuaction \"_Morphology\" \"apply a morphological method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmethod = Magick.morphmeth_widget;\n\t\titer = Expression \"Iterations (-1=repeat until done)\" 1;\n\n\t\tkernel = Magick.kernel_widget;\n\t\t// FIXME: custom kernel eg \"3x1+2+0:1,0,0\"\n\t\t//   width x height + offsx + offsy : {w*h values}\n\t\t//   each value is 0.0 to 1.0 or \"NaN\" or \"-\"\n\n\t\t// kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0\n\t\t// but\n\t\t//   ring takes: radius1, radius2, scale\n\t\t//   rectangle and comet take: width x height + offsx + offsy\n\t\t//   blur takes: radius x sigma\n\t\t// FIXME: for now, simply allow any string input.\n\t\tkernel_arg = String \"Kernel arguments\" \"\";\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-morphology\",\n\t\t\tmethod._flag ++ \":\" ++ print iter.expr, \n\t\t\tkernel._flag ++\n\t\t\t(if kernel_arg.value == \"\" then \"\" else \":\") ++ kernel_arg.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_negate_item = class\n\tMenuaction \"_Negate\" \"negate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-negate\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_addNoise_item = class\n\tMenuaction \"_add Noise\" \"add noise\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tattenuate = Scale \"attenuate\" 0 1.0 1.0;\n\t\tnoise = Magick.noise_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-attenuate\", \n\t\t\tprint attenuate.value,\n\t\t\tnoise._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_normalize_item = class\n\tMenuaction \"_Normalize\" \"normalize\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-normalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_opaque_item = class\n\tMenuaction \"_Opaque\" \"change this colour to the fill colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfill = Magick.foreground_widget;\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfill._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"opaque\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_paint_item = class\n\tMenuaction \"_Paint\" \"simulate an oil painting\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"radius\" 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-paint\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/*=== FIXME Bug; remove for now.\nPolaroid_item = class\n\tMenuaction \"_Polaroid\" \"simulate a polaroid picture\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle\" (-90) 90 20;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-polaroid\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_posterize_item = class\n\tMenuaction \"_Posterize\" \"reduce to (n) levels per channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tlevels = Expression \"levels\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-posterize\",\n\t\t\tprint levels.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_raise_item = class\n\tMenuaction \"_Raise\" \"lighten or darken image edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthk = Expression \"Thickness\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-raise\",\n\t\t\tprint thk.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_resize_item = class\n\tMenuaction \"_Resize\" \"resize to given width and height\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfilter = Magick.filter_widget;\n\t\ttype = Magick.ResizeType_widget;\n\t\twidth = Scale \"Width\" 1 100 10;\n\t\theight = Scale \"Height\" 1 100 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfilter._flag,\n\t\t\t\"-\" ++ type._flag,\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"!\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_roll_item = class\n\tMenuaction \"_Roll\" \"roll an image horizontally or vertically\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trollx = Expression \"X\" 3;\n\t\trolly = Expression \"Y\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-roll\",\n\t\t\t(if rollx.expr >= 0 then \"+\" else \"\") ++ print rollx.expr ++\n\t\t\t(if rolly.expr >= 0 then \"+\" else \"\") ++ print rolly.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_rotate_item = class\n\tMenuaction \"_Rotate\" \"rotate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"+distort\",\n\t\t\t\"SRT\",\n\t\t\tprint angle.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -segment, but cluster-threshold should be percentage of image area.\n\nMagick_sepia_item = class\n\tMenuaction \"_Sepia tone\" \"simulate a sepia-toned photo\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sepia-tone\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shade_item = class\n\tMenuaction \"_Shade\" \"shade with a distant light source\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tazimuth = Scale \"Azimuth (degrees)\" (-360) 360 0;\n\t\televation = Scale \"Elevation (degrees)\" 0 90 45;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shade\",\n\t\t\tprint azimuth.value ++ \"x\" ++ print elevation.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shadow_item = class\n\tMenuaction \"_Shadow\" \"simulate a shadow\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshadowCol = Magick.generalcol_widget;\n\t\topacity = Scale \"Opacity (percent)\" 0 100 75;\n\t\tsigma = Scale \"Sigma\" 0 30 2;\n\t\t// FIXME: make offsets a single widget?\n\t\toffsx = Scale \"X-offset\" (-20) 20 4;\n\t\toffsy = Scale \"Y-offset\" (-20) 20 4;\n\t\tarePc = Toggle \"offsets are percentages\" false;\n\n\t\t// FIXME: raw operation creates page offset, which vips dislikes.\n\t\t// So we take this futher, compositing with source.\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"(\\\" +clone\",\n\t\t\t\"-background\", \"\\\"\" ++ shadowCol._flag ++ \"\\\"\",\n\t\t\t\"-shadow\",\n\t\t\tconcat [\n\t\t\t\t\"\\\"\",\n\t\t\t\tprint opacity.value, \"x\", print sigma.value,\n\t\t\t\t(if offsx.value >= 0 then \"+\" else \"\"), print offsx.value,\n\t\t\t\t(if offsy.value >= 0 then \"+\" else \"\"), print offsy.value,\n\t\t\t\t(if arePc then \"%%\" else \"\"),\n\t\t\t\t\"\\\"\"\n\t\t\t],\n\t\t\t\"\\\")\\\" +swap -background None -layers merge\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shave_item = class\n\tMenuaction \"_Shave\" \"shave pixels from the edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 0 50 10;\n\t\theight = Scale \"Height\" 0 50 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shave\",\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shear_item = class\n\tMenuaction \"_Shear\" \"shear along the x-axis and/or y-axis\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-shear\",\n\t\t\tprint shearX.expr ++ \"x\" ++ print shearY.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sigmoid_item = class\n\tMenuaction \"_Sigmoid\" \"increase or decrease mid-tone contrast sigmoidally\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcontrast = Scale \"contrast\" 0 30 3;\n\t\tmidpoint = Scale \"mid-point (percent)\" 0 100 50;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"sigmoidal-contrast\",\n\t\t\t\"\\\"\" ++ print contrast.value ++ \"x\" ++ \n\t\t\t\tprint midpoint.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sketch_item = class\n\tMenuaction \"_Sketch\" \"simulate a pencil sketch\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tangle = Scale \"angle\" (-360) 360 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sketch\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if angle >= 0 then (\"+\" ++ print angle.value) else \"\"),\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_solarize_item = class\n\tMenuaction \"_Solarize\" \"negate all pixels above a threshold level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-solarize\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -sparse-color needs abitrary list of {x,y,colour}.\n\nMagick_splice_item = class\n\tMenuaction \"_Splice\" \"splice a colour into the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-splice\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_spread_item = class\n\tMenuaction \"_Spread\" \"displace pixels by random amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tamount = Expression \"Amount (pixels)\" 5;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"-spread\",\n\t\t\tprint amount.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_statistic_item = class\n\tMenuaction \"_Statistic\" \"replace each pixel with statistic from neighbourhood\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width\" 5;\n\t\theight = Expression \"Height\" 5;\n\t\tstatisticType = Magick.StatType_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-statistic\", \n\t\t\tstatisticType._flag, \n\t\t\tprint width.expr ++ \"x\" ++ print height.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_swirl_item = class\n\tMenuaction \"_Swirl\" \"swirl around the centre\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Magick.angle_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-swirl\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_thresholdMenu_item = class\n\tMenupullright \"_Threshold\" \"make black or white\" {\n\n\tMagick_threshold_item = class\n\t\tMenuaction \"_Threshold\" \"apply black/white threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-threshold\", \n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blackThreshold_item = class\n\t\tMenuaction \"_Black threshold\" \"where below threshold set to black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-black-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_whiteThreshold_item = class\n\t\tMenuaction \"_White threshold\" \"where above threshold set to white\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-white-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_latThreshold_item = class\n\t\tMenuaction \"_Local Adaptive Threshold\" \"where above average plus offset set to white, otherwise black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twidth = Expression \"Width\" 10;\n\t\t\theight = Expression \"Height\" 10;\n\t\t\toffset = Scale \"Offset (percent)\" (-100) 100 0;\n\t\t\t// note: \"-lat\" doesn't respond to channels\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-lat\",\n\t\t\t\tconcat [\"\\\"\", print width.expr, \"x\", print height.expr, \n\t\t\t\t\t(if offset.value >= 0 then \"+\" else \"\"), print offset.value,\n\t\t\t\t\t\"%%\\\"\"\n\t\t\t\t],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_randThreshold_item = class\n\t\tMenuaction \"_Random Threshold\" \"between specified limits, apply random threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tlow = Scale \"Low threshold\" 0 100 10;\n\t\t\thigh = Scale \"High threshold\" 0 100 90;\n\t\t\tisPc = Toggle \"Thresholds are percent\" true;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-random-threshold\", \n\t\t\t\t\"\\\"\" ++ print low.value ++ \"x\" ++ print high.value ++\n\t\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end ThresholdMenu_item\n\n\n// Note: alternatives include:\n// convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif\n\nMagick_tile_item = class\n\tMenuaction \"_Tile\" \"fill given size with tiled image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tsize = Magick.Size_widget;\n\n\t\tcommand = Magick.command [\n\t\t\tsize._flag,\n\t\t\t\"tile:\" ++ \"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_tint_item = class\n\tMenuaction \"_Tint\" \"apply a tint\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tamount = Scale \"amount (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-tint\",\n\t\t\t// snibgo note: although the amount is a percentage, it doesn't need \"%\" character.\n\t\t\tprint amount.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_transparent_item = class\n\tMenuaction \"_Transparent\" \"make this colour transparent\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"transparent\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_trim_item = class\n\tMenuaction \"_Trim\" \"trims away border\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfuzz = Magick.fuzz_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-trim +repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_uniqueCols_item = class\n\tMenuaction \"_Unique colours\" \"discard all but one of any pixel color\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-unique-colors\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_vignette_item = class\n\tMenuaction \"_Vignette\" \"soften the edges in vignette style\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\trx = Scale \"Rolloff x (percent)\" 0 100 10;\n\t\try = Scale \"Rolloff y (percent)\" 0 100 10;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-vignette\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if rx.value >= 0 then \"+\" else \"\") ++ print rx.value ++\n\t\t\t\t(if ry.value >= 0 then \"+\" else \"\") ++ print ry.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_wave_item = class\n\tMenuaction \"_Wave\" \"shear the columns into a sine wave\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tamplitude = Scale \"Amplitude (pixels)\" 0 100 10;\n\t\twavelength = Scale \"Wavelength (pixels)\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-wave\",\n\t\t\tprint amplitude.value ++ \"x\" ++ print wavelength.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\n"
  },
  {
    "path": "share/nip2/compat/8.2/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/8.2\n\nstart_DATA = \\\n\tColour.def \\\n\t_convert.def \\\n\tFilter.def \\\n\t_generate.def \\\n\tHistogram.def \\\n\tImage.def \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_list.def \\\n\t_magick.def \\\n\tMagick.def \\\n\tMath.def \\\n\tMatrix.def \\\n\t_Object.def \\\n\tObject.def \\\n\t_predicate.def \\\n\tPreferences.ws \\\n\t_stdenv.def \\\n\tTasks.def \\\n\t_types.def \\\n\tWidgets.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/8.2/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_AND\" \"bitwise AND of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_OR\" \"bitwise OR of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"_XOR\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_NOT\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBandand_item = Image_band_item.Bandand_item; \n\n\tBandor_item = Image_band_item.Bandor_item; \n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tDifference_item = class \n\t\tMenuaction \"_Difference\" \"difference of two lists\" {\n\t\taction a b = map_binary difference a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tValue_item = class \n\t\tMenuaction \"_Value\" \"value of point in object\" {\n\t\taction a = class _result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tposition = Expression \"Coordinate\" (0, 0);\n\t\n\t\t\t_result = map_binary point position.expr a;\n\t\t}\n\t}\n\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tSkew_item = class \n\t\tMenuaction \"S_kew\" \"skew of image or list or vector\" {\n\t\taction a = map_unary skew a;\n\t}\n\n\tKurtosis_item = class \n\t\tMenuaction \"Kurtosis\" \"kurtosis of image or list or vector\" {\n\t\taction a = map_unary kurtosis a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \n\t\t\t\"position of centre of gravity of histogram\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = linreg xes yes;\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = linregw xes yes devs;\n\t}\n\n\tCluster_item = class \n\t\tMenuaction \"_Cluster\" \"cluster a list of numbers\" {\n\t\taction l = class {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tthresh = Expression \"Threshold\" 10;\n\t\n\t\t\t[_r, _w] = cluster thresh.expr l;\n\t\n\t\t\tresult = _r;\n\t\t\tweights = _w;\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.2/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_identity_item = class \n\t\tMenuaction \"_Identity\" \"make an identity matrix\" {\n\t\taction = identity (identity_matrix 5);\n\t\t\n\t\tidentity v = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix (identity_matrix (to_real s)), to_real s != len v;\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = identity value;\n\t\t}\n\t}\n\n\tMatrix_series_item = class \n\t\tMenuaction \"_Series\" \"make a series\" {\n\t\taction = series (mkseries 0 1 5);\n\n\t\tmkseries s t e \n\t\t\t= transpose [[to_real s, to_real s + to_real t .. to_real e]];\n\n\t\tseries v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t_s = v?0?0;\n\t\t\t_t = v?1?0 - v?0?0;\n\t\t\t_e = (last v)?0;\n\n\t\t\ts = Expression \"Start value\" _s;\n\t\t\tt = Expression \"Step by\" _t;\n\t\t\te = Expression \"End value\" _e;\n\n\t\t\t_result \n\t\t\t\t= Matrix (mkseries s t e), \n\t\t\t\t\t\tto_real s != _s || to_real t != _t || to_real e != _e\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = series value;\n\t\t}\n\t}\n\n\tMatrix_square_item = class \n\t\tMenuaction \"_Square\" \"make a square matrix\" {\n\t\taction = square (mksquare 5);\n\n\t\tmksquare s = replicate s (take s [1, 1 ..]);\n\n\t\tsquare v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == to_real s\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mksquare (to_real s); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = square value;\n\t\t}\n\t}\n\n\tMatrix_circular_item = class \n\t\tMenuaction \"_Circular\" \"make a circular matrix\" {\n\t\taction = circle (mkcircle 3);\n\n\t\tmkcircle r\n\t\t\t\t= map2 (map2 pyth) xes yes\n\t\t{\n\t\t\tline = [-r .. r];\n\t\t\txes = replicate (2 * r + 1) line;\n\t\t\tyes = transpose xes;\n\t\t\tpyth a b \n\t\t\t\t\t= 1, (a**2 + b**2) ** 0.5 <= r\n\t\t\t\t\t= 0;\n\t\t}\n\n\t\tcircle v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tr = Expression \"Radius\" ((len v - 1) / 2);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mkcircle (to_real r); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = circle value;\n\t\t}\n\t}\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\nMatrix_sort_item = class \n\tMenuaction \"_Sort\" \"sort by column or row\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\to = Option (_ \"Orientation\") [\n\t\t\t_ \"Sort by column\",\n\t\t\t_ \"Sort by row\"\n\t\t] 0;\n\t\ti = Expression (_ \"Sort on index\") 0;\n\t\td = Option (_ \"Direction\") [\n\t\t\t_ \"Ascending\",\n\t\t\t_ \"Descending\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary sort x\n\t\t{\n\t\t\tidx = to_real i;\n\t\t\tpred a b \n\t\t\t\t= a?idx <= b?idx, d == 0\n\t\t\t\t= a?idx >= b?idx;\n\t\t\tsort x\n\t\t\t\t= (x.Matrix_base @ sortc pred) x.value,\n\t\t\t\t\to == 0\n\t\t\t\t= (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value;\n\t\t}\n\t}\n}\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ \n\t\t\t\t\trange;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.2/Object.def",
    "content": "Object_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nObject_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nObject_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nObject_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nObject_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.2/Preferences.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/7.41.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"680\" window_height=\"800\" filename=\"$VIPSHOME/share/$PACKAGE/start/Preferences.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"100\" lpane_open=\"false\" rpane_position=\"400\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"Preferences\">\n    <Column x=\"0\" y=\"3067\" open=\"false\" selected=\"false\" sform=\"false\" next=\"99\" name=\"B\" caption=\"Interface column -- don't touch this!\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"CSV_SEPARATOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"O1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PRINT_CARTIESIAN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F10.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"USE_GRAPHICSMAGICK\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D45.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_PANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"237\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"788\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"700\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"100\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RELOAD\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D42.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_STATUSBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR_STYLE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MATRIX_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_RECOMP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"N2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_MAX_UNDO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[-1,0,1,5,10]?N1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_FONT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"N4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_INTERLACE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_LINELENGTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D41.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A6.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE_FILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PPM_MODE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"G1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_LAYOUT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C16.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C18.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_MULTI_RES\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_FORMAT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_PREDICTOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_BIGTIFF\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_START\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D25.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_SEARCH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D2.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_TMP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_SLIDER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D28.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_REGION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D29.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_AUTO_WS_SAVE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D30.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_DISPLAY_LED\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLKITBROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_MAX_HEAP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D38.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PIN_FILESEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_STATUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CONVERSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_RULERS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CROSSHAIR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL_HQ\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E21.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_TRACE_FUNCTIONS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"H1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_DEVICE\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CHANNEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_BRIGHTNESS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_COLOUR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CONTRAST\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_HUE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_FRAMES\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J13.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_MONO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J14.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_LEFT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_TOP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_ASPECT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_MAX_BLEND_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_REFINE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_WINDOW_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_OBJECT_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_BALANCE_GAMMA\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"680\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER_REMOTE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"POPUP_NEW_ROWS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_HISTORY_MAX\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D43.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_CPUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D44.value\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2831\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"I\" caption=\"Mosaic defaults\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Maximum blend width&quot; 0 100 10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Refine tie-points&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search windows this size&quot; 30\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search for objects this size&quot; 10\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Image gamma for mosaic balance&quot; 1 3 1.6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2495\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"J\" caption=\"Video for linux\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"J2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;Device&quot; &quot;/dev/video&quot;\"/>\n            <Pathname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Channel&quot; [&quot;TV&quot;, &quot;Composite 1&quot;, &quot;Composite 2&quot;, &quot;Composite 3&quot;] 1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Brightness&quot; 0 32767 23000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Colour&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Contrast&quot; 0 32767 27000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Hue&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Number of frames to average&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Grab monochrome&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2208\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"K\" caption=\"General video capture\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"K1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Crop video: \" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Crop video&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop left&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop top&quot; 6\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number  &quot;Crop width&quot; 747\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop height&quot; 570\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Aspect ratio (stretch vertically\\nby this much)&quot; 1.202\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2072\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"M\" caption=\"PNG save options\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"M1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Compression&quot; (map print [0..9]) 6\"/>\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Interlace&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1970\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"G\" caption=\"PPM/PGM/PBM save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"PPM mode\" labelsn=\"2\" labels0=\"Binary\" labels1=\"ASCII\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Mode&quot; [&quot;Binary&quot;, &quot;ASCII&quot;] 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1620\" open=\"true\" selected=\"true\" sform=\"false\" next=\"27\" name=\"C\" caption=\"TIFF save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Compression&quot; [&quot;None&quot;, &quot;LZW&quot;, &quot;Zip (deflate)&quot;, &quot;PACKBITS&quot;, &quot;JPEG&quot;, &quot;CCITTFAX4&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;JPEG quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Deflate/LZW predictor&quot; [&quot;None&quot;,&quot;Horizontal difference&quot;,&quot;Floating-point&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Layout\" labelsn=\"2\" labels0=\"Strip\" labels1=\"Tile\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Layout&quot; [&quot;Strip&quot;, &quot;Tile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile width&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile height&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Multi-res&quot; [&quot;Single image&quot;, &quot;Image pyramid&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Format&quot; [&quot;No truncation&quot;,&quot;Save 1 band 8 bit images as 1 bit&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Save as BigTIFF&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1518\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"O\" caption=\"CSV save\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"String &quot;Separator character&quot; &quot;\\t&quot;\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1348\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"A\" caption=\"JPEG save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;ICC profile&quot; [&quot;Use image profile, if any&quot;, &quot;Embed profile from file&quot;, &quot;Don't attach a profile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Pathname/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;ICC profile file&quot; &quot;$VIPSHOME/share/nip2/data/sRGB.icm&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1144\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"F\" caption=\"Widgets\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Pin up file requestors&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Main window toolbar&quot; [&quot;Default style&quot;, &quot;Icon only&quot;, &quot;Text only&quot;, &quot;Icon and text&quot;, &quot;Icon and text to right&quot;] 0\"/>\n            <Option caption=\"Main window toolbar\" labelsn=\"5\" labels0=\"Default style\" labels1=\"Icon only\" labels2=\"Text only\" labels3=\"Icon and text\" labels4=\"Icon and text to right\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display LEDs in workspace&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display complex numbers as coordinates&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1044\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"H\" caption=\"Debug options\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Disassemble functions\" value=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;untitled&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"906\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"L\" caption=\"Help browser\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"L2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Command to start browser&quot; &quot;firefox&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Go-to-page argument&quot; &quot;-remote 'openURL(%s)'&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"734\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"N\" caption=\"Paintbox \">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Max undo steps\" labelsn=\"5\" labels0=\"Unlimited\" labels1=\"None\" labels2=\"1\" labels3=\"5\" labels4=\"10\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Max undo steps&quot; [&quot;Unlimited&quot;, &quot;None&quot;, &quot;1&quot;, &quot;5&quot;, &quot;10&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Fontname &quot;Default paintbox font&quot; &quot;Sans 12&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Fontname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update during paint&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"458\" open=\"true\" selected=\"false\" sform=\"false\" next=\"27\" name=\"E\" caption=\"Image display\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"E20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use crosshair cursor in image windows&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Thumbnail size&quot; 64\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;High-quality thumbnails&quot; false\"/>\n            <Toggle/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window width&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window height&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto image window pop up&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"46\" name=\"D\" caption=\"Calculation\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Data path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;data&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;data&quot;], &quot;.&quot;]\"/>\n            <Expression caption=\"Data path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Temporary files&quot; (path_relative [&quot;$SAVEDIR&quot;, &quot;tmp&quot;])\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Start path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;start&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;start&quot;]]\"/>\n            <Expression caption=\"Start path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D28\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update sliders during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update sliders during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D29\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update regions during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update regions during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D30\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto workspace save&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D42\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto-reload on file change&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D41\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Text display length (characters)&quot; 80\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D38\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Heap size (per workspace)&quot; 600000\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D43\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of VIPS functions to memoise&quot; 20000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D44\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of CPUs to use (0 for autodetect)&quot; 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D45\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use GraphicsMagick for Magick menu&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/compat/8.2/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\n\tCsv_import_item = class\n\t\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tstart_line = Expression \"Start at line\" 1;\n\t\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_csv2vips filename)\n\t\t\t{\n\t\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\t\tescape x \n\t\t\t\t\t= foldr prefix [] x\n\t\t\t\t{\n\t\t\t\t\tprefix x l\n\t\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t\t= x : l;\n\t\t\t\t}\n\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tRaw_import_item = class\n\t\tMenuaction \"_Raw Import\" \"read a file of binary values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tacross = Expression \"Pixels across\" 100;\n\t\t\tdown = Expression \"Pixels down\" 100;\n\t\t\tbytes = Expression \"Bytes per pixel\" 3;\n\t\t\tskip = Expression \"Skip over initial bytes\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_binfile path.value \n\t\t\t\t\tacross.expr down.expr bytes.expr skip.expr)\n\t\t\t{\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// interpret Analyze header for layout and calibration\n\tAnalyze7_header_item = class\n\t\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\t\"examine the Analyze header and set layout and value\" {\n\t\taction x \n\t\t\t= x'''\n\t\t{\n\t\t\t// read bits of header\n\t\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\t\tdim0 = dim 0 x;\n\t\t\tdim1 = dim 1 x;\n\t\t\tdim2 = dim 2 x;\n\t\t\tdim3 = dim 3 x;\n\t\t\tdim4 = dim 4 x;\n\t\t\tdim5 = dim 5 x;\n\t\t\tdim6 = dim 6 x;\n\t\t\tdim7 = dim 7 x;\n\t\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\t\n\t\t\t// oops, now a nop\n\t\t\tx' = x;\n\t\n\t\t\t// lay out higher dimensions width-ways\n\t\t\tx'' \n\t\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\t\tdim0 == 7\n\t\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\t\n\t\t\t// multiply by scale factor to get kBeq\n\t\t\tx''' = x'' * (cal_max / glmax);\n\t\t}\n\t}\n\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\t[image, patch] = sortc larger [a, b];\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n\t\t\tsample = measure_draw 6 4 (to_real measure) image;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\tmode = Option \"Input LUT\" [\n\t\t\t\t\"Linearize from chart greyscale\",\n\t\t\t\t\"Fit intercept from chart greyscale\",\n\t\t\t\t\"Linear input, set brightness from chart\",\n\t\t\t\t\"Linear input\"\n\t\t\t] 0;\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = measure_sample 6 4 (to_real measure) image;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb \n\t\t\t\t= Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0\n\t\t\t\t= Matrix [0: intercepts, replicate (_camera.width + 1) 1], \n\t\t\t\t\tmode == 1\n\t\t\t\t= Matrix [[0, 0], [1, 1]]\n\t\t\t{\n\t\t\t\tintercepts = [(linreg _true_grey_Y' cam).intercept :: \n\t\t\t\t\tcam <- transpose _camera_grey'];\n\t\t\t}\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\t// plot from 0 explicitly so we see the effect of mode1 (intercept\n\t\t\t// from greyscale)\n\t\t\tlinearising_lut = Plot [$ymin => 0] _linear_lut;\n\n\t\t\t// map an image though the lineariser\n\t\t\tlinear x\n\t\t\t\t= hist_map linearising_lut.value x, mode == 0 || mode == 1\n\t\t\t\t= x;\n\n\t\t\t// map the chart measurements though the lineariser\n\t\t\t_camera' = (to_matrix @ linear @ to_image) _camera;\n\n\t\t\t// solve for RGB -> XYZ\n\t\t\t// normalise: the 2nd row is what makes Y, so divide by that to\n\t\t\t// get Y in 0-1.\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\t_full_M = transpose (_pinv * (transpose _camera' * _true_XYZ));\n\t\t\tM = _full_M / scale;\n\t\t\tscale = sum _full_M.value?1;\n\n\t\t\t// now turn the camera to LAB and calculate dE76\n\t\t\t_camera'' = (to_matrix @ \n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @ \n\t\t\t\trecomb M @ \n\t\t\t\tmultiply scale @\n\t\t\t\tto_image) _camera';\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tavg_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0 && i < len macbeth_names\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\n\t\t\t// normalise brightness ... in linear mode, we optionally don't\n\t\t\t// set the brightness from the Macbeth chart\n\t\t\tnorm x \n\t\t\t\t= x * scale, mode != 3\n\t\t\t\t= x;\n\n\t\t\t// convert RGB camera to Lab\n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tnorm @\n\t\t\t\trecomb M @\n\t\t\t\tcast_float @\n\t\t\t\tlinear) image.value;\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b = class\n\t\t\t(map_binary process a b) {\n\t\t\tprocess a b\n\t\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t\t{\n\t\t\t\t// the name of the calib object we need\n\t\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t\t// get the Calibrate_chart arg first\n\t\t\t\t[image, calib] = sortc (const (is_instanceof calib_name)) \n\t\t\t\t\t[a, b];\n\n\t\t\t\tresult = (Image @\n\t\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\t\tcalib.norm @\n\t\t\t\t\trecomb calib.M @\n\t\t\t\t\tcast_float @\n\t\t\t\t\tcalib.linear) image.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [$style => style.value] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\t!is_list_len 2 images\n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = all (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize Interpolate_bilinear xfactor yfactor scale_im;\n\t\t\t_offset_im = resize Interpolate_bilinear xfactor yfactor offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.2/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.2/_Object.def",
    "content": "/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0|1|2|3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \n\tjoin_sep \"|\" Image_type.colour_spaces.names];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide|VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad properties for \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"where\" ++ \"\\n\" ++ arg_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make arg type notes\n\targ_types = join_sep \"\\n\" (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"\\n\" ++ _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = join_sep \"\\n\" all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if those fail as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if that fails as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary'_function op a b\n\t= matches1?0, matches1 != []\n\t= matches2?0, op.symmetric && matches2 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0, matches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t// these should always be defined\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x = oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x = oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op = oo_unary_function (oo_unary_lookup op) this;\n\n\too_binary_table op x = [];\n\too_unary_table op = [];\n}\n"
  },
  {
    "path": "share/nip2/compat/8.2/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= Image x.value, is_Plot x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n// like to_image, but we do 1x1 pixel + x, then embed it up\n// always make an unwrapped image for speed ... this gets used by ifthenelse\n// and stuff like that\n// format can be NULL, meaning set format from x\nto_image_size width height bands format x\n\t= x, is_image x\n\t= x.value, is_Image x\n\t= im''\n{\n\t// we want x to set the target format if we don't have one, so we\n\t// can't use image_new\n\tim = im_black 1 1 bands + x;\n\tim'\n\t\t= clip2fmt format im, format != NULL\n\t\t= im;\n\tim'' = embed 1 0 0 width height im';\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && is_list_len 3 x\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\nto_int x = (int) (to_real x);\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The outermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x \n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), !is_list_len 2 parts \n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, !is_list_len 4 parts \n\t= sign * (abs ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", \n\t\tmember \".0123456789\",\n\t\tmember \"eE\", \n\t\tmember \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tsign \n\t\t= 1, ipart > 0\n\t\t= -1;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), !is_list_len 5 parts \n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t$D93 => D93_whitepoint,\n\t$D75 => D75_whitepoint,\n\t$D65 => D65_whitepoint,\n\t$D55 => D55_whitepoint,\n\t$D50 => D50_whitepoint,\n\t$A => A_whitepoint,\n\t$B => B_whitepoint,\n\t$C => C_whitepoint,\n\t$E => E_whitepoint,\n\t$D3250 => D3250_whitepoint\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, image_set_type GREY16 @ im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l = join_sep path_separator l;\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 > 1 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n"
  },
  {
    "path": "share/nip2/compat/8.2/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= embed 1 0 0 w h im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black 1 1 (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\nmkim options x y b\n    = Image (image_new x y b\n        (opt $format) (opt $coding) (opt $type)\n        (opt $pixel)\n        (opt $xoffset) (opt $yoffset))\n{\n    opt = get_option options [\n        $format => Image_format.UCHAR,\n        $coding => Image_coding.NOCODING,\n        $type => Image_type.sRGB,\n        $pixel => 0,\n        $xoffset => 0,\n        $yoffset => 0\n    ];\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = im_gauss_imask_sep (radius / 3) 0.2;\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n/* Make a colour from a temperature.\n */\ncolour_from_temp T\n\t= error (_ \"T out of range\"), T < 1667 || T > 25000\n\t= Colour \"Yxy\" [50, x, y]\n{\n\t// Kim et all approximation\n\t// see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation\n\tx\n\t\t= -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 +\n\t\t\t0.8776956 * 10 ** 3 / T + 0.179910, T < 4000\n\t\t= -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 +\n\t\t\t0.2226347 * 10 ** 3 / T + 0.240390;\n\n\ty \n\t\t= -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + \n\t\t\t2.18555832 * x - 0.20219638, T < 2222\n\t\t= -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + \n\t\t\t2.09137015 * x - 0.16748867, T < 4000\n\t\t=  3.0817580 * x ** 3 - 5.87338670 * x ** 2 +\n\t\t\t3.75112997 * x - 0.37001483;\n}\n\ntemp_from_colour z\n\t= T\n{\n\tc = colour_transform_to Image_type.YXY (to_colour z);\n\tx = c.value?1;\n\ty = c.value?2;\n\n\t// McCamy's approximation, see eg. \n\t// http://en.wikipedia.org/wiki/Color_temperature#Approximation\n\n\txe = 0.332;\n\tye = 0.1858;\n\tn = (x - xe) / (y - ye);\n\tT = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33;\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.2/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 1;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Interpolate_bilinear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" \n\t] 4;\n\n\tcontrol_selection mask im no\n\t\t= [\n\t\t\tif mask then im * 1.2 else im * 1,\n\t\t\tif mask then im * 0.8 else im * 1,\n\t\t\tif mask then 0 else im,\n\t\t\tif mask then 255 else im,\n\t\t\tif mask then im else 0,\n\t\t\tif mask then im else 255,\n\t\t\tmask\n\t\t]?no;\n\n\tRectangle = class\n        Menuaction \"_Rectangle\"\n            \"use an Arrow or Region x to define a rectangle\"\n        {\n        action x = class\n            _result {\n            _vislevel = 3;\n\n            control = _control;   \n\n            _result = control_selection mask im control\n                  {\n                \tim = x.image;\n                \tmask = Image m\n                    {\n\t\t\t\t\t\trx     \n\t\t\t\t\t\t\t= x.region_rect, is_Region x\n\t\t\t\t\t\t\t= x;\n\t\t\t\t\t\tb     = image_new im.width im.height 1 0 0 1 0 0 0;\n\t\t\t\t\t\tw     = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0;\n\t\t\t\t\t\tm     = insert_noexpand rx.nleft rx.ntop w b; \n                     }\n                   }\n            }\n        }\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = get_image a;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = get_image ((pt_list.value)?0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tSegment_item = class\n\t\tMenuaction \"_Segment\" \"break image into disjoint regions\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsegments\n\t\t\t\t= Expression \"Number of disjoint regions\" \n\t\t\t\t\t(map_unary (get_header \"n-segments\") _result);\n\n\t\t\t_result = map_unary segment x;\n\t\t}\n\t}\n\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize Interpolate_bilinear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize Interpolate_bilinear f1 1 b1\n\t\t\t\t\t{b1 = resize Interpolate_bilinear 1 f2 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/8.2/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = Image (get_image line);\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = Image (get_image (pt_l?0));\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t};\n\nMount_options _ctype _ppcm = class \n  {\n  _vislevel = 3;\n  apply = Toggle \"Apply mount options\" false;\n  ls = Expression \"Lower mount section bigger by (cm)\" 0;\n  mount_colour = Colour _ctype [0, 0, 0];\n  _los = ls.expr * _ppcm;\n  };\n\nFrame_variables comp = class\n  {\n  _vislevel = 3;\n\n  scale_factor = Expression \"scale the size of the frame by\" 1;\n\n  /* These sliders define the fraction of the frames width or height is extracted\n   * to produce each of the particular regions.\n   */\n  corner_section = Scale \"Corner section\" 0.1 1 0.5;\n  edge_section = Scale \"Edge section\" 0.1 1 0.2, comp > 0\n\t\t\t\t  = \"Only required for complex frames\";\n  middle_section = Scale \"Middle section\" 0.1 1 0.2;\n  blend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n  option = Toggle \"Use mirror of left-side to make right\" true;\n  };\n\n"
  },
  {
    "path": "share/nip2/compat/8.2/_list.def",
    "content": "/* any l: or all the elements of list l together\n *\n * any (map (equal 0) list) == true, if any element of list is zero.\n * any :: [bool] -> bool\n */\nany = foldr logical_or false;\n\n/* all l: and all the elements of list l together\n *\n * all (map (==0) list) == true, if every element of list is zero.\n * all :: [bool] -> bool\n */\nall = foldr logical_and true;\n\n/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* delete eq x l: delete the first x from l\n *\n * delete equal 'b' \"abcdb\" == \"acdb\"\n * delete :: (* -> bool) -> * -> [*] -> [*]\n */\ndelete eq a l\n\t= [], l == []\n\t= y, eq a b\n\t= b : delete eq a y\n{\n\tb:y = l;\n}\n\n/* difference eq a b: delete b from a\n *\n * difference equal \"asdf\" \"ad\" == \"sf\"\n * difference :: (* -> bool) -> [*] -> [*] -> [*]\n */\ndifference = foldl @ converse @ delete;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn x, fn a\n\t= l\n{\n\ta:x = l;\n}\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* flatten x: flatten a list of lists of things into a simple list\n *\n * flatten :: [[*]] -> [*]\n */\nflatten x\n\t= foldr flat [] x, is_list x\n\t= x\n{\n\tflat x sofar\n\t\t= foldr flat sofar x, is_list x\n\t\t= x : sofar;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st x) xs\n{\n\tx:xs = l;\n}\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn x xs\n{\n\tx:xs = l;\n}\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn x (foldr fn st xs)\n{\n\tx:xs = l;\n}\n\n/* foldr1 fn l: like foldr, but use the last element as the start value\n *\n * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= x, xs == []\n\t= fn x (foldr1 fn xs)\n{\n\tx:xs = l;\n}\n\n/* Search a list for an element, returning its index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn x\n\t\t= search xs (n + 1)\n\t\t{\n\t\t\tx:xs = l;\n\t\t}\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= x : init xs\n{\n\tx:xs = l;\n}\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* join_sep sep l: join a list with a separator\n *\n * join_sep \", \" (map print [1 .. 4]) == \"1, 2, 3, 4\"\n * join_sep :: [*] -> [[*]] -> [*]\n */\njoin_sep sep l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ sep ++ b;\n}\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= x, xs == []\n\t= last xs\n{\n\tx:xs = l;\n}\n\n/* len l: length of list l\n * (see also is_list_len and friends in predicate.def)\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta:b:x = l;\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = any (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge p l r\n\t= [], p == [] || l == [] || r == []\n\t= a : merge z x y, c\n\t= b : merge z x y\n{\n\ta:x = l;\n\tb:y = r;\n\tc:z = p;\n}\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta:x = l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scanl fn st l: apply (foldl fn r) to every initial segment of a list\n *\n * scanl add 0 [1,2,3] == [1,3,6]\n * scanl :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscanl fn st l\n\t= st, l == []\n\t= st' : scanl fn st' xs\n{\n\tx:xs = l;\n\tst' = fn st x;\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta:x = l1;\n\t\tb:y = l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/8.2/_magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate _magick.def\n\t Add 0-ary and 2-ary system\n\t Put utility funcs into a Magick class\n   11-Apr-2014 snibgo\n     Added VirtualPixelBack for cases where background is only relevant when VP=Background\n   17-Apr-2014 snibgo\n     Many small changes.\n   2-May-2014 jcupitt\n     Added Magick.version\n   30-June-2014\n   \t Put single-quotes around command exe to help win\n   1-July-2014\n     Automatically fall back to gm if we can't find convert\n   17-July-2014\n     better GM support\n\n\n   Last update: 17-July-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n\n*/\n\n/* Put these in a class to avoid filling the main namespace with IM stuff.\n */\n\nMagick = class {\n\n\t// turn $PATH into [[\"comp1\", \"comp2\"], [\"comp1\", \"comp2\"] ..]\n\tsystem_search_path\n\t\t= map path_parse (split (equal path_sep) (expand \"$PATH\"))\n\t{\n\t\tpath_sep\n\t\t\t= ':', expand \"$SEP\" == \"/\"\n\t\t\t= ';';\n\t}\n\n\t// the first name[.exe] on $PATH, or \"\"\n\tsearch_for name\n\t\t= hits?0, hits != []\n\t\t= \"\"\n\t{\n\t\texe_name = name ++ expand \"$EXEEXT\";\n\t\tform_path p = path_absolute (p ++ [exe_name]);\n\t\tpaths = map form_path system_search_path;\n\t\thits = dropwhile (equal []) (map search paths);\n\t}\n\n\t// first gm on path, or \"\"\n\tgm_path = search_for \"gm\";\n\n\t// first convert on $PATH, or \"\"\n\t// we check for the convert we ship first\n\tconvert_path \n\t\t= vips_convert, vips_convert != \"\"\n\t\t= search_for \"convert\"\n\t{\n\t\t// the convert we ship with the vips binary on some platforms, or \"\"\n\t\tvips_convert \n\t\t\t= search (path_absolute convert)\n\t\t{\n\t\t\tvipshome = path_parse (expand \"$VIPSHOME\");\n\t\t\tconvert = vipshome ++ [\"bin\", \"convert\" ++ expand \"$EXEEXT\"];\n\t\t}\n\t}\n\n\tuse_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK;\n\n\t// Are we in GM or IM mode? \n\tuse_gm \n\t\t= true, use_gm_pref && gm_path != \"\"\n\t\t= false, !use_gm_pref && convert_path != \"\"\n\t\t= false, convert_path != \"\"\n\t\t= true, gm_path != \"\"\n\t\t= error \"neither IM nor GM executable found\";\n\n\tcommand_path\n\t\t= gm_path, use_gm\n\t\t= convert_path;\n\n\t// try to get the version as eg. [6, 7, 7, 10]\n\t// GM versions are smaller, typically [1, 3, 18]\n\tversion\n\t\t= map parse_int (split (member \".-\") version_string)\n\t{\n\t\t[output] = vips_call \"system\" \n\t\t\t[\"'\" ++ command_path ++ \"' -version\"] [$log=>true];\n\t\tversion_string \n\t\t\t= (split (equal ' ') output)?1, use_gm\n\t\t\t= (split (equal ' ') output)?2;\n\t}\n\n\t// make a command-line ... args is a [str] we join with spaces\n\tcommand args \n\t\t= \"'\" ++ command_path ++ \"' \" ++ join_sep \" \" args'\n\t{\n\t\targs'\n\t\t\t= [\"convert\"] ++ args, use_gm\n\t\t\t= args;\n\t}\n\n\t// capabilities ... different versions support different features, we \n\t// turn features on and off based on these\n\n\t// would probably be better to test for caps somehow\n\thas_intensity\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\thas_channel\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\n\tsystem0 cmd = system_image0 cmd;\n\tsystem cmd x = map_unary (system_image cmd) x;\n\tsystem2 cmd x y = map_binary (system_image2 cmd) x y;\n\tsystem3 cmd x y z = map_trinary (system_image3 cmd) x y z;\n\n\tradius_widget = Scale \"Radius\" 0 100 10;\n\tsigma_widget = Scale \"Sigma\" 0.1 10 1;\n\tangle_widget = Scale \"Angle (degrees)\" (-360) 360 0;\n\ttext_widget = String \"Text to draw\" \"AaBbCcDdEe\";\n\n\tgamma_widget = Scale \"Gamma\" 0 10 1;\n\tcolors_widget = Scale \"Colors\" 1 10 3;\n\tresize_widget = Scale \"Resize (percent)\" 0 500 100;\n\tfuzz_widget = Scale \"Fuzz (percent)\" 0 100 0;\n\tblur_rad_widget = Scale \"Radius (0=auto)\" 0 100 0;\n\n\t// a colour with no enclosing quotes ... use this if we know there are\n\t// some quotes at an outer level\n\tprint_colour_nq triple\n\t\t= concat [\"#\", concat (map fmt triple)]\n\t{\n\t\tfmt x = reverse (take 2 (reverse (print_base 16 (x + 256))));\n\t}\n\n\t// we need the quotes because # is the comment character in *nix\n\tprint_colour triple = \"\\\"\" ++ print_colour_nq triple ++ \"\\\"\";\n\n\tForeground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-fill \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Foreground triple;\n\t}\n\tforeground_widget = Foreground [0, 0, 0];\n\n\tGeneralCol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = print_colour_nq triple;\n\n\t\tColour_edit space triple = this.GeneralCol triple;\n\t}\n\tgeneralcol_widget = GeneralCol [0, 0, 0];\n\n\tBackground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" false;\n\n\t\t_flag = \"-background \" ++ if isNone then \"None\" else print_colour triple;\n\n\t\tColour_edit space triple = this.Background triple;\n\t}\n\tbackground_widget = Background [255, 255, 255];\n\n\tBordercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-bordercolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Bordercol triple;\n\t}\n\tbordercol_widget = Bordercol [0, 0, 0];\n\n\tMattecol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-mattecolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Mattecol triple;\n\t}\n\tmattecol_widget = Mattecol [189, 189, 189];\n\n\t// FIXME: Undercolour, like many others, can have alpha channel.\n\t// How does user input this? With a slider?\n\tUndercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" true;\n\n\t\t_flag = if isNone then \"\" else (\"-undercolor \" ++ print_colour triple);\n\n\t\tColour_edit space triple = this.Undercol triple;\n\t}\n\tundercol_widget = Undercol [0, 0, 0];\n\n\tchangeCol_widget = class {\n\t\t_vislevel = 3;\n\n\t\tcolour = GeneralCol [0, 0, 0];\n\t\tfuzz = fuzz_widget;\n\t\tnonMatch = Toggle \"change non-matching colours\" false;\n\t}\n\n\tAlpha alpha = class\n\t\tOption_string \"Alpha\" [\n\t\t\t\"On\", \n\t\t\t\"Off\", \n\t\t\t\"Set\", \n\t\t\t\"Opaque\", \n\t\t\t\"Transparent\", \n\t\t\t\"Extract\", \n\t\t\t\"Copy\", \n\t\t\t\"Shape\", \n\t\t\t\"Remove\", \n\t\t\t\"Background\"\n\t\t] alpha {\n\n\t\t_flag = \"-alpha \" ++ alpha;\n\n\t\tOption_edit caption labels value = this.Alpha labels?value;\n\t}\n\talpha_widget = Alpha \"On\";\n\n\tAntialias value = class\n\t\tToggle \"Antialias\" value {\n\n\t\t_flag\n\t\t\t= \"-antialias\", value\n\t\t\t= \"+antialias\";\n\n\t\tToggle_edit caption value = this.Antialias value;\n\t}\n\tantialias_widget = Antialias true;\n\n\tBuiltin builtin = class\n\t\tOption_string \"Builtin\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"rose:\",\n\t\t\t\"logo:\",\n\t\t\t\"wizard:\",\n\t\t\t\"granite:\",\n\t\t\t\"netscape:\"\n\t\t] builtin {\n\n\t\t_flag = builtin;\n\n\t\tOption_edit caption labels value = this.Builtin labels?value;\n\t}\n\tbuiltin_widget = Builtin \"rose:\";\n\n\n\tchannels_widget = class {\n\t\t// FIXME? Can we grey-out alpha when we have no alpha channel,\n\t\t//        show CMY(K) instead of RGB(K) etc?\n\t\t// Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA.\n\t\tChanR valueR = class\n\t\t\tToggle \"Red\" valueR {\n\n\t\t\t_flag\n\t\t\t\t= \"R\", valueR\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueR = this.ChanR valueR;\n\t\t}\n\t\tchannelR = ChanR true;\n\n\t\tChanG valueG = class\n\t\t\tToggle \"Green\" valueG {\n\n\t\t\t_flag\n\t\t\t\t= \"G\", valueG\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueG = this.ChanG valueG;\n\t\t}\n\t\tchannelG = ChanG true;\n\n\t\tChanB valueB = class\n\t\t\tToggle \"Blue\" valueB {\n\n\t\t\t_flag\n\t\t\t\t= \"B\", valueB\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueB = this.ChanB valueB;\n\t\t}\n\t\tchannelB = ChanB true;\n\n\t\tChanK valueK = class\n\t\t\tToggle \"Black\" valueK {\n\n\t\t\t_flag\n\t\t\t\t= \"K\", valueK\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueK = this.ChanK valueK;\n\t\t}\n\t\tchannelK = ChanK true;\n\n\t\tChanA valueA = class\n\t\t\tToggle \"Alpha\" valueA {\n\n\t\t\t_flag\n\t\t\t\t= \"A\", valueA\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueA = this.ChanA valueA;\n\t\t}\n\t\tchannelA = ChanA false;\n\n\t\tChanSy valueSy = class\n\t\t\tToggle \"Sync\" valueSy {\n\n\t\t\t_flag\n\t\t\t\t= \",sync\", valueSy\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueSy = this.ChanSy valueSy;\n\t\t}\n\t\tchannelSy = ChanSy true;\n\n\t\t_rgbka = concat [channelR._flag,\n\t\t\t\tchannelG._flag,\n\t\t\t\tchannelB._flag,\n\t\t\t\tchannelK._flag,\n\t\t\t\tchannelA._flag\n\t\t\t];\n\n\t\t_flag\n\t\t\t= \"\", _rgbka == \"\" || !has_channel\n\t\t\t= concat [ \"-channel \",\n\t\t\t\t_rgbka,\n\t\t\t\tchannelSy._flag \n\t\t\t\t];\n\t}\n\n\tch_widget = channels_widget;\n\n\tColorspace colsp = class\n\t\tOption_string \"Colorspace\" [\n\t\t\t\"CIELab\",\n\t\t\t\"CMY\",\n\t\t\t\"CMYK\",\n\t\t\t\"Gray\",\n\t\t\t\"HCL\",\n\t\t\t\"HCLp\",\n\t\t\t\"HSB\",\n\t\t\t\"HSI\",\n\t\t\t\"HSL\",\n\t\t\t\"HSV\",\n\t\t\t\"HWB\",\n\t\t\t\"Lab\",\n\t\t\t\"LCH\",\n\t\t\t\"LCHab\",\n\t\t\t\"LCHuv\",\n\t\t\t\"LMS\",\n\t\t\t\"Log\",\n\t\t\t\"Luv\",\n\t\t\t\"OHTA\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601YCbCr\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709YCbCr\",\n\t\t\t\"RGB\",\n\t\t\t\"scRGB\",\n\t\t\t\"sRGB\",\n\t\t\t\"Transparent\",\n\t\t\t\"XYZ\",\n\t\t\t\"YCbCr\",\n\t\t\t\"YDbDr\",\n\t\t\t\"YCC\",\n\t\t\t\"YIQ\",\n\t\t\t\"YPbPr\",\n\t\t\t\"YUV\"\n\t\t] colsp {\n\n\t\t_flag = colsp;\n\n\t\tOption_edit caption labels value = this.Colorspace labels?value;\n\t}\n\tcolorspace_widget = Colorspace \"sRGB\";\n\n\tCompose comp = class\n\t\tOption_string \"Compose method\" [\n\t\t\t\"Atop\", \n\t\t\t\"Blend\", \n\t\t\t\"Blur\", \n\t\t\t\"Bumpmap\", \n\t\t\t\"ChangeMask\", \n\t\t\t\"Clear\", \n\t\t\t\"ColorBurn\", \n\t\t\t\"ColorDodge\", \n\t\t\t\"Colorize\", \n\t\t\t\"CopyBlack\", \n\t\t\t\"CopyBlue\", \n\t\t\t\"CopyCyan\", \n\t\t\t\"CopyGreen\", \n\t\t\t\"Copy\", \n\t\t\t\"CopyMagenta\", \n\t\t\t\"CopyOpacity\", \n\t\t\t\"CopyRed\", \n\t\t\t\"CopyYellow\", \n\t\t\t\"Darken\", \n\t\t\t\"DarkenIntensity\", \n\t\t\t\"DivideDst\", \n\t\t\t\"DivideSrc\", \n\t\t\t\"Dst\", \n\t\t\t\"Difference\", \n\t\t\t\"Displace\", \n\t\t\t\"Dissolve\", \n\t\t\t\"Distort\", \n\t\t\t\"DstAtop\", \n\t\t\t\"DstIn\", \n\t\t\t\"DstOut\", \n\t\t\t\"DstOver\", \n\t\t\t\"Exclusion\", \n\t\t\t\"HardLight\", \n\t\t\t\"Hue\", \n\t\t\t\"In\", \n\t\t\t\"Lighten\", \n\t\t\t\"LightenIntensity\", \n\t\t\t\"LinearBurn\", \n\t\t\t\"LinearDodge\", \n\t\t\t\"LinearLight\", \n\t\t\t\"Luminize\", \n\t\t\t\"Mathematics\", \n\t\t\t\"MinusDst\", \n\t\t\t\"MinusSrc\", \n\t\t\t\"Modulate\", \n\t\t\t\"ModulusAdd\", \n\t\t\t\"ModulusSubtract\", \n\t\t\t\"Multiply\", \n\t\t\t\"None\", \n\t\t\t\"Out\", \n\t\t\t\"Overlay\", \n\t\t\t\"Over\", \n\t\t\t\"PegtopLight\", \n\t\t\t\"PinLight\", \n\t\t\t\"Plus\", \n\t\t\t\"Replace\", \n\t\t\t\"Saturate\", \n\t\t\t\"Screen\", \n\t\t\t\"SoftLight\", \n\t\t\t\"Src\", \n\t\t\t\"SrcAtop\", \n\t\t\t\"SrcIn\", \n\t\t\t\"SrcOut\", \n\t\t\t\"SrcOver\", \n\t\t\t\"VividLight\", \n\t\t\t\"Xor\"\n\t\t] comp {\n\n\t\t_flag = \"-compose \" ++ comp;\n\n\t\tOption_edit caption labels value = this.Compose labels?value;\n\t}\n\tcompose_widget = Compose \"Over\";\n\t// FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string.\n\n\t// FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack\n\n\tcoordinate_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\n\t\t_flag = concat [print x.expr, \",\", print y.expr];\n\t};\n\n\tDistort distort = class\n\t\tOption_string \"Distort\" [\n\t\t\t\"Affine\",\n\t\t\t\"AffineProjection\",\n\t\t\t\"ScaleRotateTranslate\",\n\t\t\t\"SRT\",\n\t\t\t\"Perspective\",\n\t\t\t\"PerspectiveProjection\",\n\t\t\t\"BilinearForward\",\n\t\t\t\"BilinearReverse\",\n\t\t\t\"Polynomial\",\n\t\t\t\"Arc\",\n\t\t\t\"Polar\",\n\t\t\t\"DePolar\",\n\t\t\t\"Barrel\",\n\t\t\t\"BarrelInverse\",\n\t\t\t\"Shepards\",\n\t\t\t\"Resize\"\n\t\t] distort {\n\n\t\t_flag = distort;\n\n\t\tOption_edit caption labels value = this.Distort labels?value;\n\t}\n\tdistort_widget = Distort \"SRT\";\n\n\tDither dither = class\n\t\tOption_string \"Dither\" [\n\t\t\t\"None\",\n\t\t\t\"FloydSteinberg\",\n\t\t\t\"Riemersma\"\n\t\t] dither {\n\n\t\t_flag = \"-dither \" ++ dither;\n\n\t\tOption_edit caption labels value = this.Dither labels?value;\n\t}\n\tdither_widget = Dither \"FloydSteinberg\";\n\n\tEvaluate eval = class\n\t\tOption_string \"Evaluate operation\" [\n\t\t\t\"Abs\",\n\t\t\t\"Add\",\n\t\t\t\"AddModulus\",\n\t\t\t\"And\",\n\t\t\t\"Cos\",\n\t\t\t\"Cosine\",\n\t\t\t\"Divide\",\n\t\t\t\"Exp\",\n\t\t\t\"Exponential\",\n\t\t\t\"GaussianNoise\",\n\t\t\t\"ImpulseNoise\",\n\t\t\t\"LaplacianNoise\",\n\t\t\t\"LeftShift\",\n\t\t\t\"Log\",\n\t\t\t\"Max\",\n\t\t\t\"Mean\",\n\t\t\t\"Median\",\n\t\t\t\"Min\",\n\t\t\t\"MultiplicativeNoise\",\n\t\t\t\"Multiply\",\n\t\t\t\"Or\",\n\t\t\t\"PoissonNoise\",\n\t\t\t\"Pow\",\n\t\t\t\"RightShift\",\n\t\t\t\"Set\",\n\t\t\t\"Sin\",\n\t\t\t\"Sine\",\n\t\t\t\"Subtract\",\n\t\t\t\"Sum\",\n\t\t\t\"Threshold\",\n\t\t\t\"ThresholdBlack\",\n\t\t\t\"ThresholdWhite\",\n\t\t\t\"UniformNoise\",\n\t\t\t\"Xor\"\n\t\t] eval {\n\n\t\t_flag = \"-evaluate \" ++ eval;\n\n\t\tOption_edit caption labels value = this.Evaluate labels?value;\n\t}\n\tevaluate_widget = Evaluate \"Add\";\n\n\tFilter filt = class\n\t\tOption_string \"Filter\" [\n\t\t\t\"default\",\n\t\t\t\"Bartlett\",\n\t\t\t\"Blackman\",\n\t\t\t\"Bohman\",\n\t\t\t\"Box\",\n\t\t\t\"Catrom\",\n\t\t\t\"Cosine\",\n\t\t\t\"Cubic\",\n\t\t\t\"Gaussian\",\n\t\t\t\"Hamming\",\n\t\t\t\"Hann\",\n\t\t\t\"Hermite\",\n\t\t\t\"Jinc\",\n\t\t\t\"Kaiser\",\n\t\t\t\"Lagrange\",\n\t\t\t\"Lanczos\",\n\t\t\t\"Lanczos2\",\n\t\t\t\"Lanczos2Sharp\",\n\t\t\t\"LanczosRadius\",\n\t\t\t\"LanczosSharp\",\n\t\t\t\"Mitchell\",\n\t\t\t\"Parzen\",\n\t\t\t\"Point\",\n\t\t\t\"Quadratic\",\n\t\t\t\"Robidoux\",\n\t\t\t\"RobidouxSharp\",\n\t\t\t\"Sinc\",\n\t\t\t\"SincFast\",\n\t\t\t\"Spline\",\n\t\t\t\"Triangle\",\n\t\t\t\"Welch\"\n\t\t] filt {\n\n\t\t_flag = if filt == \"default\" then \"\" else \"-filter \" ++ filt;\n\n\t\tOption_edit caption labels value = this.Filter labels?value;\n\t}\n\tfilter_widget = Filter \"default\";\n\n\tFunction func = class\n\t\tOption_string \"Function\" [\n\t\t\t\"Polynomial\",\n\t\t\t\"Sinusoid\",\n\t\t\t\"Arcsin\",\n\t\t\t\"Arctan\"\n\t\t] func {\n\n\t\t_flag = func;\n\n\t\tOption_edit caption labels value = this.Function labels?value;\n\t}\n\tfunction_widget = Function \"Polynomial\";\n\n//  \"Polynomial (a[n], a[n-1], ... a[1], a[0])\",\n//  \"Sinusoid (freq, phase, amp, bias)\",\n//  \"Arcsin (width, centre, range, bias)\",\n//  \"Arctan (slope, centre, range, bias)\"\n\n\tGravity gravity = class\n\t\tOption_string \"Gravity\" [\n\t\t\t\"None\",\n\t\t\t\"Center\",\n\t\t\t\"East\",\n\t\t\t\"Forget\",\n\t\t\t\"NorthEast\",\n\t\t\t\"North\",\n\t\t\t\"NorthWest\",\n\t\t\t\"SouthEast\",\n\t\t\t\"South\",\n\t\t\t\"SouthWest\",\n\t\t\t\"West\",\n\t\t\t\"Static\"\n\t\t] gravity {\n\n\t\t_flag = \"-gravity \" ++ gravity;\n\n\t\tOption_edit caption labels value = this.Gravity labels?value;\n\t}\n\tgravity_widget = Gravity \"Center\";\n\n\tImageType imagetype = class\n\t\tOption_string \"Image type\" [\n\t\t\t\"Bilevel\",\n\t\t\t\"ColorSeparation\",\n\t\t\t\"ColorSeparationAlpha\",\n\t\t\t\"ColorSeparationMatte\",\n\t\t\t\"Grayscale\",\n\t\t\t\"GrayscaleAlpha\",\n\t\t\t\"GrayscaleMatte\",\n\t\t\t\"Optimize\",\n\t\t\t\"Palette\",\n\t\t\t\"PaletteBilevelAlpha\",\n\t\t\t\"PaletteBilevelMatte\",\n\t\t\t\"PaletteAlpha\",\n\t\t\t\"PaletteMatte\",\n\t\t\t\"TrueColorAlpha\",\n\t\t\t\"TrueColorMatte\",\n\t\t\t\"TrueColor\"\n\t\t] imagetype {\n\n\t\t_flag = \"-type \" ++ imagetype;\n\n\t\tOption_edit caption labels value = this.ImageType labels?value;\n\t}\n\timagetype_widget = ImageType \"TrueColor\";\n\n\tIntensity intensity = class\n\t\tOption_string \"Intensity (gray conversion)\" [\n\t\t\t\"Average\",\n\t\t\t\"Brightness\",\n\t\t\t\"Lightness\",\n\t\t\t\"MS\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601Luminance\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709Luminance\",\n\t\t\t\"RMS\"\n\t\t] intensity {\n\n\t\t_flag \n\t\t\t= \"-intensity \" ++ intensity, has_intensity\n\t\t\t= \"\";\n\n\t\tOption_edit caption labels value = this.Intensity labels?value;\n\t}\n\tintensity_widget = Intensity \"Rec709Luminance\";\n\n\tInterpolate interp = class\n\t\tOption_string \"Interpolate\" [\n\t\t\t\"default\",\n\t\t\t\"Average\",\n\t\t\t\"Average4\",\n\t\t\t\"Average9\",\n\t\t\t\"Average16\",\n\t\t\t\"Background\",\n\t\t\t\"Bilinear\",\n\t\t\t\"Blend\",\n\t\t\t\"Integer\",\n\t\t\t\"Mesh\",\n\t\t\t\"Nearest\",\n\t\t\t\"NearestNeighbor\",\n\t\t\t\"Spline\"\n\t\t] interp {\n\n\t\t_flag = if interp == \"default\" then \"\" else \"-interpolate \" ++ interp;\n\n\t\tOption_edit caption labels value = this.Interpolate labels?value;\n\t}\n\tinterpolate_widget = Interpolate \"default\";\n\n\tKernel kernel = class\n\t\tOption_string \"Kernel\" [\n\t\t\t\"Unity\",\n\t\t\t\"Gaussian\",\n\t\t\t\"DoG\",\n\t\t\t\"LoG\",\n\t\t\t\"Blur\",\n\t\t\t\"Comet\",\n\t\t\t\"Binomial\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Sobel\",\n\t\t\t\"FreiChen\",\n\t\t\t\"Roberts\",\n\t\t\t\"Prewitt\",\n\t\t\t\"Compass\",\n\t\t\t\"Kirsch\",\n\t\t\t\"Diamond\",\n\t\t\t\"Square\",\n\t\t\t\"Rectangle\",\n\t\t\t\"Disk\",\n\t\t\t\"Octagon\",\n\t\t\t\"Plus\",\n\t\t\t\"Cross\",\n\t\t\t\"Ring\",\n\t\t\t\"Peaks\",\n\t\t\t\"Edges\",\n\t\t\t\"Corners\",\n\t\t\t\"Diagonals\",\n\t\t\t\"LineEnds\",\n\t\t\t\"LineJunctions\",\n\t\t\t\"Ridges\",\n\t\t\t\"ConvexHull\",\n\t\t\t\"ThinSe\",\n\t\t\t\"Skeleton\",\n\t\t\t\"Chebyshev\",\n\t\t\t\"Manhattan\",\n\t\t\t\"Octagonal\",\n\t\t\t\"Euclidean\"\n\t\t\t// FIXME: custom kernel\n\t\t] kernel {\n\n\t\t_flag = kernel;\n\n\t\tOption_edit caption labels value = this.Kernel labels?value;\n\t}\n\tkernel_widget = Kernel \"Unity\";\n\n\tModColSp msp = class\n\t\tOption_string \"modulate colorspace\" [\n\t\t\t\"HCL\", \n\t\t\t\"HCLp\", \n\t\t\t\"HSB\", \n\t\t\t\"HSI\", \n\t\t\t\"HSL\", \n\t\t\t\"HSV\", \n\t\t\t\"HWB\", \n\t\t\t\"LCH\"\n\t\t] msp {\n\n\t\t_flag = \"-set option:modulate:colorspace \" ++ msp;\n\n\t\tOption_edit caption labels value = this.ModColSp labels?value;\n\t}\n\tModColSp_widget = ModColSp \"HSL\";\n\n\tMorphMeth morph = class\n\t\tOption_string \"Method\" [\n\t\t\t\"Correlate\",\n\t\t\t\"Convolve\",\n\t\t\t\"Dilate\",\n\t\t\t\"Erode\",\n\t\t\t\"Close\",\n\t\t\t\"Open\",\n\t\t\t\"DilateIntensity\",\n\t\t\t\"ErodeIntensity\",\n\t\t\t\"CloseIntensity\",\n\t\t\t\"OpenIntensity\",\n\t\t\t\"Smooth\",\n\t\t\t\"EdgeOut\",\n\t\t\t\"EdgeIn\",\n\t\t\t\"Edge\",\n\t\t\t\"TopHat\",\n\t\t\t\"BottomHat\",\n\t\t\t\"HitAndMiss\",\n\t\t\t\"Thinning\",\n\t\t\t\"Thicken\",\n\t\t\t\"Distance\",\n\t\t\t\"IterativeDistance\"\n\t\t] morph {\n\n\t\t_flag = morph;\n\n\t\tOption_edit caption labels value = this.MorphMeth labels?value;\n\t}\n\tmorphmeth_widget = MorphMeth \"Dilate\";\n\n\tNoise noise = class\n\t\tOption_string \"Noise\" [\n\t\t\t\"Gaussian\",\n\t\t\t\"Impulse\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Multiplicative\",\n\t\t\t\"Poisson\",\n\t\t\t\"Random\",\n\t\t\t\"Uniform\"\n\t\t] noise {\n\n\t\t_flag = \"+noise \" ++ noise;\n\n\t\tOption_edit caption labels value = this.Noise labels?value;\n\t}\n\tnoise_widget = Noise \"Gaussian\";\n\n\tPattern pattern = class\n\t\tOption_string \"Noise\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"bricks\",\n\t\t\t\"checkerboard\",\n\t\t\t\"circles\",\n\t\t\t\"crosshatch\",\n\t\t\t\"crosshatch30\",\n\t\t\t\"crosshatch45\",\n\t\t\t\"gray0\",\n\t\t\t\"gray5\",\n\t\t\t\"gray10\",\n\t\t\t\"gray15\",\n\t\t\t\"gray20\",\n\t\t\t\"gray25\",\n\t\t\t\"gray30\",\n\t\t\t\"gray35\",\n\t\t\t\"gray40\",\n\t\t\t\"gray45\",\n\t\t\t\"gray50\",\n\t\t\t\"gray55\",\n\t\t\t\"gray60\",\n\t\t\t\"gray65\",\n\t\t\t\"gray70\",\n\t\t\t\"gray75\",\n\t\t\t\"gray80\",\n\t\t\t\"gray85\",\n\t\t\t\"gray90\",\n\t\t\t\"gray95\",\n\t\t\t\"gray100\",\n\t\t\t\"hexagons\",\n\t\t\t\"horizontal\",\n\t\t\t\"horizontal2\",\n\t\t\t\"horizontal3\",\n\t\t\t\"horizontalsaw\",\n\t\t\t\"hs_bdiagonal\",\n\t\t\t\"hs_cross\",\n\t\t\t\"hs_diagcross\",\n\t\t\t\"hs_fdiagonal\",\n\t\t\t\"hs_horizontal\",\n\t\t\t\"hs_vertical\",\n\t\t\t\"left30\",\n\t\t\t\"left45\",\n\t\t\t\"leftshingle\",\n\t\t\t\"octagons\",\n\t\t\t\"right30\",\n\t\t\t\"right45\",\n\t\t\t\"rightshingle\",\n\t\t\t\"smallfishscales\",\n\t\t\t\"vertical\",\n\t\t\t\"vertical2\",\n\t\t\t\"vertical3\",\n\t\t\t\"verticalbricks\",\n\t\t\t\"verticalleftshingle\",\n\t\t\t\"verticalrightshingle\",\n\t\t\t\"verticalsaw\"\n\t\t] pattern {\n\n\t\t_flag = \"pattern:\" ++ pattern;\n\n\t\tOption_edit caption labels value = this.Pattern labels?value;\n\t}\n\tpattern_widget = Pattern \"bricks\";\n\n\tResizeType resizet = class\n\t\tOption_string \"Resize type\" [\n\t\t\t\"resize\", \n\t\t\t\"scale\",\n\t\t\t\"sample\",\n\t\t\t\"adaptive-resize\"\n\t\t] resizet {\n\n\t\t_flag = resizet;\n\n\t\tOption_edit caption labels value = this.ResizeType labels?value;\n\t}\n\tResizeType_widget = ResizeType \"resize\";\n\n\tSize_widget = class {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width (pixels)\" 64;\n\t\theight = Expression \"Height (pixels)\" 64;\n\n\t\t_flag = \"-size \" ++\n\t\t\tprint width.expr ++ \"x\" ++ print height.expr;\n\n\t};\n\n\tStatType statt = class\n\t\tOption_string \"Statistic type\" [\n\t\t\t\"Gradient\", \n\t\t\t\"Maximum\", \n\t\t\t\"Mean\", \n\t\t\t\"Median\", \n\t\t\t\"Minimum\", \n\t\t\t\"Mode\", \n\t\t\t\"Nonpeak\", \n\t\t\t\"StandardDeviation\"\n\t\t] statt {\n\n\t\t_flag = statt;\n\n\t\tOption_edit caption labels value = this.StatType labels?value;\n\t}\n\tStatType_widget = StatType \"Mean\";\n\n\tVirtualPixel vp = class\n\t\tOption_string \"Virtual pixel\" [\n\t\t\t\"Background\", \n\t\t\t\"Black\", \n\t\t\t\"CheckerTile\", \n\t\t\t\"Dither\", \n\t\t\t\"Edge\", \n\t\t\t\"Gray\", \n\t\t\t\"HorizontalTile\", \n\t\t\t\"HorizontalTileEdge\", \n\t\t\t\"Mirror\", \n\t\t\t\"None\",\n\t\t\t\"Random\",\n\t\t\t\"Tile\",\n\t\t\t\"Transparent\",\n\t\t\t\"VerticalTile\",\n\t\t\t\"VerticalTileEdge\",\n\t\t\t\"White\"\n\t\t] vp {\n\n\t\t_flag = \"-virtual-pixel \" ++ vp;\n\n\t\t_isBackground = (vp == \"Background\");\n\n\t\tOption_edit caption labels value = this.VirtualPixel labels?value;\n\t}\n\tVirtualPixel_widget = VirtualPixel \"Edge\";\n\n\tVirtualPixelBack_widget = class {\n\t\tvirtpix = Magick.VirtualPixel_widget;\n\t\tbackground = Magick.background_widget;\n\t\t_flag = (if virtpix._isBackground then (background._flag ++ \" \") else \"\")\n\t\t\t++ virtpix._flag;\n\t}\n\n\tGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tAnnotGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print shearX.expr, \"x\", print shearY.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tOffsetGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag = concat [format hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tWhxyGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFrameGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\toutbev = Expression \"Outer bevel thickness\" 0;\n\t\tinbev = Expression \"Inner bevel thickness\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat outbev, format inbev]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFont_widget = class {\n\t\t_vislevel = 3;\n\n\t\tfamily = Option_string \"Family\" [\n\t\t\t\"Arial\",\n\t\t\t\"ArialBlack\",\n\t\t\t\"AvantGarde\",\n\t\t\t\"BitstreamCharter\",\n\t\t\t\"Bookman\",\n\t\t\t\"CenturySchoolbook\",\n\t\t\t\"ComicSansMS\",\n\t\t\t\"Courier\",\n\t\t\t\"CourierNew\",\n\t\t\t\"DejaVuSans\",\n\t\t\t\"DejaVuSansMono\",\n\t\t\t\"DejaVuSerif\",\n\t\t\t\"Dingbats\",\n\t\t\t\"FreeMono\",\n\t\t\t\"FreeSans\",\n\t\t\t\"FreeSerif\",\n\t\t\t\"Garuda\",\n\t\t\t\"Georgia\",\n\t\t\t\"Helvetica\",\n\t\t\t\"HelveticaNarrow\",\n\t\t\t\"Impact\",\n\t\t\t\"LiberationMono\",\n\t\t\t\"LiberationSans\",\n\t\t\t\"LiberationSerif\",\n\t\t\t\"NewCenturySchlbk\",\n\t\t\t\"Palatino\",\n\t\t\t\"Purisa\",\n\t\t\t\"Symbol\",\n\t\t\t\"Times\",\n\t\t\t\"TimesNewRoman\",\n\t\t\t\"Ubuntu\",\n\t\t\t\"Verdana\",\n\t\t\t\"Webdings\"\n\t\t] \"Arial\";\n\t\tstyle = Option_string \"Style\" [\n\t\t\t\"Any\", \"Italic\", \"Normal\", \"Oblique\"\n\t\t] \"Normal\";\n\t\tweight = Scale \"Weight\" 1 800 400;\n\t\tsize = Scale \"Point size\" 1 100 12;\n\t\tstretch = Option_string \"Stretch\" [\n\t\t\t\"Any\", \"Condensed\", \"Expanded\", \"ExtraCondensed\", \"ExtraExpanded\", \n\t\t\t\"Normal\", \"SemiCondensed\", \"SemiExpanded\", \"UltraCondensed\", \n\t\t\t\"UltraExpanded\"\n\t\t] \"Normal\";\n\n\t\t_flag = join_sep \" \" [\n\t\t\t\t\"-family\", family.item,\n\t\t\t\t\"-weight\", print weight.value,\n\t\t\t\t\"-pointsize\", print size.value,\n\t\t\t\t\"-style\", style.item,\n\t\t\t\t\"-stretch\", stretch.item];\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.2/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = any (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && all (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* Test list length ... quicker than len x == n for large lists.\n */\nis_list_len n x\n\t= true, x == [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len (n - 1) (tl x);\n\nis_list_len_more n x\n\t= true, x != [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len_more (n - 1) (tl x);\n\nis_list_len_more_equal n x\n\t= true, n == 0\n\t= false, x == [] \n\t= is_list_len_more_equal (n - 1) (tl x);\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, all (map is_obj l)\n\t= true, all (map is_list l) &&\n\t\tall (map (not @ is_obj) l) &&\n\t\tall (map is_rectangular l) &&\n\t\tis_list_len_more 0 l &&\n\t\tall (map (is_list_len (len (hd l))) (tl l))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && is_list_len (len (hd l)) l;\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_NULL x = is_instanceof \"NULL\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Plot x = is_instanceof \"Plot\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && all (map xy l)\n{\n\txy l = is_real_list l && is_list_len 2 l;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && any (map is_Group l)\n\t= any (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= oo_unary_function get_type_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_type\")\n{\n\tget_type_op = Operator \"get_type\" get_type \n\t\tOperator_type.COMPOUND false;\n\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\t// can have alpha, hence we let bands be one more than you might think\n\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.GREY16, type == Image_type.GREY16 && is_bands 1\n\t\t= Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && \n\t\t\t(width == 1 || height == 1)\n\t\t= Image_type.B_W, is_bands 1 \n\t\t= Image_type.CMYK, type == Image_type.CMYK && is_bands 4\n\t\t= type, is_colorimetric && is_bands 3\n\t\t= Image_type.sRGB, !is_colorimetric && is_bands 3\n\t\t= Image_type.MULTIBAND, !is_colorimetric && !is_bands 3\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\n\t\t// is bands n, with an optional alpha (ie. can be n + 1 too)\n\t\tis_bands n = bands == n || bands == n + 1;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= oo_unary_function get_format_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_format\")\n{\n\tget_format_op = Operator \"get_format\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= oo_unary_function get_bits_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bits\")\n{\n\tget_bits_op = Operator \"get_bits\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= oo_unary_function get_bands_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bands\")\n{\n\tget_bands_op = Operator \"get_bands\" get_bands \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= oo_unary_function get_coding_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_coding\")\n{\n\tget_coding_op = Operator \"get_coding\" get_coding \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= oo_unary_function get_xres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xres\")\n{\n\tget_xres_op = Operator \"get_xres\" get_xres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= oo_unary_function get_yres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yres\")\n{\n\tget_yres_op = Operator \"get_yres\" get_yres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= oo_unary_function get_xoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xoffset\")\n{\n\tget_xoffset_op = Operator \"get_xoffset\" get_xoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= oo_unary_function get_yoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yoffset\")\n{\n\tget_yoffset_op = Operator \"get_yoffset\" get_yoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= oo_unary_function get_image_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_image\")\n{\n\tget_image_op = Operator \"get_image\" get_image \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= oo_unary_function get_number_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_number\")\n{\n\tget_number_op = Operator \"get_number\" get_number \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= oo_unary_function get_real_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_real\")\n{\n\tget_real_op = Operator \"get_real\" get_real \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= oo_unary_function get_width_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_width\")\n{\n\tget_width_op = Operator \"get_width\" get_width \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= oo_unary_function get_height_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_height\")\n{\n\tget_height_op = Operator \"get_height\" get_height \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= oo_unary_function get_left_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_left\")\n{\n\tget_left_op = Operator \"get_left\" get_left \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= oo_unary_function get_top_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_top\")\n{\n\tget_top_op = Operator \"get_top\" get_top \n\t\tOperator_type.COMPOUND false;\n}\n\n// like has/get member, but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.2/_stdenv.def",
    "content": "/* optional args to functions\n */\n\nget_option options defaults f\n\t= error (_ \"unknown parameter \" ++ f), hits == []\n\t= hits?0\n{\n\thits = [v :: [n, v] <- options ++ defaults; n == f];\n}\n\n/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\nidivide a b = (int) ((int) a / (int) b);\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\n// 'difference' is defined in _list\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the function we call for \"a -> v\" expressions\nmksvpair s v\n\t= [s, v], is_string s\n\t= error \"not str on lhs of ->\";\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error (\"unimplemented vector operation: \" ++ op_name)\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n// make a name value pair\nmknvpair n v\n\t= [n, v], is_string n\n\t= error \"not [char] on LHS of =>\";\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined, has_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nbandand x\n\t= oo_unary_function bandand_op x, is_class x\n\t= foldr1 bitwise_and (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandand\")\n{\n\tbandand_op = Operator \"bandand\" bandand Operator_type.COMPOUND_REWRAP false;\n}\n\nbandor x\n\t= oo_unary_function bandor_op x, is_class x\n\t= foldr1 bitwise_or (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandor\")\n{\n\tbandor_op = Operator \"bandor\" bandor Operator_type.COMPOUND_REWRAP false;\n}\n\nsum x\n\t= oo_unary_function sum_op x, is_class x\n\t= im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x\n\t= sum_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"sum\")\n{\n\tsum_op = Operator \"sum\" sum Operator_type.COMPOUND false;\n\n\t// add elements in a nested-list thing\n\tsum_list l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nproduct x\n\t= oo_unary_function product_op x, is_class x\n\t= product_list x, is_list x \n\t// (product image) doesn't make much sense :(\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"product\")\n{\n\tproduct_op = Operator \"product\" product Operator_type.COMPOUND false;\n\n\tproduct_list l\n\t\t= foldr prod 1 l\n\t{\n\t\tprod x total\n\t\t\t= total * product x, is_list x\n\t\t\t= total * x;\n\t}\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\nskew x\n\t= oo_unary_function skew_op x, is_class x\n\t= sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x \n\t= sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"skew\")\n{\n\tskew_op = Operator \"skew\" skew Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN \n\t\t= w * h * b, is_image x'\n\t\t= len x';\n}\n\nkurtosis x\n\t= oo_unary_function kurtosis_op x, is_class x\n\t= sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x \n\t= sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"kurtosis\")\n{\n\tkurtosis_op = Operator \"kurtosis\" kurtosis Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN\n\t\t= len x', is_list x';\n\t\t= w * h * b;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image_hist x, is_image x && \n\t\t(fmt == Image_format.UCHAR || fmt == Image_format.USHORT)\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tfmt = get_format x;\n\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean, for any image type\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n\n\t// image mean for 8 and 16-bit unsigned images\n\t// we can use a histogram, yay, and save a pass through the image\n\tmeanze_image_hist i\n\t\t= sum / N\n\t{\n\t\t// histogram, knock out zeros\n\t\thist = hist_find i;\n\t\tblack = image_new 1 1 (get_bands hist) \n\t\t\t(get_format hist) (get_coding hist) (get_type hist) 0 0 0;\n\t\thistze = insert 0 0 black hist;\n\n\t\t// matching identity\n\t\tiden\n\t\t\t= im_identity_ushort (get_bands hist) (get_width hist),\n\t\t\t\t(get_width hist) > 256\n\t\t\t= im_identity (get_bands hist);\n\n\t\t// number of non-zero pixels\n\t\tN = mean histze * 256;\n\n\t\t// sum of pixels\n\t\tsum = mean (hist * iden) * 256;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_tile_cache_random x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (\\row [row?x']) obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\" ++ \": \" ++\n\t\tjoin_sep \", \" (map print [cond, in1, in2]))\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x \n\t\t\t= to_image_size target_width target_height \n\t\t\t\ttarget_bands target_format x;\n\n\t\t[then_image, else_image] = map to_image [then_part, else_part];\n\n\t\tblend_result_image = image_set_type target_type \n\t\t\t(im_blend cond then_image else_image);\n\t}\n}\n\n// do big first: we want to keep big's class, if possible\n// eg. big is a Plot, small is a 1x1 Image\ninsert x y small big\n\t= oo_binary'_function insert_op small big, is_class big\n\t= oo_binary_function insert_op small big, is_class small\n\t= im_insert big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ndecode im\n\t= oo_unary_function decode_op im, is_class im\n\t= decode_im im, is_image im\n\t= error (_ \"bad arguments to \" ++ \"decode\")\n{\n\tdecode_op = Operator \"decode\" \n\t\tdecode Operator_type.COMPOUND_REWRAP false;\n\n\tdecode_im im\n\t\t= im_LabQ2Lab im, get_coding im == Image_coding.LABPACK\n\t\t= im_rad2float im, get_coding im == Image_coding.RAD\n\t\t= im;\n}\n\nmeasure_draw across down measure image\n    = mark\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n\n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::  \n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n    x = map (extract 0) cods;\n    y = map (extract 1) cods;\n\n    outer = mkim [$pixel => 255] sample_width sample_height 1;\n    inner = mkim [] (sample_width - 4) (sample_height - 4) 1;\n    patch = insert 2 2 inner outer;\n\n    bg = mkim [] image.width image.height 1;\n\n    mask = Image (im_insertset bg.value patch.value x y);\n\n    image' = colour_transform_to Image_type.sRGB image;\n\n    mark = if mask then Vector [0, 255, 0] else image';\n}\n\nmeasure_sample across down measure image\n    = measures\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n                \n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::\n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n\n\timage' = decode image;\n    patches = map (\\p extract_area p?0 p?1 sample_width sample_height image') \n\t\tcods;\n    measures = Matrix (map (map mean) (map bandsplit patches));\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ninvert x\n\t= oo_unary_function invert_op x, is_class x\n\t= im_invert x, is_image x\n\t= 255 - x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"invert\")\n{\n\tinvert_op = Operator \"invert\" invert Operator_type.COMPOUND false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate interp angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_affinei_all image interp.value a (-b) b a 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\t(rotate interp) Operator_type.COMPOUND_REWRAP false;\n\ta = cos angle;\n\tb = sin angle;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_lr\")\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin_lr Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert (get_width a) 0 b a;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_tb\")\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin_tb Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert 0 (get_height a) b a;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\t// The [[real]] can contain 128 values ... squeeze them out!\n\timage = im_mask2vips (Matrix m2) == 255;\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\" ++ \": \" ++ \n\t\t\"conv (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvf mask image\n\t= oo_unary_function convf_op image, is_class image\n\t= im_conv_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convf\" ++ \": \" ++ \n\t\t\"convf (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconvf_op = Operator \"convf\" \n\t\t(convf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\naconvsep layers mask image \n\t= oo_unary_function aconvsep_op image, is_class image\n\t= im_aconvsep image (to_matrix mask) (to_real layers), is_image image\n\t= error (_ \"bad arguments to \" ++ \"aconvsep\")\n{\n\taconvsep_op = Operator \"aconvsep\" \n\t\t(aconvsep layers mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsep_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_indexed index value\n\t= oo_binary_function hist_find_indexed_op index value, is_class index\n\t= oo_binary'_function hist_find_indexed_op index value, is_class value\n\t= im_hist_indexed index value, is_image index && is_image value\n\t= error (_ \"bad arguments to \" ++ \"hist_find_indexed\")\n{\n\thist_find_indexed_op = Operator \"hist_find_indexed\" \n\t\t(compose (compose Plot_histogram) hist_find_indexed) \n\t\t\tOperator_type.COMPOUND false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h \n\t\t= (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h\n\t{\n\t\t// up the format so it can represent the whole range of\n\t\t// possible values from this mask\n\t\tfmt x\n\t\t\t= Image_format.SHORT, \n\t\t\t\tx == Image_format.UCHAR || x == Image_format.CHAR\n\t\t\t= Image_format.INT, \n\t\t\t\tx == Image_format.USHORT || x == Image_format.SHORT ||\n\t\t\t\tx == Image_format.UINT \n\t\t\t= x;\n\t}\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_inv hist \n\t= oo_unary_function hist_inv_op hist, is_class hist\n\t= inv hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_inv\")\n{\n\thist_inv_op = Operator \"hist_inv\" \n\t\thist_inv Operator_type.COMPOUND_REWRAP false;\n\n\tinv im\n\t\t= im_invertlut (to_matrix im''') len\n\t{\n\t\t// need a vertical doublemask\n\t\tim' \n\t\t\t= rot90 im, get_width im > 1 && get_height im == 1 \n\t\t\t= im, get_width im == 1 && get_height im > 1\n\t\t\t= error (_ \"not a hist\");\n\t\tlen = get_height im';\n\n\t\t// values must be scaled to 0 - 1\n\t\tim'' = im' / (max im');\n\t\t\n\t\t// add an index column on the left\n\t\t// again, must be in 0-1\n\t\ty = ((make_xy 1 len)?1) / len;\n\t\tim''' = y ++ im'';\n\t}\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= lhisteq image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n\n\t// loop over bands, if necessary\n\tlhisteq im\n\t\t= im_lhisteq im (to_real w) (to_real h), get_bands im == 1\n\t\t= (foldl1 join @ map lhisteq @ bandsplit) im;\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nresize interp xfac yfac image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\t// is this interpolation nearest-neighbour?\n\tis_nn x = x.type == Interpolate_type.NEAREST_NEIGHBOUR;\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// upscale by any factor, nearest neighbour \n\t\t// upscale by integer part, then affine to exact size\n\t\t= scale xg?1 yg?1 (im_zoom im xg?0 yg?0),\n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// downscale by any factor, nearest neighbour \n\t\t// downscale by integer part, then affine to exact size\n\t\t= scale xs?1 ys?1 (im_subsample im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn interp\n\n\t\t// upscale by any factor with affine\n\t\t= scale xfac' yfac' im,\n\t\t\txfac' >= 1 && yfac' >= 1 \n\n\t\t// downscale by any factor, bilinear\n\t\t// block shrink by integer factor, then resample to \n\t\t// exact with affine\n\t\t= scale xs?1 ys?1 (im_shrink im xs?0 ys?0),\n\t\t\trxfac' >= 1 && ryfac' >= 1 \n\n\t\t= error (\"resize: unimplemented argument combination:\\n\" ++ \n\t\t\t\"  xfac = \" ++ print xfac' ++ \"\\n\" ++\n\t\t\t\"  yfac = \" ++ print yfac' ++ \"\\n\" ++\n\t\t\t\"  interp = \" ++ print interp ++ \" (\" ++\n\t\t\t\tInterpolate_type.descriptions?interp.type ++ \")\")\n\t{\n\t\t// convert a float scale to integer plus fraction\n\t\t// eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25)\n\t\tbreak f = [floor f, f / floor f];\n\n\t\t// same, but for downsizing ... turn a float scale which is less than\n\t\t// 1 into an int shrink and a float scale\n\n\t\t// complicated: the int shrink may round the size down (eg. imagine\n\t\t// subsampling a 11 pixel wide image by 3, we'd get a 3 pixel wide\n\t\t// image, not a 3.666 pixel wide image), so pass in the size of image\n\t\t// we are operating on and adjust for any rounding\n\t\t\n\t\t// so ... x is (eg.) 467, f is (eg. 128/467, about 0.274)\n\t\trbreak x f \n\t\t\t= [int_shrink, float_resample]\n\t\t{\n\t\t\t// the size of image we are aiming for after the combined int and\n\t\t\t// float resample\n\t\t\tx' = x * f;\n\n\t\t\t// int part\n\t\t\tint_shrink = floor (1 / f);\n\n\t\t\t// size after int shrink\n\t\t\tx'' = floor (x / int_shrink);\n\n\t\t\t// therefore what we need for the float part\n\t\t\tfloat_resample = x' / x'';\n\t\t}\n\n\t\twidth = get_width im;\n\t\theight = get_height im;\n\n\t\t// grow and shrink factors\n\t\txg = break xfac';\n\t\tyg = break yfac';\n\t\txs = rbreak width xfac';\n\t\tys = rbreak height yfac';\n\n\t\t// resize\n\t\tscale xfac yfac im\n\t\t\t= im_affinei_all im interp.value xfac 0 0 yfac 0 0;\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\n\n// Given a xywh rect, flip it around so wh are always positive\nrect_normalise x y w h \n\t= [x', y', w', h']\n{\n\tx'\n\t\t= x + w, w < 0\n\t\t= x;\n\ty'\n\t\t= y + h, h < 0\n\t\t= y;\n\tw' = abs w;\n\th' = abs h;\n}\n\ndraw_flood_blob x y ink image\n\t= oo_unary_function draw_flood_blob_op image, is_class image\n\t= im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood_blob\")\n{\n\tdraw_flood_blob_op = Operator \"draw_flood_blob\" \n\t\t(draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_flood x y ink image\n\t= oo_unary_function draw_flood_op image, is_class image\n\t= im_draw_flood image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood\")\n{\n\tdraw_flood_op = Operator \"draw_flood\" \n\t\t(draw_flood x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* This version of draw_rect uses insert_noexpand and will be fast, even for\n * huge images.\n */\ndraw_rect_width x y w h f t ink image\n\t= oo_unary_function draw_rect_width_op image, is_class image\n\t= my_draw_rect_width image (to_int x) (to_int y) \n\t\t(to_int w) (to_int h) (to_int f) (to_int t) ink, \n\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_width\")\n{\n\tdraw_rect_width_op = Operator \"draw_rect_width\" \n\t\t(draw_rect_width x y w h f t ink) \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\tmy_draw_rect_width image x y w h f t ink\n\t\t= insert x' y' (block w' h') image, f == 1\n\t\t= (insert x' y' (block w' t) @ \n\t\t\tinsert (x' + w' - t) y' (block t h') @ \n\t\t\tinsert x' (y' + h' - t) (block w' t) @ \n\t\t\tinsert x' y' (block t h')) image\n\t{\n\t\tinsert = insert_noexpand;\n\t\tblock w h = image_new w h (get_bands image) (get_format image)\n\t\t\t(get_coding image) (get_type image) ink' 0 0;\n\t\tink' \n\t\t\t= Vector ink, is_list ink\n\t\t\t= ink;\n\t\t[x', y', w', h'] = rect_normalise x y w h;\n\t}\n}\n\n/* Default to 1 pixel wide edges.\n */\ndraw_rect x y w h f ink image\n\t= draw_rect_width x y w h f 1 ink image;\n\n/* This version of draw_rect uses the paintbox rect draw operation. It is an\n * inplace operation and will use bucketloads of memory.\n */\ndraw_rect_paintbox x y w h f ink image\n\t= oo_unary_function draw_rect_op image, is_class image\n\t= im_draw_rect image (to_real x) (to_real y) \n\t\t(to_real w) (to_real h) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_paintbox\")\n{\n\tdraw_rect_op = Operator \"draw_rect\" \n\t\t(draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_circle x y r f ink image\n\t= oo_unary_function draw_circle_op image, is_class image\n\t= im_draw_circle image (to_real x) (to_real y) \n\t\t(to_real r) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_circle\")\n{\n\tdraw_circle_op = Operator \"draw_circle\" \n\t\t(draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_line x1 y1 x2 y2 ink image\n\t= oo_unary_function draw_line_op image, is_class image\n\t= im_draw_line image (to_real x1) (to_real y1) \n\t\t(to_real x2) (to_real y2) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_line\")\n{\n\tdraw_line_op = Operator \"draw_line\" \n\t\t(draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (\\x x % base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (\\x idivide x base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= NULL, any (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n/* Linear regression. Return a class with the stuff we need in.\n * from s15.2, p 665 NR in C\n * \n * Also calculate R2, see eg.:\n * https://en.wikipedia.org/wiki/Coefficient_of_determination \n */\nlinreg xes yes\n    = obj\n{\n    obj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [t * y :: [t, y] <- zip2 tes yes] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes];\n\n\t\tsiga = (chi2 / (ss - 2)) ** 0.5 *\n\t\t\t((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5;\n\n\t\t// for compat with linregw, see below\n\t\tq = 1.0;\n\n\t\tR2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes];\n\t}\n\n\tss = len xes;\n\tsx = sum xes;\n\tsy = sum yes;\n\tmy = sy / ss;\n\tsxoss = sx / ss;\n\n\ttes = [x - sxoss :: x <- xes];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Weighted linear regression. Xes, yes and a list of deviations.\n */\nlinregw xes yes devs \n\t= obj\n{\n\tobj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: \n\t\t\t[x, y, sd] <- zip3 xes yes devs];\n\n\t\tsiga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (1 / st2) ** 0.5;\n\n\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\n\t\tR2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes];\n\t}\n\n\twt = [sd ** -0.5 :: sd <- devs];\n\n\tss = sum wt;\n\tsx = sum [x * w :: [x, w] <- zip2 xes wt];\n\tsy = sum [y * w :: [y, w] <- zip2 yes wt];\n\tmy = sy / len xes;\n\tsxoss = sx / ss;\n\n\ttes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Clustering: pass in a list of points, repeatedly merge the\n * closest two points until no two points are closer than the threshold.\n * Return [merged-points, corresponding-weights]. A weight is a list of the\n * indexes we merged to make that point, ie. len weight == how significant\n * this point is.\n *\n * eg. \n *\tcluster 12 [152,154,155,42,159] == \n *\t\t[[155,42],[[1,2,0,4],[3]]]\n */\ncluster thresh points\n\t= oo_unary_function cluster_op points, is_class points\n\t// can't use [0..len points - 1], in case len points == 0\n\t= merge [points, map (converse cons []) (take (len points) [0 ..])],\n\t\tis_list points\n\t= error (_ \"bad arguments to \" ++ \"cluster\")\n{\n\tcluster_op = Operator \"cluster\" \n\t\t(cluster thresh) Operator_type.COMPOUND false;\n\n\tmerge x\n\t\t= x, m < 2 || d > thresh\n\t\t= merge [points', weights']\n\t{\n\t\t[points, weights] = x;\n\t\tm = len points;\n\n\t\t// generate indexes of all possible pairs, avoiding comparing a thing \n\t\t// to itself, and assuming that dist is reflexive\n\t\t// first index is always less than 2nd index\n\t\t// the +1,+2 makes sure we have an increasing generator, otherwise we\n\t\t// can get [3 .. 4] (for example), which will make a decreasing\n\t\t// sequence\n\t\tpairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]];\n\n\t\t// distance function\n\t\t// arg is eg. [3,1], meaning get distance from point 3 to point 1\n\t\tdist x \n\t\t\t= abs (points?i - points?j)\n\t\t{\n\t\t\t[i, j] = x;\n\t\t}\n\n\t\t// smallest distance, then the two points we merge\n\t\tp = minpos (map dist pairs);\n\t\td = dist pairs?p;\n\t\t[i, j] = pairs?p;\n\n\t\t// new point and new weight\n\t\tnw = weights?i ++ weights?j;\n\t\tnp = (points?i * len weights?i + points?j * len weights?j) / len nw;\n\n\t\t// remove element i from a list\n\t\tremove i l = take i l ++ drop (i + 1) l;\n\n\t\t// remove two old points, add the new merged one\n\t\t// i < j (see \"pairs\", above)\n\t\tpoints' = np : remove i (remove j points);\n\t\tweights' = nw : remove i (remove j weights);\n\t}\n}\n\n/* Extract the area of an image around an arrow.\n * Transform the image to make the arrow horizontal, then displace by hd and\n * vd pxels, then cut out a bit h pixels high centered on the arrow.\n */\nextract_arrow hd vd h arrow\n\t= extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im'\n{\n\t// the line as a polar vector\n\tpv = polar (arrow.width, arrow.height);\n\ta = im pv;\n\n\t// smallest rotation that will make the line horizontal\n\ta'\n\t\t= 360 - a, a > 270\n\t\t= 180 - a, a > 90\n\t\t= -a;\n\n\tim' = rotate Interpolate_bilinear a' arrow.image;\n\n\t// look at the start and end of the arrow, pick the leftmost\n\tp\n\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t= (arrow.right, arrow.bottom);\n\n\t// transform that point to im' space\n\tp' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset);\n}\n\n/* You'd think these would go in _convert, but they are not really colour ops,\n * so put them here.\n */\nrad2float image\n\t= oo_unary_function rad2float_op image, is_class image\n\t= im_rad2float image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"rad2float\")\n{\n\trad2float_op = Operator \"rad2float\" \n\t\trad2float Operator_type.COMPOUND_REWRAP false;\n}\n\nfloat2rad image\n\t= oo_unary_function float2rad_op image, is_class image\n\t= im_float2rad image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"float2rad\")\n{\n\tfloat2rad_op = Operator \"float2rad\" \n\t\tfloat2rad Operator_type.COMPOUND_REWRAP false;\n}\n\nsegment x\n\t= oo_unary_function segment_op x, is_class x\n\t= image', is_image x \n\t= error (_ \"bad arguments to \" ++ \"segment\")\n{\n\tsegment_op = Operator \"segment\" \n\t\tsegment Operator_type.COMPOUND_REWRAP false;\n\n\t[image, nsegs] = im_segment x;\n\timage' = im_copy_set_meta image \"n-segments\" nsegs;\n}\n\npoint a b\n\t= oo_binary_function point_op a b, is_class a\n\t= oo_binary'_function point_op a b, is_class b\n\t= im_read_point b x y, is_image b\n\t= [b?x?y], is_matrix b\n\t= [b?x], is_real_list b && y == 0\n\t= [b?y], is_real_list b && x == 0\n\t= error (_ \"bad arguments to \" ++ \"point\")\n{\n\tpoint_op = Operator \"point\" \n\t\t(\\a\\b Vector (point a b)) Operator_type.COMPOUND false;\n\n\t(x, y) \n\t\t= a, is_complex a;\n\t\t= (a?0, a?1), is_real_list a && is_list_len 2 a\n\t\t= error \"bad position format\";\n}\n\n/* One image in, one out. \n */\nsystem_image command x\n\t= oo_unary_function system_image_op x, is_class x\n\t= system x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"system_image\")\n{\n\tsystem_image_op = Operator \"system_image\" \n\t\t(system_image command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem im\n\t\t= image_out\n\t{\n\t\t[image_out, log] = \n\t\t\tim_system_image (get_image im) \"%s.tif\" \"%s.tif\" command;\n\t}\n}\n\n/* Two images in, one out. \n */\nsystem_image2 command x1 x2\n\t= oo_binary_function system_image2_op x1 x2, is_class x1\n\t= oo_binary'_function system_image2_op x1 x2, is_class x2\n\t= system x1 x2, is_image x1 && is_image x2\n\t= error (_ \"bad arguments to \" ++ \"system_image2\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image2 command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Three images in, one out. \n */\nsystem_image3 command x1 x2 x3\n\t= oo_binary_function system_image2_op x2 x3, is_class x2\n\t= oo_binary'_function system_image2_op x2 x3, is_class x3\n\t= system x1 x2 x3, is_image x1 && is_image x2 && is_image x3\n\t= error (_ \"bad arguments to \" ++ \"system_image3\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image3 command x1) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2 x3\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2, x3], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Zero images in, one out. \n */\nsystem_image0 command \n\t= Image image_out\n{\n\t[image_out] = vips_call \"system\" [command] [\n\t\t$out => true,\n\t\t$out_format => \"%s.tif\" \n\t];\n}\n\nhough_line w h x \n\t= oo_unary_function hough_line_op x, is_class x\n\t= hline (to_real w) (to_real h) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_line\")\n{\n\though_line_op = Operator \"hough_line\" \n\t\t(hough_line w h) Operator_type.COMPOUND_REWRAP false;\n\n\thline w h x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_line\" [x] [\n\t\t\t$width => w, \n\t\t\t$height => h\n\t\t];\n\t}\n}\n\nhough_circle s mn mx x \n\t= oo_unary_function hough_circle_op x, is_class x\n\t= hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_circle\")\n{\n\though_circle_op = Operator \"hough_circle\" \n\t\t(hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false;\n\n\thcircle s mn mx x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_circle\" [x] [\n\t\t\t$scale => s, \n\t\t\t$min_radius => mn, \n\t\t\t$max_radius => mx\n\t\t];\n\t}\n}\n\nmapim interp ind in\n\t= oo_binary_function mapim_op ind in, is_class ind\n\t= oo_binary'_function mapim_op ind in, is_class in\n\t= mapim_fn ind in, is_image ind && is_image in\n\t= error (_ \"bad arguments to \" ++ \"mapim\")\n{\n\tmapim_op = Operator \"mapim\" \n\t\t(mapim interp) Operator_type.COMPOUND_REWRAP false;\n\n\tmapim_fn ind im\n\t\t= out\n\t{\n\t\t[out] = vips_call \"mapim\" [im, ind] [$interpolate => interp];\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.2/_types.def",
    "content": "/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary (\\a op.fn a x) this,\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// we can't call map_trinary directly, since it uses Group and we\n\t// don't support mutually recursive top-level functions :-(\n\t// copy-paste it here, keep in sync with the version in _stdenv\n\tmap_nary fn args\n\t\t= fn args, groups == []\n\t\t= Group (map process [0, 1 .. shortest - 1])\n\t{\n\t\tgroups = filter is_Group args;\n\t\n\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\tprocess n\n\t\t\t= NULL, any (map (is_noval n) args)\n\t\t\t= map_nary fn (map (extract n) args)\n\t\t{\n\t\t\textract n arg\n\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t= arg;\n\t\n\t\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t\t}\n\t}\n\n\t// need ite as a true trinary\n\tite a b c = if a then b else c;\n\n\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t];\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\n\t\t[op.fn this.value x,\n\t\t\top.type == Operator_type.COMPOUND]\n\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[is_list_len 3 value, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.item colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum \"Colour space\" Image_type.colour_spaces default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\n/* An option whose value is a string rather than a number.\n */\nOption_string caption labels item = class\n\tOption caption labels (index (equal item) labels) {\n\tOption_edit caption labels value \n\t\t= this.Option_string caption labels (labels?value);\n}\n\n/* Make an option from an enum.\n */\nOption_enum caption enum item = class\n\tOption_string caption enum.names item {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing item;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum caption enum (enum.names?value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNONE = 0;\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNONE = 0;\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n\tRAD = 6;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* Extract a column.\n\t */\n\tcolumn n = map (extract n) value;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (column col) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (column from);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = this.column 0; \n\tthings = this.column 1; \n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tHISTOGRAM = 10;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tARRAY = 27;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t$MULTIBAND => MULTIBAND,\n\t\t$B_W => B_W,\n\t\t$HISTOGRAM => HISTOGRAM,\n\t\t$XYZ => XYZ,\n\t\t$LAB => LAB,\n\t\t$CMYK => CMYK,\n\t\t$LABQ => LABQ,\n\t\t$RGB => RGB,\n\t\t$UCS => UCS,\n\t\t$LCH => LCH,\n\t\t$LABS => LABS,\n\t\t$sRGB => sRGB,\n\t\t$YXY => YXY,\n\t\t$FOURIER => FOURIER,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$ARRAY => ARRAY\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options generated from this, so match the order to the order in the\n\t * Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t$sRGB => sRGB,\n\t\t$Lab => LAB,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t$Mono => B_W,\n\t\t$sRGB => sRGB,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$Lab => LAB,\n\t\t$LabQ => LABQ,\n\t\t$LabS => LABS,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \n\t\t// \"Image v == 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\t// if one of then/else is an image, get the target format from that\n\t\t// otherwise, let the non-image objects set the target\n\t\ttarget_format \n\t\t\t= get_member_list has_format get_format x, \n\t\t\t\thas_member_list has_format x\n\t\t\t= NULL;\n\n\t\tto_image x = to_image_size width height target_bands target_format x;\n\n\t\t[then', else'] = map to_image x;\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if value then then' else else');\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nInterpolate_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\tLBB = 3;\n\tNOHALO = 4;\n\tVSQBS = 5;\n\n\t// Should introspect to get the list of interpolators :-(\n        // We can \"dir\" on VipsInterpolate to get a list of them, but we\n        // can't get i18n'd descriptions until we have more\n        // introspection stuff in nip2.\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Bilinear\", \n\t\t_ \"Bicubic\",\n\t\t_ \"Upsize: reduced halo bicubic (LBB)\",\n\t\t_ \"Upsharp: reduced halo bicubic with edge sharpening (Nohalo)\",\n\t\t_ \"Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)\"\n\t];\n\n\t/* And to vips type names.\n\t */\n\ttypes = [\n\t\t\"VipsInterpolateNearest\",\n\t\t\"VipsInterpolateBilinear\",\n\t\t\"VipsInterpolateBicubic\",\n\t\t\"VipsInterpolateLbb\",\n\t\t\"VipsInterpolateNohalo\",\n\t\t\"VipsInterpolateVsqbs\"\n\t];\n}\n\nInterpolate type options = class {\n\tvalue = vips_object_new Interpolate_type.types?type [] options;\n}\n\nInterpolate_bilinear = Interpolate Interpolate_type.BILINEAR [];\n\nInterpolate_picker default = class \n\tInterpolate interp.value [] {\n\t_vislevel = 2;\n\n\tinterp = Option \"Interpolation\" Interpolate_type.descriptions default;\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t_ \"Perceptual\" => PERCEPTUAL,\n\t\t_ \"Relative\" => RELATIVE,\n\t\t_ \"Saturation\" => SATURATION,\n\t\t_ \"Absolute\" => ABSOLUTE\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t_ \"Point\" => POINT,\n\t\t_ \"Line\" => LINE,\n\t\t_ \"Spline\" => SPLINE,\n\t\t_ \"Bar\" => BAR\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t_ \"YYYY\" => YYYY,\n\t\t_ \"XYYY\" => XYXY,\n\t\t_ \"XYXY\" => XYXY\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n\tto_image dpi = extract_bands 0 3 \n\t\t(graph_export_image (to_real dpi) this);\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [$format => Plot_format.XYYY] value {\n}\n\n/* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate\n * empty slots, for example.\n */\nNULL = class \n\t_Object {\n\too_binary_table op x = [\n\t\t// the only operation we allow is equality .. use pointer equality,\n\t\t// this lets us test a == NULL and a != NULL\n\t\t[this === x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"equal\"],\n\t\t[this !== x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"not_equal\"]\n\t] ++ super.oo_binary_table op x;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.3/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t[_L, _a, _b] = default_value;\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n\n\tCCT_colour = class\n\t\tMenuaction (_ \"Colour from CCT\") (_ \"pick colour by CCT\") {\n\t\taction = widget 6500;\n\n\t\twidget x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tT = Scale \"CCT\" 1800 25000 x;\n\n\t\t\t_result = colour_from_temp (to_real T);\n\n\t\t\tColour_edit space value \n\t\t\t\t= widget (temp_from_colour (Colour space value));\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Convert to\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Tag as\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum (_ \"Old whitepoint\") Whitepoints \"D65\";\n\t\t\tnew_white = Option_enum (_ \"New whitepoint\") Whitepoints \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCCT_item = class\n\t\tMenuaction (_ \"Calculate temperature\")\n\t\t\t(_ \"estimate CCT using the McCamy approximation\") {\n\t\taction z = map_unary temp_from_colour z;\n\t}\n\n\tColour_item = Colour_new_item.CCT_colour;\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= print_profile, \n\t\t\thas_type image && \n\t\t\tget_type image == Image_type.CMYK &&\n\t\t\thas_bands image && \n\t\t\tget_bands image >= 4\n\t\t= monitor_profile;\n\trender_intents = Option_enum (_ \"Render intent\") Render_intent.names\n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_rad_item = class\n\tMenupullright (_ \"_Radiance\") (_ \"convert to and from Radiance packed format\") {\n\tUnpack_item = class\n\t\tMenuaction (_ \"Unpack\") \n\t\t\t(_ \"unpack Radiance format to float\") {\n\t\taction x = map_unary rad2float x;\n\t}\n\n\tPack_item = class\n\t\tMenuaction (_ \"Pack\") \n\t\t\t(_ \"pack 3-band float to Radiance format\") {\n\t\taction x = map_unary float2rad x;\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n        // get a representative image from an arg\n        get_image x\n            = get_image x.value?0, is_Group x\n            = x;\n\n        _im = get_image x; \n\t\tsample = measure_draw (to_real pacross) (to_real pdown) \n\t\t\t\t(to_real measure) _im;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure_sample (to_real pacross) (to_real pdown) \n\t\t\t\t\t(to_real measure) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.3/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 2;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 20;\n\t\t\tfs = Scale \"Sharpen flat areas by\" 0 5 0.5;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" 0 5 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tlayers = Scale \"Layers\" 1 100 10;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\", \"Approximate\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf, aconvsep layers]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\t\t\trotate = Option \"Rotate\" [\n\t\t\t\t\"Don't rotate\", \n\t\t\t\t\"4 x 45 degrees\", \n\t\t\t\t\"8 x 45 degrees\", \n\t\t\t\t\"2 x 90 degrees\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_lindetect, !separable && type == 0 && rotate == 1\n\t\t\t\t\t\t= im_compass, !separable && type == 0 && rotate == 2\n\t\t\t\t\t\t= im_gradient, !separable && type == 0 && rotate == 3\n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_conv_f, !separable && type == 1\n\t\t\t\t\t\t= im_convsep_f, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 4) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width.expr window_height.expr in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\nFilter_hough_item = class\n\tMenupullright \"_Hough Transform\" \"transform to parameter space\" {\n\tLine_item = class\n\t\tMenuaction \"_Line\" \"find straight line Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpspace_width = Expression \"Parameter space width\" 64;\n\t\t\tpspace_height = Expression \"Parameter space height\" 64;\n\n\t\t\t_result \n\t\t\t\t= map_unary line a \n\t\t\t{\n\t\t\t\tline a \n\t\t\t\t\t= hough_line \n\t\t\t\t\t\t(to_real pspace_width) (to_real pspace_height) a;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class\n\t\tMenuaction \"_Circle\" \"find circle Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Expression \"Scale down parameter space by\" 10;\n\t\t\tmin_radius = Expression \"Minimum radius\" 10;\n\t\t\tmax_radius = Expression \"Maximum radius\" 30;\n\n\t\t\t_result \n\t\t\t\t= map_unary circle a \n\t\t\t{\n\t\t\t\tcircle a \n\t\t\t\t\t= hough_circle (to_real scale) (to_real min_radius)\n\t\t\t\t\t\t(to_real max_radius) a;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_coordinate_item = class\n\tMenupullright \"_Coordinate Transform\" \"various coordinate transforms\" {\n\t// run a function which wants a complex arg on a non-complex two-band\n\t// image\n\trun_cmplx fn x\n\t\t= re x' ++ im x'\n\t{\n\t\tx' = fn (x?0, x?1);\n\t}\n\n\tPolar_item = class\n\t\tMenuaction \"_Polar\" \"transform to polar coordinates\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result \n\t\t\t\t= map_unary to_polar a \n\t\t\t{\n\t\t\t\tto_polar im \n\t\t\t\t\t= mapim interp.value map' im\n\t\t\t\t{\n\t\t\t\t\t// xy image, origin in the centre, scaled to fit image to\n\t\t\t\t\t// a circle\n\t\t\t\t\txy = make_xy im.width im.height;\n\t\t\t\t\txy' = xy - Vector [im.width / 2, im.height / 2];\n\t\t\t\t\tscale = min [im.width, im.height] / im.width;\n\t\t\t\t\txy'' = 2 * xy' / scale;\n\n\t\t\t\t\t// to polar, scale vertical axis to 360 degrees\n\t\t\t\t\tmap = run_cmplx polar xy'';\n\t\t\t\t\tmap' = map * Vector [1, im.height / 360];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tRectangular_item = class\n\t\tMenuaction \"_Rectangular\" \"transform to rectangular coordinates\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result \n\t\t\t\t= map_unary to_rect a \n\t\t\t{\n\t\t\t\tto_rect im \n\t\t\t\t\t= mapim interp.value map'' im\n\t\t\t\t{\n\t\t\t\t\t// xy image, vertical scaled to 360 degrees\n\t\t\t\t\txy = make_xy im.width im.height;\n\t\t\t\t\txy' = xy * Vector [1, 360 / im.height];\n\n\t\t\t\t\t// to rect, scale to image rect\n\t\t\t\t\tmap = run_cmplx rectangular xy';\n\t\t\t\t\tscale = min [im.width, im.height] / im.width;\n\t\t\t\t\tmap' = map * scale / 2;\n\n\t\t\t\t\tmap'' = map' + Vector [im.width / 2, im.height / 2];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image\" \"use an image to blend two objects\" {\n\t\taction a b c = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ti = Toggle \"Invert mask\" false;\n\n\t\t\t_result \n\t\t\t\t= map_trinary process a b c\n\t\t\t{\n\t\t\t\tprocess a b c \n\t\t\t\t\t= blend condition in1 in2, !i\n\t\t\t\t\t= blend (invert condition) in1 in2\n\t\t\t\t{\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t\t= false,\n\t\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t\t= true;\n\t\t\t\t\t[condition, in1, in2] = sortc compare [a, b, c];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"_Alpha\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t_ \"Normal\" => NORMAL,\n\t\t\t_ \"If Lighter\" => IFLIGHTER,\n\t\t\t_ \"If Darker\" => IFDARKER,\n\t\t\t_ \"Multiply\" => MULTIPLY,\n\t\t\t_ \"Add\" => ADD,\n\t\t\t_ \"Subtract\" => SUBTRACT,\n\t\t\t_ \"Screen\" => SCREEN,\n\t\t\t_ \"Burn\" => BURN,\n\t\t\t_ \"Soft Light\" => SOFTLIGHT,\n\t\t\t_ \"Hard Light\" => HARDLIGHT,\n\t\t\t_ \"Lighten\" => LIGHTEN,\n\t\t\t_ \"Darken\" => DARKEN,\n\t\t\t_ \"Dodge\" => DODGE,\n\t\t\t_ \"Reflect\" => REFLECT,\n\t\t\t_ \"Freeze\" => FREEZE,\n\t\t\t_ \"Bitwise OR\" => OR,\n\t\t\t_ \"Bitwise AND\" => AND\n\t\t];\n\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum \"Blend mode\" names \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\t[mono, colour] = \n\t\t\t\t\tsortc (const (is_colour_type @ get_type)) [a, b];\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t_ \"Grey\",\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t_ \"North-west\",\n\t\t\t\t_ \"North\",\n\t\t\t\t_ \"North-east\",\n\t\t\t\t_ \"West\",\n\t\t\t\t_ \"Centre\",\n\t\t\t\t_ \"East\",\n\t\t\t\t_ \"South-west\",\n\t\t\t\t_ \"South\",\n\t\t\t\t_ \"South-east\",\n\t\t\t\t_ \"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nAutotrace_item = class \n\tMenuaction \"_Trace\" \"convert a bitmap to an SVG file\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tdespeckle = Scale \"Despeckle level\" 1 20 1;\n\t\tline = Scale \"Line threshold\" 1 20 1;\n\t\tcenter = Toggle \"Trace centreline\" false;\n\t\tscale = Scale \"SVG scale\" 0.1 10 1;\n\n\t\tcommand \n\t\t\t= \"autotrace %s \" ++ join_sep \" \" \n\t\t\t\t[ofmt, ofile, desp, lint, cent]\n\t\t{\n\t\t\tprog = search_for_error \"autotrace\"; \n\t\t\tofmt = \"-output-format svg\";\n\t\t\tofile = \"-output-file %s\";\n\t\t\tdesp = \"-despeckle-level \" ++ print despeckle.value;\n\t\t\tlint = \"-line-threshold \" ++ print line.value;\n\t\t\tcent = if center then \"-centerline \" else \"\";\n\t\t}\n\n\t\t_result \n\t\t\t= Image output\n\t\t{\n\t\t\t[output] = vips_call \"system\" \n\t\t\t\t[command] \n\t\t\t\t[$in => [x.value],\n\t\t\t\t $in_format => \"%s.ppm\", \n\t\t\t\t $out => true,\n\t\t\t\t $out_format => \"%s.svg[scale=\" ++ print scale.value ++ \"]\"\n\t\t\t\t];\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.3/Histogram.def",
    "content": "Hist_new_item = class\n\tMenupullright \"_New\" \"new histogram\" {\n\tHist_item = class\n\t\tMenuaction \"_Identity\" \"make an identity histogram\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\t_result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d);\n\t\t}\n\t}\n\n\tHist_new_from_matrix = Matrix_buildlut_item; \n\n\tHist_from_image_item = class\n\t\tMenuaction \"Ta_g Image As Histogram\" \"set image Type to Histogram\" {\n\t\taction x = hist_tag x;\n\t}\n\n\tTone_item = class \n\t\tMenuaction \"_Tone Curve\" \"make a new tone mapping curve\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\t_result \n\t\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t\t{\n\t\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_convert_to_hist_item = class \n\tMenuaction \"Con_vert to Histogram\" \"convert anything to a histogram\" {\n\taction x = hist_tag (to_image x);\n}\n\nHist_find_item = class \n\tMenupullright \"_Find\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n\n\tIndexed_item = class\n\t\tMenuaction \"_Indexed\" \n\t\t\t\"use a 1-band index image to pick bins for an n-band image\" {\n\t\taction x y \n\t\t\t= map_binary map x y\n\t\t{\n\t\t\tmap a b\n\t\t\t\t= hist_find_indexed index im\n\t\t\t{\n\t\t\t\t[im, index] = sortc (const is_index) [a, b];\n\n\t\t\t\tis_index x\n\t\t\t\t\t= has_image x && b == 1 && \n\t\t\t\t\t\t(f == Image_format.UCHAR || f == Image_format.USHORT)\n\t\t\t\t{\n\t\t\t\t\tim = get_image x;\n\t\t\t\t\tb = get_bands x;\n\t\t\t\t\tf = get_format x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\t[im, hist] = sortc (const is_hist) [a, b];\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Integrate\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate\" \n\t\t\"find point-to-point differences (inverse of Integrate)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_inv_item = class \n\tMenuaction \"In_vert\" \"invert a histogram\" {\n\taction x = map_unary hist_inv x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\tarea = extract_arrow \n\t\t\t\t\tdisplace.value vdisplace.value width.value arrow;\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize Kernel_linear 1 (1 / width.value) area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary (extract_arrow \n\t\t\t\tdisplace.value vdisplace.value width.value) x;\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcaption = Expression \"Chart caption\" \"none\";\n\t\tformat = Option_enum \"Format\" Plot_format.names \"YYYY\";\n\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\t\txcaption = Expression \"X axis caption\" \"none\";\n\t\tycaption = Expression \"Y axis caption\" \"none\";\n\t\tseries_captions = Expression \"Series captions\" [\"Band 0\"];\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => style.value, $format => format.value] ++ \n\t\t\t\t\trange ++ captions;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\tcaptions \n\t\t\t\t= concat (map test caption_options) ++ \n\t\t\t\t  [$series_captions => series_captions.expr]\n\t\t\t{\n\t\t\t\tcaption_options = [\n\t\t\t\t\t$caption => caption.expr,\n\t\t\t\t\t$xcaption => xcaption.expr,\n\t\t\t\t\t$ycaption => ycaption.expr\n\t\t\t\t];\n\t\t\t\ttest x\n\t\t\t\t\t= [], value == \"none\"\n\t\t\t\t\t= [option_name => value]\n\t\t\t\t{\n\t\t\t\t\t[option_name, value] = x;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow 0 0 1 x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.3/Image.def",
    "content": "Image_new_item = class Menupullright \"_New\" \"make new things\" {\n\tImage_black_item = class Menuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \"Image type\"\n\t\t\t\tImage_type.type_names \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region on image using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\t[target, x] = sortc compare [a, b];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\nImage_number_format_item = class\n\tMenupullright \"_Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_header_item = class \n\tMenupullright \"_Header\" \"do stuff to the image header\" {\n\n\tImage_get_item = class\n\t\tMenupullright \"_Get\" \"get header fields\" {\n\n\t\t// the header fields we can get\n\t\tfields = class {\n\t\t\ttype = 0;\n\t\t\twidth = 1;\n\t\t\theight = 2;\n\t\t\tformat = 3;\n\t\t\tbands = 4;\n\t\t\txres = 5;\n\t\t\tyres = 6;\n\t\t\txoffset = 7;\n\t\t\tyoffset = 8;\n\t\t\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t$width => width,\n\t\t\t\t$height => height,\n\t\t\t\t$bands => bands,\n\t\t\t\t$format => format,\n\t\t\t\t$type => type,\n\t\t\t\t$xres => xres,\n\t\t\t\t$yres => yres,\n\t\t\t\t$xoffset => xoffset,\n\t\t\t\t$yoffset => yoffset,\n\t\t\t\t$coding => coding\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum (_ \"Field\") field_names name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tCustom_item = class\n\t\t\tMenuaction \"C_ustom\" \"get any header field\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tfield = String \"Field\" \"Xsize\";\n\t\t\t\tparse = Option \"Parse\" [\n\t\t\t\t\t\"No parsing\",\n\t\t\t\t\t\"Parse string as integer\",\n\t\t\t\t\t\"Parse string as real\",\n\t\t\t\t\t\"Parse string as hh:mm:ss\"\n\t\t\t\t] 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary (wrap @ process @ get_header field.value) x\n\t\t\t\t{\n\t\t\t\t\tparse_str parse str = parse (split is_space str)?0;\n\n\t\t\t\t\tparse_field name cast parse x\n\t\t\t\t\t\t= cast x, is_number x\n\t\t\t\t\t\t= parse_str parse x, is_string x\n\t\t\t\t\t\t= error (\"not \" ++ name);\n\n\t\t\t\t\tget_int = parse_field \"int\" \n\t\t\t\t\t\tcast_signed_int parse_int;\n\t\t\t\t\tget_float = parse_field \"float\" \n\t\t\t\t\t\tcast_float parse_float;\n\t\t\t\t\tget_time = parse_field \"hh:mm:ss\" \n\t\t\t\t\t\tcast_signed_int parse_time;\n\n\t\t\t\t\twrap x\n\t\t\t\t\t\t= Real x, is_real x\n\t\t\t\t\t\t= Vector x, is_real_list x\n\t\t\t\t\t\t= Image x, is_image x\n\t\t\t\t\t\t= Bool x, is_bool x\n\t\t\t\t\t\t= Matrix x, is_matrix x\n\t\t\t\t\t\t= String \"String\" x, is_string x\n\t\t\t\t\t\t= List x, is_list x\n\t\t\t\t\t\t= x;\n\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tget_int, \n\t\t\t\t\t\tget_float,\n\t\t\t\t\t\tget_time\n\t\t\t\t\t]?parse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum \"Image type\" Image_type.type_names \n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_cache_item = class\n\tMenuaction \"C_ache\" \"cache calculated image pixels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttile_width = Number \"Tile width\" 128;\n\t\ttile_height = Number \"Tile height\" 128;\n\t\tmax_tiles = Number \"Maximum number of tiles to cache\" (-1);\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= cache (to_real tile_width) (to_real tile_height) \n\t\t\t\t\t(to_real max_tiles) image;\n\t\t}\n\t}\n}\n\n#separator\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\t// we can't use id here since we want to \"declass\"\n\t\t\t\t\t\t// the members of x ... consider if x is a crop class,\n\t\t\t\t\t\t// for example, we don't want to inherit from crop, we\n\t\t\t\t\t\t// want to make a new image class\n\t\t\t\t\t\trot180 @ rot180,\n\t\t\t\t\t\trot90,\n\t\t\t\t\t\trot180,\n\t\t\t\t\t\trot270\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate interp angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary straighten x\n\t\t\t\t{\n\t\t\t\t\tstraighten arrow\n\t\t\t\t\t\t= rotate interp angle'' arrow.image\n\t\t\t\t\t{\n\t\t\t\t\t\tx = arrow.width;\n\t\t\t\t\t\ty = arrow.height;\n\t\t\n\t\t\t\t\t\tangle = im (polar (x, y));\n\t\t\n\t\t\t\t\t\tangle'\n\t\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t\t= angle;\n\t\t\n\t\t\t\t\t\tangle''\n\t\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize kernel xfactor yfactor image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\taspect = Toggle \"Break aspect ratio\" false;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize kernel h v image, aspect\n\t\t\t\t\t\t= resize kernel fac fac image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac > yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\tmin_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac < yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\t[h, v] = [\n\t\t\t\t\t\t\tmax_factor, \n\t\t\t\t\t\t\tmin_factor, \n\t\t\t\t\t\t\t[xfac, 1], \n\t\t\t\t\t\t\t[1, yfac]]?which;\n\n\t\t\t\t\t\tfac \n\t\t\t\t\t\t\t= h, v == 1\n\t\t\t\t\t\t\t= v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_within_item = class\n\t\t\tMenuaction \"Size _Within\" \"size to fit within a rectangle\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\t// the rects we size to fit within\n\t\t\t\t_rects = [\n\t\t\t\t\t[2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], \n\t\t\t\t\t[1280, 1024], [1024, 768], [800, 600], [640, 480] \n\t\t\t\t];\n\n\t\t\t\twithin = Option \"Fit within (pixels)\" (\n\t\t\t\t\t[print w ++ \" x \" ++ print h :: [w, h] <- _rects] ++\n\t\t\t\t\t[\"Custom\"]\n\t\t\t\t) 4;\n\t\t\t\tcustom_width = Expression \"Custom width\" 1000;\n\t\t\t\tcustom_height = Expression \"Custom height\" 1000;\n\t\t\t    size = Option \"Page size\" [\n\t\t\t\t\t\"Full page\", \"Half page\", \"Quarter page\" \n\t\t\t\t] 0;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t \t_result\n\t\t\t\t \t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\txdiv = [1, 2, 2]?size;\n\t\t\t\t\tydiv = [1, 1, 2]?size;\n\t\t\t\t\tallrect = _rects ++ [\n\t\t\t\t\t\t[custom_width.expr, custom_height.expr]\n\t\t\t\t\t];\n\t\t\t\t\t[width, height] = allrect?within;\n\n\t\t\t\t\tprocess x\n\t\t\t\t\t\t= resize kernel fac fac x, fac < 1\n\t\t\t\t\t\t= x\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = (width / xdiv) / x.width;\n\t\t\t\t\t\tyfac = (height / ydiv) / x.height;\n\t\t\t\t\t\tfac = min_pair xfac yfac;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_map_item = class\n\t\tMenuaction \"_Map\" \"map an image through a 2D transform image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result\n\t\t\t\t= map_binary trans a b\n\t\t\t{\n\t\t\t\ttrans a b\n\t\t\t\t\t= mapim interp.value in index\n\t\t\t\t{\n\t\t\t\t\t// get the index image first\n\t\t\t\t\t[index, in] = sortc (const is_twocomponent) [a, b];\n\n\t\t\t\t\t// is a two-component image, ie. one band complex, or\n\t\t\t\t\t// two-band non-complex\n\t\t\t\t\tis_twocomponent x\n\t\t\t\t\t\t= is_nonc x || is_c x;\n\t\t\t\t\tis_nonc x\n\t\t\t\t\t\t= has_bands x && get_bands x == 2 && \n\t\t\t\t\t\t\thas_format x && !is_complex_format (get_format x);\n\t\t\t\t\tis_c x\n\t\t\t\t\t\t= has_bands x && get_bands x == 1 && \n\t\t\t\t\t\t\thas_format x && is_complex_format (get_format x);\n\t\t\t\t\tis_complex_format f\n\t\t\t\t\t\t= f == Image_format.COMPLEX || \n\t\t\t\t\t\t\tf == Image_format.DPCOMPLEX;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\" [\"Nearest\", \"Bilinear\"] 1;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_trn {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t[sample', trn, err] = transform_search \n\t\t\t\t\tmax_err max_iter order interp wrap\n\t\t\t\t\tsample reference;\n\t\t\t\ttransformed_image = Image sample';\n\t\t\t\t_trn = Transform trn reference.width reference.height;\n\t\t\t\tfinal_error = err;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\t[i, t] = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tBandwise_item = Image_join_item.Bandwise_item;\n\n    sep1 = Menuseparator;\n\n\tBandand_item = class\n\t\tMenuaction \"Bitwise Band AND\" \"bitwise AND of image bands\" {\n\t\taction x = bandand x;\n\t}\n\n\tBandor_item = class\n\t\tMenuaction \"Bitwise Band OR\" \"bitwise OR of image bands\" {\n\t\taction x = bandor x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldl1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x \n\t\t= crop x [l, t, w, h]\n\t{\n\t\tfields = [\n\t\t\t[has_left, get_left, 0],\n\t\t\t[has_top, get_top, 0],\n\t\t\t[has_width, get_width, 100],\n\t\t\t[has_height, get_height, 100]\n\t\t];\n\n\t\t[l, t, w, h] \n\t\t\t= map get_default fields\n\t\t{\n\t\t\tget_default line\n\t\t\t\t= get x, has x\n\t\t\t\t= default\n\t\t\t{\n\t\t\t\t[has, get, default] = line;\n\t\t\t}\n\t\t}\n\t}\n\n\tcrop x geo = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tl = Expression \"Crop left\" ((int) (geo?0 + geo?2 / 4));\n\t\tt = Expression \"Crop top\" ((int) (geo?1 + geo?3 / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (geo?2 / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (geo?3 / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t[_a', _b'] = sortc _pred [a, b];\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_draw_item = class \n\tMenupullright \"_Draw\" \"draw lines, circles, rectangles, floods\" {\n\tLine_item = class Menuaction \"_Line\" \"draw line on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tx1 = Expression \"Start x\" 0;\n\t\t\ty1 = Expression \"Start y\" 0;\n\t\t\tx2 = Expression \"End x\" 100;\n\t\t\ty2 = Expression \"End y\" 100;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary line x\n\t\t\t{\n\t\t\t\tline im \n\t\t\t\t\t= draw_line x1 y1 x2 y2 i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tRect_item = class Menuaction \"_Rectangle\" \"draw rectangle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\trx = Expression \"Left\" 50;\n\t\t\try = Expression \"Top\" 50;\n\t\t\trw = Expression \"Width\" 100;\n\t\t\trh = Expression \"Height\" 100;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\tt = Scale \"Line thickness\" 1 50 3;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary rect x\n\t\t\t{\n\t\t\t\trect im \n\t\t\t\t\t= draw_rect_width rx ry rw rh f t i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class Menuaction \"_Circle\" \"draw circle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcx = Expression \"Centre x\" 100;\n\t\t\tcy = Expression \"Centre y\" 100;\n\t\t\tr = Expression \"Radius\" 50;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary circle x\n\t\t\t{\n\t\t\t\tcircle im \n\t\t\t\t\t= draw_circle cx cy r f i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tFlood_item = class Menuaction \"_Flood\" \"flood bounded area of image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsx = Expression \"Start x\" 100;\n\t\t\tsy = Expression \"Start y\" 100;\n\n\t\t\te = Option \"Flood while\" [\n\t\t\t\t\"Not equal to ink\",\n\t\t\t\t\"Equal to start point\"\n\t\t\t] 0;\n\n\t\t\t// pick a default ink that won't flood, if we can\n\t\t\ti \n\t\t\t\t= Expression \"Ink\" default_ink\n\t\t\t{\n\t\t\t\tdefault_ink\n\t\t\t\t\t= [0], ! has_image x\n\t\t\t\t\t= pixel;\n\t\t\t\tpixel = map mean (bandsplit (extract_area sx sy 1 1 im));\n\t\t\t\tim = get_image x;\n\t\t\t}\n\n\t\t\t_result \n\t\t\t\t= map_unary flood x\n\t\t\t{\n\t\t\t\tflood im \n\t\t\t\t\t= draw_flood sx sy i.expr im, e == 0\n\t\t\t\t\t= draw_flood_blob sx sy i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tDraw_scalebar_item = class Menuaction \"_Scale\" \"draw scale bar\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpx = Expression \"Left\" 50;\n\t\t\tpy = Expression \"Top\" 50;\n\t\t\twid = Expression \"Width\" 100;\n\t\t\tthick = Scale \"Line thickness\" 1 50 3;\n\t\t\ttext = String \"Dimension text\" \"50μm\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\tpos = Option \"Position Text\" [\"Above\", \"Below\"] 1;\n\t\t\tvp = Option \"Dimension by\" [\n\t\t\t\t\"Inner Vertical Edge\", \n\t\t\t\t\"Centre of Vertical\", \n\t\t\t\t\"Outer Vertical Edge\"\n\t\t\t] 1;\n            dpi = Expression \"DPI\" 100;\n            ink = Colour \"Lab\" [50,0,0];\n      \n            _result\n                = map_unary process x\n            {\n                process im\n                    = blend (Image scale) ink' im\n                {\n                    // make an ink compatible with the image\n                    ink' = colour_transform_to (get_type im) ink;\n\n                    x = to_real px;\n                    y = to_real py;\n                    w = to_real wid;\n                    d = to_real dpi;\n\n                    t = floor thick;\n\n                    bg = image_new (get_width im) (get_height im) (get_bands im)\n                        (get_format im) (get_coding im) (get_type im) 0 0 0;\n                    draw_block x y w t im =\n                        draw_rect_width x y w t true 1 [255] im;\n                    label = im_text text.value font.value w 1 d;\n                    lw = get_width label;\n                    lh = get_height label;\n                    ly = [y - lh - t, y + 2 * t]?pos;\n                    vx = [\n\t\t\t\t\t\t[x - t, x + w],\n\t\t\t\t\t\t[x - t / 2, x + w - t / 2],\n\t\t\t\t\t\t[x, x + w - t]\n\t\t\t\t\t]?vp;\n\n\t\t\t\t\tscale = (draw_block x y w t @\n\t\t\t\t\t\tdraw_block vx?0 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tdraw_block vx?1 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tinsert_noexpand (x + w / 2 - lw / 2) ly label)\n\t\t\t\t\t\tbg;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise Join\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t// we can't use map_unary since chop-into-tiles returns a group of\n\t\t\t// groups and we want to be able to reassemble that\n\t\t\t// TODO: chop-into-tiles should return an array class which\n\t\t\t// displays as group but does not have the looping behaviour?\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n\n\tArrayFL_item = class\n\t\tMenuaction \"_Array from List\"\n\t\t\t\"join a list of images into a single image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tncol = Number \"Max. Number of Columns\" 1;\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t_l \n\t\t\t\t= split_lines ncol.value x.value, is_Group x\n\t\t\t\t= split_lines ncol.value x;\n\n\t\t\t_result\n\t\t\t\t= (image_set_origin 0 0 @\n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value\n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list _l));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tGaussian_item = class \n\t\tMenuaction \"Gaussian _Noise\" \"make an image of gaussian noise\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t_result = Image (im_gaussnoise (to_real nwidth) (to_real nheight) \n\t\t\t\tmean.value deviation.value);\n\t\t}\n\t}\n\n\tFractal_item = class \n\t\tMenuaction \"_Fractal\" \"make a fractal image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t}\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n\tColour_atlas_item = class\n\tMenuaction \"_Colour Atlas\"\n\t\t\"make a grid of patches grouped around a colour\" {\n\t\taction = class \n\t\t\t_result {   \n\t\t\t_vislevel = 3;\n       \n\t\t\tstart = Colour_picker \"Lab\" [50,0,0];\n\t\t\tnstep = Expression \"Number of steps\" 9;\n\t\t\tssize = Expression \"Step size\" 10; \n\t\t\tpsize = Expression \"Patch size\" 32;\n\t\t\tsepsize = Expression \"Separator size\" 4;\n\t\n\t\t\t_result\n\t\t\t\t= colour_transform_to (get_type start) blocks'''\n\t\t\t{\n\t\t\t\tsize = (to_real nstep * 2 + 1) * to_real psize - \n\t\t\t\t\tto_real sepsize;\n\t\t\t\txy = make_xy size size; \n\n\t\t\t\txy_grid = (xy % to_real psize) < \n\t\t\t\t\t(to_real psize - to_real sepsize);\n\t\t\t\tgrid = xy_grid?0 & xy_grid?1;\n\n\t\t\t\tblocks = (int) (to_real ssize * ((int) (xy / to_real psize)));\n\t\t\t\tlab_start = colour_transform_to Image_type.LAB start;\n\t\t\t\tblocks' = blocks - to_real nstep * to_real ssize + \n\t\t\t\t\tVector (tl lab_start.value);\n\t\t\t\tblocks'' = hd lab_start.value ++ Image blocks';\n\t\t\t\tblocks''' \n\t\t\t\t\t= image_set_type Image_type.LAB blocks'', Image grid\n\t\t\t\t\t= 0;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.3/Magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate Magick.def\n   13-Apr-2014 snibgo\n     Put \"new image\" items into sub-menu.\n     New class VirtualPixlBack.\n   17-Apr-2014 snibgo\n     Many small changes.\n     A few new menu options.\n     Created sub-menu for multi-input operations.\n   3-May-2014 jcupitt\n     Put quotes around ( in shadow to help unix\n\n   Last update: 17-Apr-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n*/\n\n// We don't need Noop.\n/*===\nMagick_noop_item = class\n\tMenuaction \"_Noop\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_testPar_item = class\n\tMenuaction \"_TestPar\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"( +clone ) +append \",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/* Removed Read_item and Write_item, much better to use nip2 load/save image.\n * Plus they can load all libMagick formats anyway.\n */\n\n\n// Put \"new image\" items into sub-menu\nMagick_NewImageMenu_item = class\n\tMenupullright \"_New image\" \"make a new image\" {\n\n\tMagick_newcanvas_item = class\n\t\tMenuaction \"_Solid colour\" \"make image of solid colour\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tcolour = Magick.generalcol_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"\\\"canvas:\" ++ colour._flag ++ \"\\\"\", \n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_builtin_item = class\n\t\tMenuaction \"_Built-in image\" \"create a built-in image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbuiltin = Magick.builtin_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tbuiltin._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_gradient_item = class\n\t\tMenuaction \"_Gradient\" \"make a linear gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\ttopColour = Magick.generalcol_widget;\n\t\t\tbottomColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"gradient:\", \n\t\t\t\t\ttopColour._flag, \"-\", bottomColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_hald_item = class\n\t\tMenuaction \"_Hald-clut image\" \"create an identity hald-clut image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torder = Expression \"order\" 8;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"hald:\" ++ print order.expr,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_pattern_item = class\n\t\tMenuaction \"_Pattern\" \"create pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tpattern = Magick.pattern_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tpattern._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_plasma_item = class\n\t\tMenuaction \"_Plasma image\" \"create plasma image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\t// FIXME? ColourA-ColourB.\n\t\t\t// FIXME? Allow plasma:fractal?\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"plasma:\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_radialgradient_item = class\n\t\tMenuaction \"_Radial gradient\" \n\t\t\t\"make a radial gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tinnerColour = Magick.generalcol_widget;\n\t\t\touterColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"radial-gradient:\", \n\t\t\t\t\tinnerColour._flag, \"-\", outerColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n}  // end Magick_NewImageMenu_item\n\n\nMagick_MultiMenu_item = class\n\tMenupullright \"_Multiple inputs\" \"make an image from multiple images\" {\n\n\tMagick_composite_item = class\n\t\tMenuaction \"_Composite\" \"composite two images (without mask)\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag,\n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_compositeMask_item = class\n\t\tMenuaction \"_Composite masked\" \"composite two images (with mask)\" {\n\t\taction x y z = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag, \n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system3 command x y z; \n\t\t}\n\t}\n\n\t// FIXME: other operations like remap that take another image as arguments are:\n\t// mask (pointless?), texture, tile (pointless?)\n\n\t// FIXME: operations that take a filename that isn't an image:\n\t// cdl, profile\n\n\tMagick_clut_item = class\n\t\tMenuaction \"_Clut\" \"replace values using second image as colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// FIXME: uses -intensity \"when mapping greyscale CLUT image to alpha channel if set by -channels\"\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_haldclut_item = class\n\t\tMenuaction \"_Hald clut\" \"replace values using second image as Hald colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-hald-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\n\t// Encipher and decipher: key files can be text or image files.\n\n\tMagick_encipher_item = class\n\t\tMenuaction \"_Encipher/Decipher\" \"encipher or decipher an image image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname = Pathname \"Read key file\" \"\";\n\t\t\tisDecipher = Toggle \"Decipher\" false;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname.value == \"\" then \"\" else (\n\t\t\t\t\t( if isDecipher then \"-decipher \" else \"-encipher \") ++\n\t\t\t\t\t( \"\\\"\" ++ pathname.value ++ \"\\\"\" )\n\t\t\t\t),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_profile_item = class\n\t\tMenuaction \"_Profile\" \"assigns/applies an ICC profile\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname1 = Pathname \"Read profile file\" \"\";\n\t\t\tpathname2 = Pathname \"Read profile file\" \"\";\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname1.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname1.value ++ \"\\\"\"),\n\t\t\t\tif pathname2.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname2.value ++ \"\\\"\"),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_remap_item = class\n\t\tMenuaction \"_Remap\" \"reduce colours to those in another image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-remap\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n}  // end Magick_MultiMenu_item\n\n\nMagick_image_type_item = class\n\tMenuaction \"_Image Type\" \"change image type\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\timagetype = Magick.imagetype_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\timagetype._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nsep2 = Menuseparator;\n\nMagick_alpha_item = class\n\tMenuaction \"_Alpha\" \"add/remove alpha channel\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\talpha = Magick.alpha_widget; \n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\talpha._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_annotate_item = class\n\tMenuaction \"_Annotate\" \"add text annotation\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttext = Magick.text_widget;\n\t\tfont = Magick.Font_widget;\n\t\tgeometry = Magick.AnnotGeometry_widget; \n\t\tgravity = Magick.gravity_widget; \n\t\tforeground = Magick.foreground_widget;\n\t\tundercol = Magick.undercol_widget;\n\t\tantialias = Magick.antialias_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfont._flag,\n\t\t\tantialias._flag,\n\t\t\tgravity._flag,\n\t\t\tforeground._flag,\n\t\t\tundercol._flag,\n\t\t\t\"-annotate\", \n\t\t\tgeometry._flag, \n\t\t\t\"\\\"\" ++ text.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoGamma_item = class\n\tMenuaction \"_AutoGamma\" \"automatic gamma\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-gamma\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoLevel_item = class\n\tMenuaction \"_AutoLevel\" \"automatic level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-level\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_blurSharpMenu_item = class\n\tMenupullright \"_Blur/Sharpen\" \"blur and sharpen\" {\n\n\tMagick_adaptive_blur_item = class\n\t\tMenuaction \"_Adaptive Blur\" \"blur less near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\t// note: adaptive-blur doesn't regard VP.\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-adaptive-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blur_item = class\n\t\tMenuaction \"_Blur\" \"blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_gaussianBlur_item = class\n\t\tMenuaction \"_Gaussian Blur\" \"blur with a Gaussian operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-gaussian-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_motionBlur_item = class\n\t\tMenuaction \"_Motion Blur\" \"simulate motion blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tangle = Scale \"angle\" (-360) 360 0;\n\t\t\tchannels = Magick.ch_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-motion-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_rotationalBlur_item = class\n\t\tMenuaction \"_RotationalBlur\" \"blur around the centre\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-radial-blur\", \n\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_selectiveBlur_item = class\n\t\tMenuaction \"_Selective Blur\" \"blur where contrast is less than or equal to threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-selective-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++  \"+\" ++\n\t\t\t\t\tprint threshold.value ++ \"%%\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMagick_adaptive_sharpen_item = class\n\t\tMenuaction \"_Adaptive Sharpen\" \"sharpen more near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\t\"-adaptive-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_sharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"sharpen\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_unsharpen_item = class\n\t\tMenuaction \"_Unsharp\" \"sharpen with unsharp mask\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tgain = Scale \"Gain\" (-10) 10 1;\n\t\t\tthreshold = Scale \"Threshold\" 0 1 0.05;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-unsharp\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint gain.value ++ \"+\" ++\n\t\t\t\t\tprint threshold.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end BlurSharpMenu_item\n\n\nMagick_border_item = class\n\tMenuaction \"_Border\" \"add border of given colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcompose = Magick.compose_widget;\n\t\twidth = Expression \"Width\" 3;\n\t\tbordercol = Magick.bordercol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag,\n\t\t\tbordercol._flag,\n\t\t\t\"-border\", \n\t\t\tprint width.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_brightCont_item = class\n\tMenuaction \"_Brightness-contrast\" \"adjust the brightness and/or contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbri = Scale \"brightness\" (-100) 100 0;\n\t\tcon = Scale \"contrast\" (-100) 100 0;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-brightness-contrast\", \n\t\t\tprint bri.value ++ \"x\" ++ print con.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// Note: canny requires ImageMagick 6.8.9-0 or later.\n\nMagick_canny_item = class\n\tMenuaction \"_Canny\" \"detect a wide range of edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tlowPc = Scale \"lower percent\" 0 100 10;\n\t\thighPc = Scale \"lower percent\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-canny\", \n\t\t\tconcat [\"\\\"\",\n\t\t\t\tprint radius.value ++ \"x\" ++ \n\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\tprint lowPc.value ++ \"%%+\" ++\n\t\t\t\tprint highPc.value ++ \"%%\" ++ \"\\\"\"\n\t\t\t],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_charcoal_item = class\n\tMenuaction \"_Charcoal\" \"simulate a charcoal drawing\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tfactor = Scale \"factor\" 0 50 1;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-charcoal\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_chop_item = class\n\tMenuaction \"_Chop\" \"remove pixels from the interior\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-chop\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorize_item = class\n\tMenuaction \"_Colorize\" \"colorize by given amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tval = Scale \"value\" 0 100 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-colorize\", \n\t\t\tprint val.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colors_item = class\n\tMenuaction \"_Colors\" \"reduce number of colors\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\t\tquantize = Magick.colorspace_widget;\n\t\tcolors = Expression \"Colours\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-quantize\", quantize._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\tdither._flag,\n\t\t\t\"-colors\", \n\t\t\tprint colors.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: color-matrix?\n\nMagick_colorspace_item = class\n\tMenuaction \"_Colourspace\" \"convert to arbitrary colourspace\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolsp = Magick.colorspace_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-colorspace\",\n\t\t\tcolsp._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorspaceGray_item = class\n\tMenuaction \"_Colourspace gray\" \"convert to gray using given intensity method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-colorspace gray\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrast_item = class\n\tMenuaction \"_Contrast\" \"increase or reduce the contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tisReduce = Toggle \"reduce contrast\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t(if isReduce then \"+\" else \"-\") ++ \"contrast\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrastStretch_item = class\n\tMenuaction \"_Contrast stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-contrast-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: convolve (bias, kernel)\n\nMagick_crop_item = class\n\tMenuaction \"_Crop\" \"cut out a rectangular region\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-crop\",\n\t\t\tgeometry._flag,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_deskew_item = class\n\tMenuaction \"_Deskew\" \"straighten the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\t// FIXME: toggle auto-crop?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-deskew\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_despeckle_item = class\n\tMenuaction \"_Despeckle\" \"reduce the speckles\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-despeckle\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_distort_item = class\n\tMenuaction \"_Distort\" \"distort using a method and arguments\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tdistort = Magick.distort_widget;\n\t\targs = String \"Arguments\" \"1,0\";\n\t\tisPlus = Toggle \"Extend to show entire image\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t(if isPlus then \"+\" else \"-\") ++ \"distort\",\n\t\t\tdistort._flag,\n\t\t\targs.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_draw_item = class\n\tMenuaction \"_Draw\" \"annotate with one or more graphic primitives\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\targs = String \"Arguments\" \"line 0,0 9,9 rectangle 10,10 20,20\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-draw\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_edge_item = class\n\tMenuaction \"_Edge\" \"detect edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-edge\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_emboss_item = class\n\tMenuaction \"_Emboss\" \"emboss\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-emboss\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_enhance_item = class\n\tMenuaction \"_Enhance\" \"enhance a noisy image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-enhance\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_equalize_item = class\n\tMenuaction \"_Equalize\" \"equalize the histogram\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-equalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_evaluate_item = class\n\tMenuaction \"_Evaluate\" \"evaluate an expression on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\toperation = Magick.evaluate_widget;\n\t\tval = Expression \"value\" 5;\n\t\tisPc = Toggle \"Value is percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag, \n\t\t\toperation._flag, \n\t\t\tprint val.expr ++ if isPc then \"%%\" else \"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_extent_item = class\n\tMenuaction \"_Extent\" \"set the image size and offset\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-extent\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_FlipFlopMenu_item = class\n\tMenupullright \"_Flip/flop\" \"flip/flop/transverse/transpose\" {\n\n\tMagick_flip_item = class\n\t\tMenuaction \"_Flip vertically\" \"mirror upside-down\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flip\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_flop_item = class\n\t\tMenuaction \"_Flop horizontally\" \"mirror left-right\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flop\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transpose_item = class\n\t\tMenuaction \"_Transpose\" \"mirror along the top-left to bottom-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transpose +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transverse_item = class\n\t\tMenuaction \"_Transverse\" \"mirror along the bottom-left to top-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transverse +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end Magick_FlipFlopMenu_item\n\n\nMagick_floodfill_item = class\n\tMenuaction \"_Floodfill\" \"recolour neighbours that match\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tfuzz = Magick.fuzz_widget;\n\t\tcoordinate = Magick.coordinate_widget;\n\n\t\t// -draw \"color x,y floodfill\"\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-draw \\\" color\",\n\t\t\tcoordinate._flag,\n\t\t\t\"floodfill \\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_frame_item = class\n\tMenuaction \"_Frame\" \"surround with border or beveled frame\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tborder = Magick.bordercol_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tmatte = Magick.mattecol_widget;\n\t\tgeometry = Magick.FrameGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tborder._flag, \n\t\t\tmatte._flag, \n\t\t\t\"-frame\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_function_item = class\n\tMenuaction \"_Function\" \"evaluate a function on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfunction = Magick.function_widget;\n\t\t// FIXME: explain values; use sensible defaults.\n\t\tvalues = String \"values\" \"0,0,0,0\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-function\", \n\t\t\tfunction._flag, \n\t\t\tvalues.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_fx_item = class\n\tMenuaction \"_Fx\" \"apply a mathematical expression\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\targs = String \"Expression\" \"u*1/2\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\tinterpolate._flag,\n\t\t\tvirtpixback._flag,\n\t\t\t\"-fx\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gamma_item = class\n\tMenuaction \"_Gamma\" \"apply a gamma correction\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tgamma = Magick.gamma_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-gamma\",\n\t\t\tprint gamma.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradient_item = class\n\tMenuaction \"_Gradient\" \"apply a linear gradient\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolourA = Magick.generalcol_widget;\n\t\tcolourB = Magick.generalcol_widget;\n\n\t\tposition = Option \"colourA is at\" [\n\t\t\t\t\"top\", \"bottom\", \n\t\t\t\t\"left\", \"right\", \n\t\t\t\t\"top-left\", \"top-right\", \n\t\t\t\t\"bottom-left\", \"bottom-right\"] 0;\n\t\t_baryArg\n\t\t\t= concat [\"0,0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 0\n\t\t\t= concat [\"0,0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 1\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],0,\", colourB._flag], position.value == 2\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],0,\", colourA._flag], position.value == 3\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourB._flag], position.value == 4\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 5\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 6\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourA._flag], position.value == 7\n\t\t\t= \"dunno\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color barycentric \\\"\" ++ _baryArg ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradientCorn_item = class\n\tMenuaction \"_Gradient corners\" \n\t\t\"apply a bilinear gradient between the corners\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour_top_left = Magick.generalcol_widget;\n\t\tcolour_top_right = Magick.generalcol_widget;\n\t\tcolour_bottom_left = Magick.generalcol_widget;\n\t\tcolour_bottom_right = Magick.generalcol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color bilinear \\\"\" ++\n\t\t\t\t\"0,0,\" ++ colour_top_left._flag ++\n\t\t\t\t\",%%[fx:w-1],0\" ++ colour_top_right._flag ++\n\t\t\t\t\",0,%%[fx:h-1]\" ++ colour_bottom_left._flag ++\n\t\t\t\t\",%%[fx:w-1],%%[fx:h-1]\" ++ colour_bottom_right._flag ++ \"\\\"\",\n\t\t\t\"+depth\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_histogram_item = class\n\tMenuaction \"_Histogram\" \"make a histogram image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-define histogram:unique-colors=false histogram:\" ++\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_implode_item = class\n\tMenuaction \"_Implode\" \"implode pixels about the center\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfactor = Scale \"factor\" 0 20 1;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\t// FIXME: virtual-pixel?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tinterpolate._flag,\n\t\t\t\"-implode\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_level_item = class\n\tMenuaction \"_Level\" \"adjust the level of channels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"black point\" (-100) 200 0;\n\t\twht = Scale \"white point\" (-100) 200 100;\n\t\tgam = Scale \"gamma\" 0 30 1;\n\t\tisPc = Toggle \"Levels are percent\" true;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \",\" ++ \n\t\t\t\tprint wht.value ++ (if isPc then \"%%\" else \"\") ++ \",\" ++ \n\t\t\t\tprint gam.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_levelCols_item = class\n\tMenuaction \"_Level colors\" \"adjust levels to given colours\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcolour_black = Magick.generalcol_widget;\n\t\tcolour_white = Magick.generalcol_widget;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level-colors\",\n\t\t\t\"\\\"\" ++ colour_black._flag ++ \",\" ++ colour_white._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_linearStretch_item = class\n\tMenuaction \"_Linear stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-linear-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_magnify_item = class\n\tMenuaction \"_Magnify\" \"double the size of the image with pixel art scaling\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-magnify\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_modulate_item = class\n\tMenuaction \"_Modulate\" \"modulate brightness, saturation and hue\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmodcolsp = Magick.ModColSp_widget;\n\t\tbright = Scale \"brightness\" 0 200 100;\n\t\tsat = Scale \"saturation\" 0 200 100;\n\t\thue = Scale \"hue\" 0 200 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tmodcolsp._flag,\n\t\t\t\"-modulate\",\n\t\t\tprint bright.value ++ \",\" ++ print sat.value ++ \",\" ++ \n\t\t\t\tprint hue.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_monochrome_item = class\n\tMenuaction \"_Monochrome\" \"transform to black and white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// FIXME: also intensity?\n\n\t\tintensity = Magick.intensity_widget;\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tdither._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\t\"-monochrome\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_morphology_item = class\n\t// See http://www.imagemagick.org/Usage/morphology/\n\tMenuaction \"_Morphology\" \"apply a morphological method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmethod = Magick.morphmeth_widget;\n\t\titer = Expression \"Iterations (-1=repeat until done)\" 1;\n\n\t\tkernel = Magick.kernel_widget;\n\t\t// FIXME: custom kernel eg \"3x1+2+0:1,0,0\"\n\t\t//   width x height + offsx + offsy : {w*h values}\n\t\t//   each value is 0.0 to 1.0 or \"NaN\" or \"-\"\n\n\t\t// kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0\n\t\t// but\n\t\t//   ring takes: radius1, radius2, scale\n\t\t//   rectangle and comet take: width x height + offsx + offsy\n\t\t//   blur takes: radius x sigma\n\t\t// FIXME: for now, simply allow any string input.\n\t\tkernel_arg = String \"Kernel arguments\" \"\";\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-morphology\",\n\t\t\tmethod._flag ++ \":\" ++ print iter.expr, \n\t\t\tkernel._flag ++\n\t\t\t(if kernel_arg.value == \"\" then \"\" else \":\") ++ kernel_arg.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_negate_item = class\n\tMenuaction \"_Negate\" \"negate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-negate\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_addNoise_item = class\n\tMenuaction \"_add Noise\" \"add noise\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tattenuate = Scale \"attenuate\" 0 1.0 1.0;\n\t\tnoise = Magick.noise_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-attenuate\", \n\t\t\tprint attenuate.value,\n\t\t\tnoise._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_normalize_item = class\n\tMenuaction \"_Normalize\" \"normalize\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-normalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_opaque_item = class\n\tMenuaction \"_Opaque\" \"change this colour to the fill colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfill = Magick.foreground_widget;\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfill._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"opaque\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_paint_item = class\n\tMenuaction \"_Paint\" \"simulate an oil painting\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"radius\" 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-paint\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/*=== FIXME Bug; remove for now.\nPolaroid_item = class\n\tMenuaction \"_Polaroid\" \"simulate a polaroid picture\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle\" (-90) 90 20;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-polaroid\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_posterize_item = class\n\tMenuaction \"_Posterize\" \"reduce to (n) levels per channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tlevels = Expression \"levels\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-posterize\",\n\t\t\tprint levels.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_raise_item = class\n\tMenuaction \"_Raise\" \"lighten or darken image edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthk = Expression \"Thickness\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-raise\",\n\t\t\tprint thk.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_resize_item = class\n\tMenuaction \"_Resize\" \"resize to given width and height\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfilter = Magick.filter_widget;\n\t\ttype = Magick.ResizeType_widget;\n\t\twidth = Scale \"Width\" 1 100 10;\n\t\theight = Scale \"Height\" 1 100 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfilter._flag,\n\t\t\t\"-\" ++ type._flag,\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"!\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_roll_item = class\n\tMenuaction \"_Roll\" \"roll an image horizontally or vertically\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trollx = Expression \"X\" 3;\n\t\trolly = Expression \"Y\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-roll\",\n\t\t\t(if rollx.expr >= 0 then \"+\" else \"\") ++ print rollx.expr ++\n\t\t\t(if rolly.expr >= 0 then \"+\" else \"\") ++ print rolly.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_rotate_item = class\n\tMenuaction \"_Rotate\" \"rotate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"+distort\",\n\t\t\t\"SRT\",\n\t\t\tprint angle.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -segment, but cluster-threshold should be percentage of image area.\n\nMagick_sepia_item = class\n\tMenuaction \"_Sepia tone\" \"simulate a sepia-toned photo\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sepia-tone\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shade_item = class\n\tMenuaction \"_Shade\" \"shade with a distant light source\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tazimuth = Scale \"Azimuth (degrees)\" (-360) 360 0;\n\t\televation = Scale \"Elevation (degrees)\" 0 90 45;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shade\",\n\t\t\tprint azimuth.value ++ \"x\" ++ print elevation.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shadow_item = class\n\tMenuaction \"_Shadow\" \"simulate a shadow\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshadowCol = Magick.generalcol_widget;\n\t\topacity = Scale \"Opacity (percent)\" 0 100 75;\n\t\tsigma = Scale \"Sigma\" 0 30 2;\n\t\t// FIXME: make offsets a single widget?\n\t\toffsx = Scale \"X-offset\" (-20) 20 4;\n\t\toffsy = Scale \"Y-offset\" (-20) 20 4;\n\t\tarePc = Toggle \"offsets are percentages\" false;\n\n\t\t// FIXME: raw operation creates page offset, which vips dislikes.\n\t\t// So we take this futher, compositing with source.\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"(\\\" +clone\",\n\t\t\t\"-background\", \"\\\"\" ++ shadowCol._flag ++ \"\\\"\",\n\t\t\t\"-shadow\",\n\t\t\tconcat [\n\t\t\t\t\"\\\"\",\n\t\t\t\tprint opacity.value, \"x\", print sigma.value,\n\t\t\t\t(if offsx.value >= 0 then \"+\" else \"\"), print offsx.value,\n\t\t\t\t(if offsy.value >= 0 then \"+\" else \"\"), print offsy.value,\n\t\t\t\t(if arePc then \"%%\" else \"\"),\n\t\t\t\t\"\\\"\"\n\t\t\t],\n\t\t\t\"\\\")\\\" +swap -background None -layers merge\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shave_item = class\n\tMenuaction \"_Shave\" \"shave pixels from the edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 0 50 10;\n\t\theight = Scale \"Height\" 0 50 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shave\",\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shear_item = class\n\tMenuaction \"_Shear\" \"shear along the x-axis and/or y-axis\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-shear\",\n\t\t\tprint shearX.expr ++ \"x\" ++ print shearY.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sigmoid_item = class\n\tMenuaction \"_Sigmoid\" \"increase or decrease mid-tone contrast sigmoidally\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcontrast = Scale \"contrast\" 0 30 3;\n\t\tmidpoint = Scale \"mid-point (percent)\" 0 100 50;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"sigmoidal-contrast\",\n\t\t\t\"\\\"\" ++ print contrast.value ++ \"x\" ++ \n\t\t\t\tprint midpoint.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sketch_item = class\n\tMenuaction \"_Sketch\" \"simulate a pencil sketch\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tangle = Scale \"angle\" (-360) 360 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sketch\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if angle >= 0 then (\"+\" ++ print angle.value) else \"\"),\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_solarize_item = class\n\tMenuaction \"_Solarize\" \"negate all pixels above a threshold level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-solarize\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -sparse-color needs abitrary list of {x,y,colour}.\n\nMagick_splice_item = class\n\tMenuaction \"_Splice\" \"splice a colour into the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-splice\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_spread_item = class\n\tMenuaction \"_Spread\" \"displace pixels by random amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tamount = Expression \"Amount (pixels)\" 5;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"-spread\",\n\t\t\tprint amount.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_statistic_item = class\n\tMenuaction \"_Statistic\" \"replace each pixel with statistic from neighbourhood\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width\" 5;\n\t\theight = Expression \"Height\" 5;\n\t\tstatisticType = Magick.StatType_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-statistic\", \n\t\t\tstatisticType._flag, \n\t\t\tprint width.expr ++ \"x\" ++ print height.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_swirl_item = class\n\tMenuaction \"_Swirl\" \"swirl around the centre\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Magick.angle_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-swirl\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_thresholdMenu_item = class\n\tMenupullright \"_Threshold\" \"make black or white\" {\n\n\tMagick_threshold_item = class\n\t\tMenuaction \"_Threshold\" \"apply black/white threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-threshold\", \n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blackThreshold_item = class\n\t\tMenuaction \"_Black threshold\" \"where below threshold set to black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-black-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_whiteThreshold_item = class\n\t\tMenuaction \"_White threshold\" \"where above threshold set to white\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-white-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_latThreshold_item = class\n\t\tMenuaction \"_Local Adaptive Threshold\" \"where above average plus offset set to white, otherwise black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twidth = Expression \"Width\" 10;\n\t\t\theight = Expression \"Height\" 10;\n\t\t\toffset = Scale \"Offset (percent)\" (-100) 100 0;\n\t\t\t// note: \"-lat\" doesn't respond to channels\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-lat\",\n\t\t\t\tconcat [\"\\\"\", print width.expr, \"x\", print height.expr, \n\t\t\t\t\t(if offset.value >= 0 then \"+\" else \"\"), print offset.value,\n\t\t\t\t\t\"%%\\\"\"\n\t\t\t\t],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_randThreshold_item = class\n\t\tMenuaction \"_Random Threshold\" \"between specified limits, apply random threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tlow = Scale \"Low threshold\" 0 100 10;\n\t\t\thigh = Scale \"High threshold\" 0 100 90;\n\t\t\tisPc = Toggle \"Thresholds are percent\" true;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-random-threshold\", \n\t\t\t\t\"\\\"\" ++ print low.value ++ \"x\" ++ print high.value ++\n\t\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end ThresholdMenu_item\n\n\n// Note: alternatives include:\n// convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif\n\nMagick_tile_item = class\n\tMenuaction \"_Tile\" \"fill given size with tiled image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tsize = Magick.Size_widget;\n\n\t\tcommand = Magick.command [\n\t\t\tsize._flag,\n\t\t\t\"tile:\" ++ \"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_tint_item = class\n\tMenuaction \"_Tint\" \"apply a tint\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tamount = Scale \"amount (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-tint\",\n\t\t\t// snibgo note: although the amount is a percentage, it doesn't need \"%\" character.\n\t\t\tprint amount.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_transparent_item = class\n\tMenuaction \"_Transparent\" \"make this colour transparent\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"transparent\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_trim_item = class\n\tMenuaction \"_Trim\" \"trims away border\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfuzz = Magick.fuzz_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-trim +repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_uniqueCols_item = class\n\tMenuaction \"_Unique colours\" \"discard all but one of any pixel color\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-unique-colors\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_vignette_item = class\n\tMenuaction \"_Vignette\" \"soften the edges in vignette style\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\trx = Scale \"Rolloff x (percent)\" 0 100 10;\n\t\try = Scale \"Rolloff y (percent)\" 0 100 10;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-vignette\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if rx.value >= 0 then \"+\" else \"\") ++ print rx.value ++\n\t\t\t\t(if ry.value >= 0 then \"+\" else \"\") ++ print ry.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_wave_item = class\n\tMenuaction \"_Wave\" \"shear the columns into a sine wave\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tamplitude = Scale \"Amplitude (pixels)\" 0 100 10;\n\t\twavelength = Scale \"Wavelength (pixels)\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-wave\",\n\t\t\tprint amplitude.value ++ \"x\" ++ print wavelength.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\n"
  },
  {
    "path": "share/nip2/compat/8.3/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/8.3\n\nstart_DATA = \\\n\tColour.def \\\n\t_convert.def \\\n\tFilter.def \\\n\t_generate.def \\\n\tHistogram.def \\\n\tImage.def \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_list.def \\\n\t_magick.def \\\n\tMagick.def \\\n\tMath.def \\\n\tMatrix.def \\\n\t_Object.def \\\n\tObject.def \\\n\t_predicate.def \\\n\tPreferences.ws \\\n\t_stdenv.def \\\n\tTasks.def \\\n\t_types.def \\\n\tWidgets.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/8.3/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_AND\" \"bitwise AND of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_OR\" \"bitwise OR of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"_XOR\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_NOT\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBandand_item = Image_band_item.Bandand_item; \n\n\tBandor_item = Image_band_item.Bandor_item; \n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tDifference_item = class \n\t\tMenuaction \"_Difference\" \"difference of two lists\" {\n\t\taction a b = map_binary difference a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tValue_item = class \n\t\tMenuaction \"_Value\" \"value of point in object\" {\n\t\taction a = class _result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tposition = Expression \"Coordinate\" (0, 0);\n\t\n\t\t\t_result = map_binary point position.expr a;\n\t\t}\n\t}\n\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tSkew_item = class \n\t\tMenuaction \"S_kew\" \"skew of image or list or vector\" {\n\t\taction a = map_unary skew a;\n\t}\n\n\tKurtosis_item = class \n\t\tMenuaction \"Kurtosis\" \"kurtosis of image or list or vector\" {\n\t\taction a = map_unary kurtosis a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \n\t\t\t\"position of centre of gravity of histogram\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = linreg xes yes;\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = linregw xes yes devs;\n\t}\n\n\tCluster_item = class \n\t\tMenuaction \"_Cluster\" \"cluster a list of numbers\" {\n\t\taction l = class {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tthresh = Expression \"Threshold\" 10;\n\t\n\t\t\t[_r, _w] = cluster thresh.expr l;\n\t\n\t\t\tresult = _r;\n\t\t\tweights = _w;\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.3/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_identity_item = class \n\t\tMenuaction \"_Identity\" \"make an identity matrix\" {\n\t\taction = identity (identity_matrix 5);\n\t\t\n\t\tidentity v = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix (identity_matrix (to_real s)), to_real s != len v;\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = identity value;\n\t\t}\n\t}\n\n\tMatrix_series_item = class \n\t\tMenuaction \"_Series\" \"make a series\" {\n\t\taction = series (mkseries 0 1 5);\n\n\t\tmkseries s t e \n\t\t\t= transpose [[to_real s, to_real s + to_real t .. to_real e]];\n\n\t\tseries v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t_s = v?0?0;\n\t\t\t_t = v?1?0 - v?0?0;\n\t\t\t_e = (last v)?0;\n\n\t\t\ts = Expression \"Start value\" _s;\n\t\t\tt = Expression \"Step by\" _t;\n\t\t\te = Expression \"End value\" _e;\n\n\t\t\t_result \n\t\t\t\t= Matrix (mkseries s t e), \n\t\t\t\t\t\tto_real s != _s || to_real t != _t || to_real e != _e\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = series value;\n\t\t}\n\t}\n\n\tMatrix_square_item = class \n\t\tMenuaction \"_Square\" \"make a square matrix\" {\n\t\taction = square (mksquare 5);\n\n\t\tmksquare s = replicate s (take s [1, 1 ..]);\n\n\t\tsquare v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == to_real s\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mksquare (to_real s); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = square value;\n\t\t}\n\t}\n\n\tMatrix_circular_item = class \n\t\tMenuaction \"_Circular\" \"make a circular matrix\" {\n\t\taction = circle (mkcircle 3);\n\n\t\tmkcircle r\n\t\t\t\t= map2 (map2 pyth) xes yes\n\t\t{\n\t\t\tline = [-r .. r];\n\t\t\txes = replicate (2 * r + 1) line;\n\t\t\tyes = transpose xes;\n\t\t\tpyth a b \n\t\t\t\t\t= 1, (a**2 + b**2) ** 0.5 <= r\n\t\t\t\t\t= 0;\n\t\t}\n\n\t\tcircle v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tr = Expression \"Radius\" ((len v - 1) / 2);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mkcircle (to_real r); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = circle value;\n\t\t}\n\t}\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\nMatrix_sort_item = class \n\tMenuaction \"_Sort\" \"sort by column or row\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\to = Option (_ \"Orientation\") [\n\t\t\t_ \"Sort by column\",\n\t\t\t_ \"Sort by row\"\n\t\t] 0;\n\t\ti = Expression (_ \"Sort on index\") 0;\n\t\td = Option (_ \"Direction\") [\n\t\t\t_ \"Ascending\",\n\t\t\t_ \"Descending\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary sort x\n\t\t{\n\t\t\tidx = to_real i;\n\t\t\tpred a b \n\t\t\t\t= a?idx <= b?idx, d == 0\n\t\t\t\t= a?idx >= b?idx;\n\t\t\tsort x\n\t\t\t\t= (x.Matrix_base @ sortc pred) x.value,\n\t\t\t\t\to == 0\n\t\t\t\t= (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value;\n\t\t}\n\t}\n}\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ \n\t\t\t\t\trange;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.3/Object.def",
    "content": "Object_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nObject_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nObject_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nObject_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nObject_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.3/Preferences.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/7.41.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"680\" window_height=\"800\" filename=\"$VIPSHOME/share/$PACKAGE/start/Preferences.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"100\" lpane_open=\"false\" rpane_position=\"400\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"Preferences\">\n    <Column x=\"0\" y=\"3067\" open=\"false\" selected=\"false\" sform=\"false\" next=\"99\" name=\"B\" caption=\"Interface column -- don't touch this!\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"CSV_SEPARATOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"O1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PRINT_CARTIESIAN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F10.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"USE_GRAPHICSMAGICK\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D45.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_PANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"237\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"788\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"700\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"100\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RELOAD\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D42.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_STATUSBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR_STYLE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MATRIX_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_RECOMP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"N2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_MAX_UNDO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[-1,0,1,5,10]?N1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_FONT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"N4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_INTERLACE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_LINELENGTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D41.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A6.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE_FILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PPM_MODE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"G1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_LAYOUT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C16.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C18.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_MULTI_RES\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_FORMAT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_PREDICTOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_BIGTIFF\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_START\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D25.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_SEARCH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D2.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_TMP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_SLIDER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D28.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_REGION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D29.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_AUTO_WS_SAVE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D30.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_DISPLAY_LED\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLKITBROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_MAX_HEAP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D38.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PIN_FILESEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_STATUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CONVERSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_RULERS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CROSSHAIR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL_HQ\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E21.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_TRACE_FUNCTIONS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"H1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_DEVICE\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CHANNEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_BRIGHTNESS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_COLOUR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CONTRAST\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_HUE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_FRAMES\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J13.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_MONO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J14.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_LEFT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_TOP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_ASPECT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_MAX_BLEND_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_REFINE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_WINDOW_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_OBJECT_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_BALANCE_GAMMA\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"680\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER_REMOTE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"POPUP_NEW_ROWS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_HISTORY_MAX\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D43.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_CPUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D44.value\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2831\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"I\" caption=\"Mosaic defaults\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Maximum blend width&quot; 0 100 10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Refine tie-points&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search windows this size&quot; 30\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search for objects this size&quot; 10\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Image gamma for mosaic balance&quot; 1 3 1.6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2495\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"J\" caption=\"Video for linux\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"J2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;Device&quot; &quot;/dev/video&quot;\"/>\n            <Pathname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Channel&quot; [&quot;TV&quot;, &quot;Composite 1&quot;, &quot;Composite 2&quot;, &quot;Composite 3&quot;] 1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Brightness&quot; 0 32767 23000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Colour&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Contrast&quot; 0 32767 27000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Hue&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Number of frames to average&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Grab monochrome&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2208\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"K\" caption=\"General video capture\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"K1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Crop video: \" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Crop video&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop left&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop top&quot; 6\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number  &quot;Crop width&quot; 747\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop height&quot; 570\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Aspect ratio (stretch vertically\\nby this much)&quot; 1.202\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2072\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"M\" caption=\"PNG save options\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"M1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Compression&quot; (map print [0..9]) 6\"/>\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Interlace&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1970\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"G\" caption=\"PPM/PGM/PBM save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"PPM mode\" labelsn=\"2\" labels0=\"Binary\" labels1=\"ASCII\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Mode&quot; [&quot;Binary&quot;, &quot;ASCII&quot;] 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1620\" open=\"true\" selected=\"true\" sform=\"false\" next=\"27\" name=\"C\" caption=\"TIFF save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Compression&quot; [&quot;None&quot;, &quot;LZW&quot;, &quot;Zip (deflate)&quot;, &quot;PACKBITS&quot;, &quot;JPEG&quot;, &quot;CCITTFAX4&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;JPEG quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Deflate/LZW predictor&quot; [&quot;None&quot;,&quot;Horizontal difference&quot;,&quot;Floating-point&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Layout\" labelsn=\"2\" labels0=\"Strip\" labels1=\"Tile\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Layout&quot; [&quot;Strip&quot;, &quot;Tile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile width&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile height&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Multi-res&quot; [&quot;Single image&quot;, &quot;Image pyramid&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Format&quot; [&quot;No truncation&quot;,&quot;Save 1 band 8 bit images as 1 bit&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Save as BigTIFF&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1518\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"O\" caption=\"CSV save\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"String &quot;Separator character&quot; &quot;\\t&quot;\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1348\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"A\" caption=\"JPEG save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;ICC profile&quot; [&quot;Use image profile, if any&quot;, &quot;Embed profile from file&quot;, &quot;Don't attach a profile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Pathname/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;ICC profile file&quot; &quot;$VIPSHOME/share/nip2/data/sRGB.icm&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1144\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"F\" caption=\"Widgets\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Pin up file requestors&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Main window toolbar&quot; [&quot;Default style&quot;, &quot;Icon only&quot;, &quot;Text only&quot;, &quot;Icon and text&quot;, &quot;Icon and text to right&quot;] 0\"/>\n            <Option caption=\"Main window toolbar\" labelsn=\"5\" labels0=\"Default style\" labels1=\"Icon only\" labels2=\"Text only\" labels3=\"Icon and text\" labels4=\"Icon and text to right\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display LEDs in workspace&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display complex numbers as coordinates&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1044\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"H\" caption=\"Debug options\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Disassemble functions\" value=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;untitled&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"906\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"L\" caption=\"Help browser\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"L2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Command to start browser&quot; &quot;firefox&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Go-to-page argument&quot; &quot;-remote 'openURL(%s)'&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"734\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"N\" caption=\"Paintbox \">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Max undo steps\" labelsn=\"5\" labels0=\"Unlimited\" labels1=\"None\" labels2=\"1\" labels3=\"5\" labels4=\"10\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Max undo steps&quot; [&quot;Unlimited&quot;, &quot;None&quot;, &quot;1&quot;, &quot;5&quot;, &quot;10&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Fontname &quot;Default paintbox font&quot; &quot;Sans 12&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Fontname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update during paint&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"458\" open=\"true\" selected=\"false\" sform=\"false\" next=\"27\" name=\"E\" caption=\"Image display\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"E20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use crosshair cursor in image windows&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Thumbnail size&quot; 64\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;High-quality thumbnails&quot; false\"/>\n            <Toggle/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window width&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window height&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto image window pop up&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"46\" name=\"D\" caption=\"Calculation\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Data path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;data&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;data&quot;], &quot;.&quot;]\"/>\n            <Expression caption=\"Data path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Temporary files&quot; (path_relative [&quot;$SAVEDIR&quot;, &quot;tmp&quot;])\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Start path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;start&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;start&quot;]]\"/>\n            <Expression caption=\"Start path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D28\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update sliders during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update sliders during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D29\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update regions during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update regions during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D30\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto workspace save&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D42\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto-reload on file change&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D41\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Text display length (characters)&quot; 80\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D38\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Heap size (per workspace)&quot; 600000\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D43\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of VIPS functions to memoise&quot; 20000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D44\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of CPUs to use (0 for autodetect)&quot; 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D45\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use GraphicsMagick for Magick menu&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/compat/8.3/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\n\tCsv_import_item = class\n\t\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tstart_line = Expression \"Start at line\" 1;\n\t\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_csv2vips filename)\n\t\t\t{\n\t\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\t\tescape x \n\t\t\t\t\t= foldr prefix [] x\n\t\t\t\t{\n\t\t\t\t\tprefix x l\n\t\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t\t= x : l;\n\t\t\t\t}\n\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tRaw_import_item = class\n\t\tMenuaction \"_Raw Import\" \"read a file of binary values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tacross = Expression \"Pixels across\" 100;\n\t\t\tdown = Expression \"Pixels down\" 100;\n\t\t\tbytes = Expression \"Bytes per pixel\" 3;\n\t\t\tskip = Expression \"Skip over initial bytes\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_binfile path.value \n\t\t\t\t\tacross.expr down.expr bytes.expr skip.expr)\n\t\t\t{\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// interpret Analyze header for layout and calibration\n\tAnalyze7_header_item = class\n\t\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\t\"examine the Analyze header and set layout and value\" {\n\t\taction x \n\t\t\t= x'''\n\t\t{\n\t\t\t// read bits of header\n\t\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\t\tdim0 = dim 0 x;\n\t\t\tdim1 = dim 1 x;\n\t\t\tdim2 = dim 2 x;\n\t\t\tdim3 = dim 3 x;\n\t\t\tdim4 = dim 4 x;\n\t\t\tdim5 = dim 5 x;\n\t\t\tdim6 = dim 6 x;\n\t\t\tdim7 = dim 7 x;\n\t\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\t\n\t\t\t// oops, now a nop\n\t\t\tx' = x;\n\t\n\t\t\t// lay out higher dimensions width-ways\n\t\t\tx'' \n\t\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\t\tdim0 == 7\n\t\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\t\n\t\t\t// multiply by scale factor to get kBeq\n\t\t\tx''' = x'' * (cal_max / glmax);\n\t\t}\n\t}\n\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\t[image, patch] = sortc larger [a, b];\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n\t\t\tsample = measure_draw 6 4 (to_real measure) image;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\tmode = Option \"Input LUT\" [\n\t\t\t\t\"Linearize from chart greyscale\",\n\t\t\t\t\"Fit intercept from chart greyscale\",\n\t\t\t\t\"Linear input, set brightness from chart\",\n\t\t\t\t\"Linear input\"\n\t\t\t] 0;\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = measure_sample 6 4 (to_real measure) image;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb \n\t\t\t\t= Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0\n\t\t\t\t= Matrix [0: intercepts, replicate (_camera.width + 1) 1], \n\t\t\t\t\tmode == 1\n\t\t\t\t= Matrix [[0, 0], [1, 1]]\n\t\t\t{\n\t\t\t\tintercepts = [(linreg _true_grey_Y' cam).intercept :: \n\t\t\t\t\tcam <- transpose _camera_grey'];\n\t\t\t}\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\t// plot from 0 explicitly so we see the effect of mode1 (intercept\n\t\t\t// from greyscale)\n\t\t\tlinearising_lut = Plot [$ymin => 0] _linear_lut;\n\n\t\t\t// map an image though the lineariser\n\t\t\tlinear x\n\t\t\t\t= hist_map linearising_lut.value x, mode == 0 || mode == 1\n\t\t\t\t= x;\n\n\t\t\t// map the chart measurements though the lineariser\n\t\t\t_camera' = (to_matrix @ linear @ to_image) _camera;\n\n\t\t\t// solve for RGB -> XYZ\n\t\t\t// normalise: the 2nd row is what makes Y, so divide by that to\n\t\t\t// get Y in 0-1.\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\t_full_M = transpose (_pinv * (transpose _camera' * _true_XYZ));\n\t\t\tM = _full_M / scale;\n\t\t\tscale = sum _full_M.value?1;\n\n\t\t\t// now turn the camera to LAB and calculate dE76\n\t\t\t_camera'' = (to_matrix @ \n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @ \n\t\t\t\trecomb M @ \n\t\t\t\tmultiply scale @\n\t\t\t\tto_image) _camera';\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tavg_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0 && i < len macbeth_names\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\n\t\t\t// normalise brightness ... in linear mode, we optionally don't\n\t\t\t// set the brightness from the Macbeth chart\n\t\t\tnorm x \n\t\t\t\t= x * scale, mode != 3\n\t\t\t\t= x;\n\n\t\t\t// convert RGB camera to Lab\n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tnorm @\n\t\t\t\trecomb M @\n\t\t\t\tcast_float @\n\t\t\t\tlinear) image.value;\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b = class\n\t\t\t(map_binary process a b) {\n\t\t\tprocess a b\n\t\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t\t{\n\t\t\t\t// the name of the calib object we need\n\t\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t\t// get the Calibrate_chart arg first\n\t\t\t\t[image, calib] = sortc (const (is_instanceof calib_name)) \n\t\t\t\t\t[a, b];\n\n\t\t\t\tresult = (Image @\n\t\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\t\tcalib.norm @\n\t\t\t\t\trecomb calib.M @\n\t\t\t\t\tcast_float @\n\t\t\t\t\tcalib.linear) image.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [$style => style.value] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\t!is_list_len 2 images\n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = all (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize Kernel_linear xfactor yfactor scale_im;\n\t\t\t_offset_im = resize Kernel_linear xfactor yfactor offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.3/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.3/_Object.def",
    "content": "/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0|1|2|3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \n\tjoin_sep \"|\" Image_type.colour_spaces.names];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide|VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad properties for \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"where\" ++ \"\\n\" ++ arg_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make arg type notes\n\targ_types = join_sep \"\\n\" (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"\\n\" ++ _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = join_sep \"\\n\" all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if those fail as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if that fails as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary'_function op a b\n\t= matches1?0, matches1 != []\n\t= matches2?0, op.symmetric && matches2 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0, matches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t// these should always be defined\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x = oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x = oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op = oo_unary_function (oo_unary_lookup op) this;\n\n\too_binary_table op x = [];\n\too_unary_table op = [];\n}\n"
  },
  {
    "path": "share/nip2/compat/8.3/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= Image x.value, is_Plot x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n// like to_image, but we do 1x1 pixel + x, then embed it up\n// always make an unwrapped image for speed ... this gets used by ifthenelse\n// and stuff like that\n// format can be NULL, meaning set format from x\nto_image_size width height bands format x\n\t= x, is_image x\n\t= x.value, is_Image x\n\t= im''\n{\n\t// we want x to set the target format if we don't have one, so we\n\t// can't use image_new\n\tim = im_black 1 1 bands + x;\n\tim'\n\t\t= clip2fmt format im, format != NULL\n\t\t= im;\n\tim'' = embed 1 0 0 width height im';\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && is_list_len 3 x\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\nto_int x = (int) (to_real x);\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The outermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x \n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), !is_list_len 2 parts \n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, !is_list_len 4 parts \n\t= sign * (abs ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", \n\t\tmember \".0123456789\",\n\t\tmember \"eE\", \n\t\tmember \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tsign \n\t\t= 1, ipart > 0\n\t\t= -1;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), !is_list_len 5 parts \n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t$D93 => D93_whitepoint,\n\t$D75 => D75_whitepoint,\n\t$D65 => D65_whitepoint,\n\t$D55 => D55_whitepoint,\n\t$D50 => D50_whitepoint,\n\t$A => A_whitepoint,\n\t$B => B_whitepoint,\n\t$C => C_whitepoint,\n\t$E => E_whitepoint,\n\t$D3250 => D3250_whitepoint\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, image_set_type GREY16 @ im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\t[RGB16, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l = join_sep path_separator l;\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 > 1 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n/* Return $PATH, reformatted as [[\"comp1\", \"comp2\"], [\"comp1\", \"comp2\"] ..]\n */\nsystem_search_path\n\t= [vipsbin] ++\n\t\tmap path_parse (split (equal path_sep) (expand \"$PATH\"))\n{\n\t/* On some platforms we ship vips with a few extra progs. Search\n \t * $VIPSHOME/bin first.\n\t */\n\tvipsbin = path_parse (expand \"$VIPSHOME\") ++ [\"bin\"];\n\n\tpath_sep\n\t\t= ':', expand \"$SEP\" == \"/\"\n\t\t= ';';\n}\n\n/* Search $PATH for the first occurence of name, or \"\". \n */\nsearch_for name\n\t= hits?0, hits != []\n\t= \"\"\n{\n\texe_name = name ++ expand \"$EXEEXT\";\n\tform_path p = path_absolute (p ++ [exe_name]);\n\tpaths = map form_path system_search_path;\n\thits = dropwhile (equal []) (map search paths);\n}\n\n/* Search $PATH for the first occurence of name, error on failure. \n */\nsearch_for_error name\n\t= path, path != \"\"\n\t= error (exe_name ++ \" not found on your search path. \" ++\n\t\t\"Check you have installed the program and it is on your PATH.\")\n{\n\texe_name = name ++ expand \"$EXEEXT\";\n\tpath = search_for name;\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.3/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= embed 1 0 0 w h im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black 1 1 (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\nmkim options x y b\n    = Image (image_new x y b\n        (opt $format) (opt $coding) (opt $type)\n        (opt $pixel)\n        (opt $xoffset) (opt $yoffset))\n{\n    opt = get_option options [\n        $format => Image_format.UCHAR,\n        $coding => Image_coding.NOCODING,\n        $type => Image_type.sRGB,\n        $pixel => 0,\n        $xoffset => 0,\n        $yoffset => 0\n    ];\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = im_gauss_imask_sep (radius / 3) 0.2;\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n/* Make a colour from a temperature.\n */\ncolour_from_temp T\n\t= error (_ \"T out of range\"), T < 1667 || T > 25000\n\t= Colour \"Yxy\" [50, x, y]\n{\n\t// Kim et all approximation\n\t// see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation\n\tx\n\t\t= -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 +\n\t\t\t0.8776956 * 10 ** 3 / T + 0.179910, T < 4000\n\t\t= -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 +\n\t\t\t0.2226347 * 10 ** 3 / T + 0.240390;\n\n\ty \n\t\t= -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + \n\t\t\t2.18555832 * x - 0.20219638, T < 2222\n\t\t= -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + \n\t\t\t2.09137015 * x - 0.16748867, T < 4000\n\t\t=  3.0817580 * x ** 3 - 5.87338670 * x ** 2 +\n\t\t\t3.75112997 * x - 0.37001483;\n}\n\ntemp_from_colour z\n\t= T\n{\n\tc = colour_transform_to Image_type.YXY (to_colour z);\n\tx = c.value?1;\n\ty = c.value?2;\n\n\t// McCamy's approximation, see eg. \n\t// http://en.wikipedia.org/wiki/Color_temperature#Approximation\n\n\txe = 0.332;\n\tye = 0.1858;\n\tn = (x - xe) / (y - ye);\n\tT = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33;\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.3/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 1;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" \n\t] 4;\n\n\tcontrol_selection mask im no\n\t\t= [\n\t\t\tif mask then im * 1.2 else im * 1,\n\t\t\tif mask then im * 0.8 else im * 1,\n\t\t\tif mask then 0 else im,\n\t\t\tif mask then 255 else im,\n\t\t\tif mask then im else 0,\n\t\t\tif mask then im else 255,\n\t\t\tmask\n\t\t]?no;\n\n\tRectangle = class\n        Menuaction \"_Rectangle\"\n            \"use an Arrow or Region x to define a rectangle\"\n        {\n        action x = class\n            _result {\n            _vislevel = 3;\n\n            control = _control;   \n\n            _result = control_selection mask im control\n                  {\n                \tim = x.image;\n                \tmask = Image m\n                    {\n\t\t\t\t\t\trx     \n\t\t\t\t\t\t\t= x.region_rect, is_Region x\n\t\t\t\t\t\t\t= x;\n\t\t\t\t\t\tb     = image_new im.width im.height 1 0 0 1 0 0 0;\n\t\t\t\t\t\tw     = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0;\n\t\t\t\t\t\tm     = insert_noexpand rx.nleft rx.ntop w b; \n                     }\n                   }\n            }\n        }\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = get_image a;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = get_image ((pt_list.value)?0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tSegment_item = class\n\t\tMenuaction \"_Segment\" \"break image into disjoint regions\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsegments\n\t\t\t\t= Expression \"Number of disjoint regions\" \n\t\t\t\t\t(map_unary (get_header \"n-segments\") _result);\n\n\t\t\t_result = map_unary segment x;\n\t\t}\n\t}\n\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize Kernel_linear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize Kernel_linear f1 1 b1\n\t\t\t\t\t{b1 = resize Kernel_linear 1 f2 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/8.3/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = Image (get_image line);\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = Image (get_image (pt_l?0));\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t};\n\nMount_options _ctype _ppcm = class \n  {\n  _vislevel = 3;\n  apply = Toggle \"Apply mount options\" false;\n  ls = Expression \"Lower mount section bigger by (cm)\" 0;\n  mount_colour = Colour _ctype [0, 0, 0];\n  _los = ls.expr * _ppcm;\n  };\n\nFrame_variables comp = class\n  {\n  _vislevel = 3;\n\n  scale_factor = Expression \"scale the size of the frame by\" 1;\n\n  /* These sliders define the fraction of the frames width or height is extracted\n   * to produce each of the particular regions.\n   */\n  corner_section = Scale \"Corner section\" 0.1 1 0.5;\n  edge_section = Scale \"Edge section\" 0.1 1 0.2, comp > 0\n\t\t\t\t  = \"Only required for complex frames\";\n  middle_section = Scale \"Middle section\" 0.1 1 0.2;\n  blend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n  option = Toggle \"Use mirror of left-side to make right\" true;\n  };\n\n"
  },
  {
    "path": "share/nip2/compat/8.3/_list.def",
    "content": "/* any l: or all the elements of list l together\n *\n * any (map (equal 0) list) == true, if any element of list is zero.\n * any :: [bool] -> bool\n */\nany = foldr logical_or false;\n\n/* all l: and all the elements of list l together\n *\n * all (map (==0) list) == true, if every element of list is zero.\n * all :: [bool] -> bool\n */\nall = foldr logical_and true;\n\n/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* delete eq x l: delete the first x from l\n *\n * delete equal 'b' \"abcdb\" == \"acdb\"\n * delete :: (* -> bool) -> * -> [*] -> [*]\n */\ndelete eq a l\n\t= [], l == []\n\t= y, eq a b\n\t= b : delete eq a y\n{\n\tb:y = l;\n}\n\n/* difference eq a b: delete b from a\n *\n * difference equal \"asdf\" \"ad\" == \"sf\"\n * difference :: (* -> bool) -> [*] -> [*] -> [*]\n */\ndifference = foldl @ converse @ delete;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn x, fn a\n\t= l\n{\n\ta:x = l;\n}\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* flatten x: flatten a list of lists of things into a simple list\n *\n * flatten :: [[*]] -> [*]\n */\nflatten x\n\t= foldr flat [] x, is_list x\n\t= x\n{\n\tflat x sofar\n\t\t= foldr flat sofar x, is_list x\n\t\t= x : sofar;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st x) xs\n{\n\tx:xs = l;\n}\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn x xs\n{\n\tx:xs = l;\n}\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn x (foldr fn st xs)\n{\n\tx:xs = l;\n}\n\n/* foldr1 fn l: like foldr, but use the last element as the start value\n *\n * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= x, xs == []\n\t= fn x (foldr1 fn xs)\n{\n\tx:xs = l;\n}\n\n/* Search a list for an element, returning its index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn x\n\t\t= search xs (n + 1)\n\t\t{\n\t\t\tx:xs = l;\n\t\t}\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= x : init xs\n{\n\tx:xs = l;\n}\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* join_sep sep l: join a list with a separator\n *\n * join_sep \", \" (map print [1 .. 4]) == \"1, 2, 3, 4\"\n * join_sep :: [*] -> [[*]] -> [*]\n */\njoin_sep sep l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ sep ++ b;\n}\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= x, xs == []\n\t= last xs\n{\n\tx:xs = l;\n}\n\n/* len l: length of list l\n * (see also is_list_len and friends in predicate.def)\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta:b:x = l;\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = any (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge p l r\n\t= [], p == [] || l == [] || r == []\n\t= a : merge z x y, c\n\t= b : merge z x y\n{\n\ta:x = l;\n\tb:y = r;\n\tc:z = p;\n}\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta:x = l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scanl fn st l: apply (foldl fn r) to every initial segment of a list\n *\n * scanl add 0 [1,2,3] == [1,3,6]\n * scanl :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscanl fn st l\n\t= st, l == []\n\t= st' : scanl fn st' xs\n{\n\tx:xs = l;\n\tst' = fn st x;\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta:x = l1;\n\t\tb:y = l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/8.3/_magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate _magick.def\n\t Add 0-ary and 2-ary system\n\t Put utility funcs into a Magick class\n   11-Apr-2014 snibgo\n     Added VirtualPixelBack for cases where background is only relevant when VP=Background\n   17-Apr-2014 snibgo\n     Many small changes.\n   2-May-2014 jcupitt\n     Added Magick.version\n   30-June-2014\n   \t Put single-quotes around command exe to help win\n   1-July-2014\n     Automatically fall back to gm if we can't find convert\n   17-July-2014\n     better GM support\n\n\n   Last update: 17-July-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n\n*/\n\n/* Put these in a class to avoid filling the main namespace with IM stuff.\n */\n\nMagick = class {\n\n\t// first gm on path, or \"\"\n\tgm_path = search_for \"gm\";\n\n\t// first convert on $PATH, or \"\"\n\t// we check for the convert we ship first\n\tconvert_path \n\t\t= vips_convert, vips_convert != \"\"\n\t\t= search_for \"convert\"\n\t{\n\t\t// the convert we ship with the vips binary on some platforms, or \"\"\n\t\tvips_convert \n\t\t\t= search (path_absolute convert)\n\t\t{\n\t\t\tvipshome = path_parse (expand \"$VIPSHOME\");\n\t\t\tconvert = vipshome ++ [\"bin\", \"convert\" ++ expand \"$EXEEXT\"];\n\t\t}\n\t}\n\n\tuse_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK;\n\n\t// Are we in GM or IM mode? \n\tuse_gm \n\t\t= true, use_gm_pref && gm_path != \"\"\n\t\t= false, !use_gm_pref && convert_path != \"\"\n\t\t= false, convert_path != \"\"\n\t\t= true, gm_path != \"\"\n\t\t= error \"neither IM nor GM executable found\";\n\n\tcommand_path\n\t\t= gm_path, use_gm\n\t\t= convert_path;\n\n\t// try to get the version as eg. [6, 7, 7, 10]\n\t// GM versions are smaller, typically [1, 3, 18]\n\tversion\n\t\t= map parse_int (split (member \".-\") version_string)\n\t{\n\t\t[output] = vips_call \"system\" \n\t\t\t[\"'\" ++ command_path ++ \"' -version\"] [$log=>true];\n\t\tversion_string \n\t\t\t= (split (equal ' ') output)?1, use_gm\n\t\t\t= (split (equal ' ') output)?2;\n\t}\n\n\t// make a command-line ... args is a [str] we join with spaces\n\tcommand args \n\t\t= \"'\" ++ command_path ++ \"' \" ++ join_sep \" \" args'\n\t{\n\t\targs'\n\t\t\t= [\"convert\"] ++ args, use_gm\n\t\t\t= args;\n\t}\n\n\t// capabilities ... different versions support different features, we \n\t// turn features on and off based on these\n\n\t// would probably be better to test for caps somehow\n\thas_intensity\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\thas_channel\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\n\tsystem0 cmd = system_image0 cmd;\n\tsystem cmd x = map_unary (system_image cmd) x;\n\tsystem2 cmd x y = map_binary (system_image2 cmd) x y;\n\tsystem3 cmd x y z = map_trinary (system_image3 cmd) x y z;\n\n\tradius_widget = Scale \"Radius\" 0 100 10;\n\tsigma_widget = Scale \"Sigma\" 0.1 10 1;\n\tangle_widget = Scale \"Angle (degrees)\" (-360) 360 0;\n\ttext_widget = String \"Text to draw\" \"AaBbCcDdEe\";\n\n\tgamma_widget = Scale \"Gamma\" 0 10 1;\n\tcolors_widget = Scale \"Colors\" 1 10 3;\n\tresize_widget = Scale \"Resize (percent)\" 0 500 100;\n\tfuzz_widget = Scale \"Fuzz (percent)\" 0 100 0;\n\tblur_rad_widget = Scale \"Radius (0=auto)\" 0 100 0;\n\n\t// a colour with no enclosing quotes ... use this if we know there are\n\t// some quotes at an outer level\n\tprint_colour_nq triple\n\t\t= concat [\"#\", concat (map fmt triple)]\n\t{\n\t\tfmt x = reverse (take 2 (reverse (print_base 16 (x + 256))));\n\t}\n\n\t// we need the quotes because # is the comment character in *nix\n\tprint_colour triple = \"\\\"\" ++ print_colour_nq triple ++ \"\\\"\";\n\n\tForeground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-fill \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Foreground triple;\n\t}\n\tforeground_widget = Foreground [0, 0, 0];\n\n\tGeneralCol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = print_colour_nq triple;\n\n\t\tColour_edit space triple = this.GeneralCol triple;\n\t}\n\tgeneralcol_widget = GeneralCol [0, 0, 0];\n\n\tBackground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" false;\n\n\t\t_flag = \"-background \" ++ if isNone then \"None\" else print_colour triple;\n\n\t\tColour_edit space triple = this.Background triple;\n\t}\n\tbackground_widget = Background [255, 255, 255];\n\n\tBordercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-bordercolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Bordercol triple;\n\t}\n\tbordercol_widget = Bordercol [0, 0, 0];\n\n\tMattecol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-mattecolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Mattecol triple;\n\t}\n\tmattecol_widget = Mattecol [189, 189, 189];\n\n\t// FIXME: Undercolour, like many others, can have alpha channel.\n\t// How does user input this? With a slider?\n\tUndercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" true;\n\n\t\t_flag = if isNone then \"\" else (\"-undercolor \" ++ print_colour triple);\n\n\t\tColour_edit space triple = this.Undercol triple;\n\t}\n\tundercol_widget = Undercol [0, 0, 0];\n\n\tchangeCol_widget = class {\n\t\t_vislevel = 3;\n\n\t\tcolour = GeneralCol [0, 0, 0];\n\t\tfuzz = fuzz_widget;\n\t\tnonMatch = Toggle \"change non-matching colours\" false;\n\t}\n\n\tAlpha alpha = class\n\t\tOption_string \"Alpha\" [\n\t\t\t\"On\", \n\t\t\t\"Off\", \n\t\t\t\"Set\", \n\t\t\t\"Opaque\", \n\t\t\t\"Transparent\", \n\t\t\t\"Extract\", \n\t\t\t\"Copy\", \n\t\t\t\"Shape\", \n\t\t\t\"Remove\", \n\t\t\t\"Background\"\n\t\t] alpha {\n\n\t\t_flag = \"-alpha \" ++ alpha;\n\n\t\tOption_edit caption labels value = this.Alpha labels?value;\n\t}\n\talpha_widget = Alpha \"On\";\n\n\tAntialias value = class\n\t\tToggle \"Antialias\" value {\n\n\t\t_flag\n\t\t\t= \"-antialias\", value\n\t\t\t= \"+antialias\";\n\n\t\tToggle_edit caption value = this.Antialias value;\n\t}\n\tantialias_widget = Antialias true;\n\n\tBuiltin builtin = class\n\t\tOption_string \"Builtin\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"rose:\",\n\t\t\t\"logo:\",\n\t\t\t\"wizard:\",\n\t\t\t\"granite:\",\n\t\t\t\"netscape:\"\n\t\t] builtin {\n\n\t\t_flag = builtin;\n\n\t\tOption_edit caption labels value = this.Builtin labels?value;\n\t}\n\tbuiltin_widget = Builtin \"rose:\";\n\n\n\tchannels_widget = class {\n\t\t// FIXME? Can we grey-out alpha when we have no alpha channel,\n\t\t//        show CMY(K) instead of RGB(K) etc?\n\t\t// Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA.\n\t\tChanR valueR = class\n\t\t\tToggle \"Red\" valueR {\n\n\t\t\t_flag\n\t\t\t\t= \"R\", valueR\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueR = this.ChanR valueR;\n\t\t}\n\t\tchannelR = ChanR true;\n\n\t\tChanG valueG = class\n\t\t\tToggle \"Green\" valueG {\n\n\t\t\t_flag\n\t\t\t\t= \"G\", valueG\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueG = this.ChanG valueG;\n\t\t}\n\t\tchannelG = ChanG true;\n\n\t\tChanB valueB = class\n\t\t\tToggle \"Blue\" valueB {\n\n\t\t\t_flag\n\t\t\t\t= \"B\", valueB\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueB = this.ChanB valueB;\n\t\t}\n\t\tchannelB = ChanB true;\n\n\t\tChanK valueK = class\n\t\t\tToggle \"Black\" valueK {\n\n\t\t\t_flag\n\t\t\t\t= \"K\", valueK\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueK = this.ChanK valueK;\n\t\t}\n\t\tchannelK = ChanK true;\n\n\t\tChanA valueA = class\n\t\t\tToggle \"Alpha\" valueA {\n\n\t\t\t_flag\n\t\t\t\t= \"A\", valueA\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueA = this.ChanA valueA;\n\t\t}\n\t\tchannelA = ChanA false;\n\n\t\tChanSy valueSy = class\n\t\t\tToggle \"Sync\" valueSy {\n\n\t\t\t_flag\n\t\t\t\t= \",sync\", valueSy\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueSy = this.ChanSy valueSy;\n\t\t}\n\t\tchannelSy = ChanSy true;\n\n\t\t_rgbka = concat [channelR._flag,\n\t\t\t\tchannelG._flag,\n\t\t\t\tchannelB._flag,\n\t\t\t\tchannelK._flag,\n\t\t\t\tchannelA._flag\n\t\t\t];\n\n\t\t_flag\n\t\t\t= \"\", _rgbka == \"\" || !has_channel\n\t\t\t= concat [ \"-channel \",\n\t\t\t\t_rgbka,\n\t\t\t\tchannelSy._flag \n\t\t\t\t];\n\t}\n\n\tch_widget = channels_widget;\n\n\tColorspace colsp = class\n\t\tOption_string \"Colorspace\" [\n\t\t\t\"CIELab\",\n\t\t\t\"CMY\",\n\t\t\t\"CMYK\",\n\t\t\t\"Gray\",\n\t\t\t\"HCL\",\n\t\t\t\"HCLp\",\n\t\t\t\"HSB\",\n\t\t\t\"HSI\",\n\t\t\t\"HSL\",\n\t\t\t\"HSV\",\n\t\t\t\"HWB\",\n\t\t\t\"Lab\",\n\t\t\t\"LCH\",\n\t\t\t\"LCHab\",\n\t\t\t\"LCHuv\",\n\t\t\t\"LMS\",\n\t\t\t\"Log\",\n\t\t\t\"Luv\",\n\t\t\t\"OHTA\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601YCbCr\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709YCbCr\",\n\t\t\t\"RGB\",\n\t\t\t\"scRGB\",\n\t\t\t\"sRGB\",\n\t\t\t\"Transparent\",\n\t\t\t\"XYZ\",\n\t\t\t\"YCbCr\",\n\t\t\t\"YDbDr\",\n\t\t\t\"YCC\",\n\t\t\t\"YIQ\",\n\t\t\t\"YPbPr\",\n\t\t\t\"YUV\"\n\t\t] colsp {\n\n\t\t_flag = colsp;\n\n\t\tOption_edit caption labels value = this.Colorspace labels?value;\n\t}\n\tcolorspace_widget = Colorspace \"sRGB\";\n\n\tCompose comp = class\n\t\tOption_string \"Compose method\" [\n\t\t\t\"Atop\", \n\t\t\t\"Blend\", \n\t\t\t\"Blur\", \n\t\t\t\"Bumpmap\", \n\t\t\t\"ChangeMask\", \n\t\t\t\"Clear\", \n\t\t\t\"ColorBurn\", \n\t\t\t\"ColorDodge\", \n\t\t\t\"Colorize\", \n\t\t\t\"CopyBlack\", \n\t\t\t\"CopyBlue\", \n\t\t\t\"CopyCyan\", \n\t\t\t\"CopyGreen\", \n\t\t\t\"Copy\", \n\t\t\t\"CopyMagenta\", \n\t\t\t\"CopyOpacity\", \n\t\t\t\"CopyRed\", \n\t\t\t\"CopyYellow\", \n\t\t\t\"Darken\", \n\t\t\t\"DarkenIntensity\", \n\t\t\t\"DivideDst\", \n\t\t\t\"DivideSrc\", \n\t\t\t\"Dst\", \n\t\t\t\"Difference\", \n\t\t\t\"Displace\", \n\t\t\t\"Dissolve\", \n\t\t\t\"Distort\", \n\t\t\t\"DstAtop\", \n\t\t\t\"DstIn\", \n\t\t\t\"DstOut\", \n\t\t\t\"DstOver\", \n\t\t\t\"Exclusion\", \n\t\t\t\"HardLight\", \n\t\t\t\"Hue\", \n\t\t\t\"In\", \n\t\t\t\"Lighten\", \n\t\t\t\"LightenIntensity\", \n\t\t\t\"LinearBurn\", \n\t\t\t\"LinearDodge\", \n\t\t\t\"LinearLight\", \n\t\t\t\"Luminize\", \n\t\t\t\"Mathematics\", \n\t\t\t\"MinusDst\", \n\t\t\t\"MinusSrc\", \n\t\t\t\"Modulate\", \n\t\t\t\"ModulusAdd\", \n\t\t\t\"ModulusSubtract\", \n\t\t\t\"Multiply\", \n\t\t\t\"None\", \n\t\t\t\"Out\", \n\t\t\t\"Overlay\", \n\t\t\t\"Over\", \n\t\t\t\"PegtopLight\", \n\t\t\t\"PinLight\", \n\t\t\t\"Plus\", \n\t\t\t\"Replace\", \n\t\t\t\"Saturate\", \n\t\t\t\"Screen\", \n\t\t\t\"SoftLight\", \n\t\t\t\"Src\", \n\t\t\t\"SrcAtop\", \n\t\t\t\"SrcIn\", \n\t\t\t\"SrcOut\", \n\t\t\t\"SrcOver\", \n\t\t\t\"VividLight\", \n\t\t\t\"Xor\"\n\t\t] comp {\n\n\t\t_flag = \"-compose \" ++ comp;\n\n\t\tOption_edit caption labels value = this.Compose labels?value;\n\t}\n\tcompose_widget = Compose \"Over\";\n\t// FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string.\n\n\t// FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack\n\n\tcoordinate_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\n\t\t_flag = concat [print x.expr, \",\", print y.expr];\n\t};\n\n\tDistort distort = class\n\t\tOption_string \"Distort\" [\n\t\t\t\"Affine\",\n\t\t\t\"AffineProjection\",\n\t\t\t\"ScaleRotateTranslate\",\n\t\t\t\"SRT\",\n\t\t\t\"Perspective\",\n\t\t\t\"PerspectiveProjection\",\n\t\t\t\"BilinearForward\",\n\t\t\t\"BilinearReverse\",\n\t\t\t\"Polynomial\",\n\t\t\t\"Arc\",\n\t\t\t\"Polar\",\n\t\t\t\"DePolar\",\n\t\t\t\"Barrel\",\n\t\t\t\"BarrelInverse\",\n\t\t\t\"Shepards\",\n\t\t\t\"Resize\"\n\t\t] distort {\n\n\t\t_flag = distort;\n\n\t\tOption_edit caption labels value = this.Distort labels?value;\n\t}\n\tdistort_widget = Distort \"SRT\";\n\n\tDither dither = class\n\t\tOption_string \"Dither\" [\n\t\t\t\"None\",\n\t\t\t\"FloydSteinberg\",\n\t\t\t\"Riemersma\"\n\t\t] dither {\n\n\t\t_flag = \"-dither \" ++ dither;\n\n\t\tOption_edit caption labels value = this.Dither labels?value;\n\t}\n\tdither_widget = Dither \"FloydSteinberg\";\n\n\tEvaluate eval = class\n\t\tOption_string \"Evaluate operation\" [\n\t\t\t\"Abs\",\n\t\t\t\"Add\",\n\t\t\t\"AddModulus\",\n\t\t\t\"And\",\n\t\t\t\"Cos\",\n\t\t\t\"Cosine\",\n\t\t\t\"Divide\",\n\t\t\t\"Exp\",\n\t\t\t\"Exponential\",\n\t\t\t\"GaussianNoise\",\n\t\t\t\"ImpulseNoise\",\n\t\t\t\"LaplacianNoise\",\n\t\t\t\"LeftShift\",\n\t\t\t\"Log\",\n\t\t\t\"Max\",\n\t\t\t\"Mean\",\n\t\t\t\"Median\",\n\t\t\t\"Min\",\n\t\t\t\"MultiplicativeNoise\",\n\t\t\t\"Multiply\",\n\t\t\t\"Or\",\n\t\t\t\"PoissonNoise\",\n\t\t\t\"Pow\",\n\t\t\t\"RightShift\",\n\t\t\t\"Set\",\n\t\t\t\"Sin\",\n\t\t\t\"Sine\",\n\t\t\t\"Subtract\",\n\t\t\t\"Sum\",\n\t\t\t\"Threshold\",\n\t\t\t\"ThresholdBlack\",\n\t\t\t\"ThresholdWhite\",\n\t\t\t\"UniformNoise\",\n\t\t\t\"Xor\"\n\t\t] eval {\n\n\t\t_flag = \"-evaluate \" ++ eval;\n\n\t\tOption_edit caption labels value = this.Evaluate labels?value;\n\t}\n\tevaluate_widget = Evaluate \"Add\";\n\n\tFilter filt = class\n\t\tOption_string \"Filter\" [\n\t\t\t\"default\",\n\t\t\t\"Bartlett\",\n\t\t\t\"Blackman\",\n\t\t\t\"Bohman\",\n\t\t\t\"Box\",\n\t\t\t\"Catrom\",\n\t\t\t\"Cosine\",\n\t\t\t\"Cubic\",\n\t\t\t\"Gaussian\",\n\t\t\t\"Hamming\",\n\t\t\t\"Hann\",\n\t\t\t\"Hermite\",\n\t\t\t\"Jinc\",\n\t\t\t\"Kaiser\",\n\t\t\t\"Lagrange\",\n\t\t\t\"Lanczos\",\n\t\t\t\"Lanczos2\",\n\t\t\t\"Lanczos2Sharp\",\n\t\t\t\"LanczosRadius\",\n\t\t\t\"LanczosSharp\",\n\t\t\t\"Mitchell\",\n\t\t\t\"Parzen\",\n\t\t\t\"Point\",\n\t\t\t\"Quadratic\",\n\t\t\t\"Robidoux\",\n\t\t\t\"RobidouxSharp\",\n\t\t\t\"Sinc\",\n\t\t\t\"SincFast\",\n\t\t\t\"Spline\",\n\t\t\t\"Triangle\",\n\t\t\t\"Welch\"\n\t\t] filt {\n\n\t\t_flag = if filt == \"default\" then \"\" else \"-filter \" ++ filt;\n\n\t\tOption_edit caption labels value = this.Filter labels?value;\n\t}\n\tfilter_widget = Filter \"default\";\n\n\tFunction func = class\n\t\tOption_string \"Function\" [\n\t\t\t\"Polynomial\",\n\t\t\t\"Sinusoid\",\n\t\t\t\"Arcsin\",\n\t\t\t\"Arctan\"\n\t\t] func {\n\n\t\t_flag = func;\n\n\t\tOption_edit caption labels value = this.Function labels?value;\n\t}\n\tfunction_widget = Function \"Polynomial\";\n\n//  \"Polynomial (a[n], a[n-1], ... a[1], a[0])\",\n//  \"Sinusoid (freq, phase, amp, bias)\",\n//  \"Arcsin (width, centre, range, bias)\",\n//  \"Arctan (slope, centre, range, bias)\"\n\n\tGravity gravity = class\n\t\tOption_string \"Gravity\" [\n\t\t\t\"None\",\n\t\t\t\"Center\",\n\t\t\t\"East\",\n\t\t\t\"Forget\",\n\t\t\t\"NorthEast\",\n\t\t\t\"North\",\n\t\t\t\"NorthWest\",\n\t\t\t\"SouthEast\",\n\t\t\t\"South\",\n\t\t\t\"SouthWest\",\n\t\t\t\"West\",\n\t\t\t\"Static\"\n\t\t] gravity {\n\n\t\t_flag = \"-gravity \" ++ gravity;\n\n\t\tOption_edit caption labels value = this.Gravity labels?value;\n\t}\n\tgravity_widget = Gravity \"Center\";\n\n\tImageType imagetype = class\n\t\tOption_string \"Image type\" [\n\t\t\t\"Bilevel\",\n\t\t\t\"ColorSeparation\",\n\t\t\t\"ColorSeparationAlpha\",\n\t\t\t\"ColorSeparationMatte\",\n\t\t\t\"Grayscale\",\n\t\t\t\"GrayscaleAlpha\",\n\t\t\t\"GrayscaleMatte\",\n\t\t\t\"Optimize\",\n\t\t\t\"Palette\",\n\t\t\t\"PaletteBilevelAlpha\",\n\t\t\t\"PaletteBilevelMatte\",\n\t\t\t\"PaletteAlpha\",\n\t\t\t\"PaletteMatte\",\n\t\t\t\"TrueColorAlpha\",\n\t\t\t\"TrueColorMatte\",\n\t\t\t\"TrueColor\"\n\t\t] imagetype {\n\n\t\t_flag = \"-type \" ++ imagetype;\n\n\t\tOption_edit caption labels value = this.ImageType labels?value;\n\t}\n\timagetype_widget = ImageType \"TrueColor\";\n\n\tIntensity intensity = class\n\t\tOption_string \"Intensity (gray conversion)\" [\n\t\t\t\"Average\",\n\t\t\t\"Brightness\",\n\t\t\t\"Lightness\",\n\t\t\t\"MS\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601Luminance\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709Luminance\",\n\t\t\t\"RMS\"\n\t\t] intensity {\n\n\t\t_flag \n\t\t\t= \"-intensity \" ++ intensity, has_intensity\n\t\t\t= \"\";\n\n\t\tOption_edit caption labels value = this.Intensity labels?value;\n\t}\n\tintensity_widget = Intensity \"Rec709Luminance\";\n\n\tInterpolate interp = class\n\t\tOption_string \"Interpolate\" [\n\t\t\t\"default\",\n\t\t\t\"Average\",\n\t\t\t\"Average4\",\n\t\t\t\"Average9\",\n\t\t\t\"Average16\",\n\t\t\t\"Background\",\n\t\t\t\"Bilinear\",\n\t\t\t\"Blend\",\n\t\t\t\"Integer\",\n\t\t\t\"Mesh\",\n\t\t\t\"Nearest\",\n\t\t\t\"NearestNeighbor\",\n\t\t\t\"Spline\"\n\t\t] interp {\n\n\t\t_flag = if interp == \"default\" then \"\" else \"-interpolate \" ++ interp;\n\n\t\tOption_edit caption labels value = this.Interpolate labels?value;\n\t}\n\tinterpolate_widget = Interpolate \"default\";\n\n\tKernel kernel = class\n\t\tOption_string \"Kernel\" [\n\t\t\t\"Unity\",\n\t\t\t\"Gaussian\",\n\t\t\t\"DoG\",\n\t\t\t\"LoG\",\n\t\t\t\"Blur\",\n\t\t\t\"Comet\",\n\t\t\t\"Binomial\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Sobel\",\n\t\t\t\"FreiChen\",\n\t\t\t\"Roberts\",\n\t\t\t\"Prewitt\",\n\t\t\t\"Compass\",\n\t\t\t\"Kirsch\",\n\t\t\t\"Diamond\",\n\t\t\t\"Square\",\n\t\t\t\"Rectangle\",\n\t\t\t\"Disk\",\n\t\t\t\"Octagon\",\n\t\t\t\"Plus\",\n\t\t\t\"Cross\",\n\t\t\t\"Ring\",\n\t\t\t\"Peaks\",\n\t\t\t\"Edges\",\n\t\t\t\"Corners\",\n\t\t\t\"Diagonals\",\n\t\t\t\"LineEnds\",\n\t\t\t\"LineJunctions\",\n\t\t\t\"Ridges\",\n\t\t\t\"ConvexHull\",\n\t\t\t\"ThinSe\",\n\t\t\t\"Skeleton\",\n\t\t\t\"Chebyshev\",\n\t\t\t\"Manhattan\",\n\t\t\t\"Octagonal\",\n\t\t\t\"Euclidean\"\n\t\t\t// FIXME: custom kernel\n\t\t] kernel {\n\n\t\t_flag = kernel;\n\n\t\tOption_edit caption labels value = this.Kernel labels?value;\n\t}\n\tkernel_widget = Kernel \"Unity\";\n\n\tModColSp msp = class\n\t\tOption_string \"modulate colorspace\" [\n\t\t\t\"HCL\", \n\t\t\t\"HCLp\", \n\t\t\t\"HSB\", \n\t\t\t\"HSI\", \n\t\t\t\"HSL\", \n\t\t\t\"HSV\", \n\t\t\t\"HWB\", \n\t\t\t\"LCH\"\n\t\t] msp {\n\n\t\t_flag = \"-set option:modulate:colorspace \" ++ msp;\n\n\t\tOption_edit caption labels value = this.ModColSp labels?value;\n\t}\n\tModColSp_widget = ModColSp \"HSL\";\n\n\tMorphMeth morph = class\n\t\tOption_string \"Method\" [\n\t\t\t\"Correlate\",\n\t\t\t\"Convolve\",\n\t\t\t\"Dilate\",\n\t\t\t\"Erode\",\n\t\t\t\"Close\",\n\t\t\t\"Open\",\n\t\t\t\"DilateIntensity\",\n\t\t\t\"ErodeIntensity\",\n\t\t\t\"CloseIntensity\",\n\t\t\t\"OpenIntensity\",\n\t\t\t\"Smooth\",\n\t\t\t\"EdgeOut\",\n\t\t\t\"EdgeIn\",\n\t\t\t\"Edge\",\n\t\t\t\"TopHat\",\n\t\t\t\"BottomHat\",\n\t\t\t\"HitAndMiss\",\n\t\t\t\"Thinning\",\n\t\t\t\"Thicken\",\n\t\t\t\"Distance\",\n\t\t\t\"IterativeDistance\"\n\t\t] morph {\n\n\t\t_flag = morph;\n\n\t\tOption_edit caption labels value = this.MorphMeth labels?value;\n\t}\n\tmorphmeth_widget = MorphMeth \"Dilate\";\n\n\tNoise noise = class\n\t\tOption_string \"Noise\" [\n\t\t\t\"Gaussian\",\n\t\t\t\"Impulse\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Multiplicative\",\n\t\t\t\"Poisson\",\n\t\t\t\"Random\",\n\t\t\t\"Uniform\"\n\t\t] noise {\n\n\t\t_flag = \"+noise \" ++ noise;\n\n\t\tOption_edit caption labels value = this.Noise labels?value;\n\t}\n\tnoise_widget = Noise \"Gaussian\";\n\n\tPattern pattern = class\n\t\tOption_string \"Noise\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"bricks\",\n\t\t\t\"checkerboard\",\n\t\t\t\"circles\",\n\t\t\t\"crosshatch\",\n\t\t\t\"crosshatch30\",\n\t\t\t\"crosshatch45\",\n\t\t\t\"gray0\",\n\t\t\t\"gray5\",\n\t\t\t\"gray10\",\n\t\t\t\"gray15\",\n\t\t\t\"gray20\",\n\t\t\t\"gray25\",\n\t\t\t\"gray30\",\n\t\t\t\"gray35\",\n\t\t\t\"gray40\",\n\t\t\t\"gray45\",\n\t\t\t\"gray50\",\n\t\t\t\"gray55\",\n\t\t\t\"gray60\",\n\t\t\t\"gray65\",\n\t\t\t\"gray70\",\n\t\t\t\"gray75\",\n\t\t\t\"gray80\",\n\t\t\t\"gray85\",\n\t\t\t\"gray90\",\n\t\t\t\"gray95\",\n\t\t\t\"gray100\",\n\t\t\t\"hexagons\",\n\t\t\t\"horizontal\",\n\t\t\t\"horizontal2\",\n\t\t\t\"horizontal3\",\n\t\t\t\"horizontalsaw\",\n\t\t\t\"hs_bdiagonal\",\n\t\t\t\"hs_cross\",\n\t\t\t\"hs_diagcross\",\n\t\t\t\"hs_fdiagonal\",\n\t\t\t\"hs_horizontal\",\n\t\t\t\"hs_vertical\",\n\t\t\t\"left30\",\n\t\t\t\"left45\",\n\t\t\t\"leftshingle\",\n\t\t\t\"octagons\",\n\t\t\t\"right30\",\n\t\t\t\"right45\",\n\t\t\t\"rightshingle\",\n\t\t\t\"smallfishscales\",\n\t\t\t\"vertical\",\n\t\t\t\"vertical2\",\n\t\t\t\"vertical3\",\n\t\t\t\"verticalbricks\",\n\t\t\t\"verticalleftshingle\",\n\t\t\t\"verticalrightshingle\",\n\t\t\t\"verticalsaw\"\n\t\t] pattern {\n\n\t\t_flag = \"pattern:\" ++ pattern;\n\n\t\tOption_edit caption labels value = this.Pattern labels?value;\n\t}\n\tpattern_widget = Pattern \"bricks\";\n\n\tResizeType resizet = class\n\t\tOption_string \"Resize type\" [\n\t\t\t\"resize\", \n\t\t\t\"scale\",\n\t\t\t\"sample\",\n\t\t\t\"adaptive-resize\"\n\t\t] resizet {\n\n\t\t_flag = resizet;\n\n\t\tOption_edit caption labels value = this.ResizeType labels?value;\n\t}\n\tResizeType_widget = ResizeType \"resize\";\n\n\tSize_widget = class {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width (pixels)\" 64;\n\t\theight = Expression \"Height (pixels)\" 64;\n\n\t\t_flag = \"-size \" ++\n\t\t\tprint width.expr ++ \"x\" ++ print height.expr;\n\n\t};\n\n\tStatType statt = class\n\t\tOption_string \"Statistic type\" [\n\t\t\t\"Gradient\", \n\t\t\t\"Maximum\", \n\t\t\t\"Mean\", \n\t\t\t\"Median\", \n\t\t\t\"Minimum\", \n\t\t\t\"Mode\", \n\t\t\t\"Nonpeak\", \n\t\t\t\"StandardDeviation\"\n\t\t] statt {\n\n\t\t_flag = statt;\n\n\t\tOption_edit caption labels value = this.StatType labels?value;\n\t}\n\tStatType_widget = StatType \"Mean\";\n\n\tVirtualPixel vp = class\n\t\tOption_string \"Virtual pixel\" [\n\t\t\t\"Background\", \n\t\t\t\"Black\", \n\t\t\t\"CheckerTile\", \n\t\t\t\"Dither\", \n\t\t\t\"Edge\", \n\t\t\t\"Gray\", \n\t\t\t\"HorizontalTile\", \n\t\t\t\"HorizontalTileEdge\", \n\t\t\t\"Mirror\", \n\t\t\t\"None\",\n\t\t\t\"Random\",\n\t\t\t\"Tile\",\n\t\t\t\"Transparent\",\n\t\t\t\"VerticalTile\",\n\t\t\t\"VerticalTileEdge\",\n\t\t\t\"White\"\n\t\t] vp {\n\n\t\t_flag = \"-virtual-pixel \" ++ vp;\n\n\t\t_isBackground = (vp == \"Background\");\n\n\t\tOption_edit caption labels value = this.VirtualPixel labels?value;\n\t}\n\tVirtualPixel_widget = VirtualPixel \"Edge\";\n\n\tVirtualPixelBack_widget = class {\n\t\tvirtpix = Magick.VirtualPixel_widget;\n\t\tbackground = Magick.background_widget;\n\t\t_flag = (if virtpix._isBackground then (background._flag ++ \" \") else \"\")\n\t\t\t++ virtpix._flag;\n\t}\n\n\tGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tAnnotGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print shearX.expr, \"x\", print shearY.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tOffsetGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag = concat [format hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tWhxyGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFrameGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\toutbev = Expression \"Outer bevel thickness\" 0;\n\t\tinbev = Expression \"Inner bevel thickness\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat outbev, format inbev]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFont_widget = class {\n\t\t_vislevel = 3;\n\n\t\tfamily = Option_string \"Family\" [\n\t\t\t\"Arial\",\n\t\t\t\"ArialBlack\",\n\t\t\t\"AvantGarde\",\n\t\t\t\"BitstreamCharter\",\n\t\t\t\"Bookman\",\n\t\t\t\"CenturySchoolbook\",\n\t\t\t\"ComicSansMS\",\n\t\t\t\"Courier\",\n\t\t\t\"CourierNew\",\n\t\t\t\"DejaVuSans\",\n\t\t\t\"DejaVuSansMono\",\n\t\t\t\"DejaVuSerif\",\n\t\t\t\"Dingbats\",\n\t\t\t\"FreeMono\",\n\t\t\t\"FreeSans\",\n\t\t\t\"FreeSerif\",\n\t\t\t\"Garuda\",\n\t\t\t\"Georgia\",\n\t\t\t\"Helvetica\",\n\t\t\t\"HelveticaNarrow\",\n\t\t\t\"Impact\",\n\t\t\t\"LiberationMono\",\n\t\t\t\"LiberationSans\",\n\t\t\t\"LiberationSerif\",\n\t\t\t\"NewCenturySchlbk\",\n\t\t\t\"Palatino\",\n\t\t\t\"Purisa\",\n\t\t\t\"Symbol\",\n\t\t\t\"Times\",\n\t\t\t\"TimesNewRoman\",\n\t\t\t\"Ubuntu\",\n\t\t\t\"Verdana\",\n\t\t\t\"Webdings\"\n\t\t] \"Arial\";\n\t\tstyle = Option_string \"Style\" [\n\t\t\t\"Any\", \"Italic\", \"Normal\", \"Oblique\"\n\t\t] \"Normal\";\n\t\tweight = Scale \"Weight\" 1 800 400;\n\t\tsize = Scale \"Point size\" 1 100 12;\n\t\tstretch = Option_string \"Stretch\" [\n\t\t\t\"Any\", \"Condensed\", \"Expanded\", \"ExtraCondensed\", \"ExtraExpanded\", \n\t\t\t\"Normal\", \"SemiCondensed\", \"SemiExpanded\", \"UltraCondensed\", \n\t\t\t\"UltraExpanded\"\n\t\t] \"Normal\";\n\n\t\t_flag = join_sep \" \" [\n\t\t\t\t\"-family\", family.item,\n\t\t\t\t\"-weight\", print weight.value,\n\t\t\t\t\"-pointsize\", print size.value,\n\t\t\t\t\"-style\", style.item,\n\t\t\t\t\"-stretch\", stretch.item];\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.3/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = any (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && all (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* Test list length ... quicker than len x == n for large lists.\n */\nis_list_len n x\n\t= true, x == [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len (n - 1) (tl x);\n\nis_list_len_more n x\n\t= true, x != [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len_more (n - 1) (tl x);\n\nis_list_len_more_equal n x\n\t= true, n == 0\n\t= false, x == [] \n\t= is_list_len_more_equal (n - 1) (tl x);\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, all (map is_obj l)\n\t= true, all (map is_list l) &&\n\t\tall (map (not @ is_obj) l) &&\n\t\tall (map is_rectangular l) &&\n\t\tis_list_len_more 0 l &&\n\t\tall (map (is_list_len (len (hd l))) (tl l))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && is_list_len (len (hd l)) l;\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_NULL x = is_instanceof \"NULL\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Plot x = is_instanceof \"Plot\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && all (map xy l)\n{\n\txy l = is_real_list l && is_list_len 2 l;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && any (map is_Group l)\n\t= any (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= oo_unary_function get_type_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_type\")\n{\n\tget_type_op = Operator \"get_type\" get_type \n\t\tOperator_type.COMPOUND false;\n\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\t// can have alpha, hence we let bands be one more than you might think\n\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.GREY16, type == Image_type.GREY16 && is_bands 1\n\t\t= Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && \n\t\t\t(width == 1 || height == 1)\n\t\t= Image_type.B_W, is_bands 1 \n\t\t= Image_type.CMYK, type == Image_type.CMYK && is_bands 4\n\t\t= type, is_colorimetric && is_bands 3\n\t\t= Image_type.sRGB, !is_colorimetric && is_bands 3\n\t\t= Image_type.MULTIBAND, !is_colorimetric && !is_bands 3\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\n\t\t// is bands n, with an optional alpha (ie. can be n + 1 too)\n\t\tis_bands n = bands == n || bands == n + 1;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= oo_unary_function get_format_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_format\")\n{\n\tget_format_op = Operator \"get_format\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= oo_unary_function get_bits_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bits\")\n{\n\tget_bits_op = Operator \"get_bits\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= oo_unary_function get_bands_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bands\")\n{\n\tget_bands_op = Operator \"get_bands\" get_bands \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= oo_unary_function get_coding_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_coding\")\n{\n\tget_coding_op = Operator \"get_coding\" get_coding \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= oo_unary_function get_xres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xres\")\n{\n\tget_xres_op = Operator \"get_xres\" get_xres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= oo_unary_function get_yres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yres\")\n{\n\tget_yres_op = Operator \"get_yres\" get_yres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= oo_unary_function get_xoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xoffset\")\n{\n\tget_xoffset_op = Operator \"get_xoffset\" get_xoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= oo_unary_function get_yoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yoffset\")\n{\n\tget_yoffset_op = Operator \"get_yoffset\" get_yoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= oo_unary_function get_image_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_image\")\n{\n\tget_image_op = Operator \"get_image\" get_image \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= oo_unary_function get_number_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_number\")\n{\n\tget_number_op = Operator \"get_number\" get_number \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= oo_unary_function get_real_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_real\")\n{\n\tget_real_op = Operator \"get_real\" get_real \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= oo_unary_function get_width_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_width\")\n{\n\tget_width_op = Operator \"get_width\" get_width \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= oo_unary_function get_height_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_height\")\n{\n\tget_height_op = Operator \"get_height\" get_height \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= oo_unary_function get_left_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_left\")\n{\n\tget_left_op = Operator \"get_left\" get_left \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= oo_unary_function get_top_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_top\")\n{\n\tget_top_op = Operator \"get_top\" get_top \n\t\tOperator_type.COMPOUND false;\n}\n\n// like has/get member, but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.3/_stdenv.def",
    "content": "/* optional args to functions\n */\n\nget_option options defaults f\n\t= error (_ \"unknown parameter \" ++ f), hits == []\n\t= hits?0\n{\n\thits = [v :: [n, v] <- options ++ defaults; n == f];\n}\n\n/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\nidivide a b = (int) ((int) a / (int) b);\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\n// 'difference' is defined in _list\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the function we call for \"a -> v\" expressions\nmksvpair s v\n\t= [s, v], is_string s\n\t= error \"not str on lhs of ->\";\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error (\"unimplemented vector operation: \" ++ op_name)\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n// make a name value pair\nmknvpair n v\n\t= [n, v], is_string n\n\t= error \"not [char] on LHS of =>\";\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined, has_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nbandand x\n\t= oo_unary_function bandand_op x, is_class x\n\t= foldr1 bitwise_and (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandand\")\n{\n\tbandand_op = Operator \"bandand\" bandand Operator_type.COMPOUND_REWRAP false;\n}\n\nbandor x\n\t= oo_unary_function bandor_op x, is_class x\n\t= foldr1 bitwise_or (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandor\")\n{\n\tbandor_op = Operator \"bandor\" bandor Operator_type.COMPOUND_REWRAP false;\n}\n\nsum x\n\t= oo_unary_function sum_op x, is_class x\n\t= im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x\n\t= sum_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"sum\")\n{\n\tsum_op = Operator \"sum\" sum Operator_type.COMPOUND false;\n\n\t// add elements in a nested-list thing\n\tsum_list l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nproduct x\n\t= oo_unary_function product_op x, is_class x\n\t= product_list x, is_list x \n\t// (product image) doesn't make much sense :(\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"product\")\n{\n\tproduct_op = Operator \"product\" product Operator_type.COMPOUND false;\n\n\tproduct_list l\n\t\t= foldr prod 1 l\n\t{\n\t\tprod x total\n\t\t\t= total * product x, is_list x\n\t\t\t= total * x;\n\t}\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\nskew x\n\t= oo_unary_function skew_op x, is_class x\n\t= sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x \n\t= sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"skew\")\n{\n\tskew_op = Operator \"skew\" skew Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN \n\t\t= w * h * b, is_image x'\n\t\t= len x';\n}\n\nkurtosis x\n\t= oo_unary_function kurtosis_op x, is_class x\n\t= sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x \n\t= sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"kurtosis\")\n{\n\tkurtosis_op = Operator \"kurtosis\" kurtosis Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN\n\t\t= len x', is_list x';\n\t\t= w * h * b;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image_hist x, is_image x && \n\t\t(fmt == Image_format.UCHAR || fmt == Image_format.USHORT)\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tfmt = get_format x;\n\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean, for any image type\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n\n\t// image mean for 8 and 16-bit unsigned images\n\t// we can use a histogram, yay, and save a pass through the image\n\tmeanze_image_hist i\n\t\t= sum / N\n\t{\n\t\t// histogram, knock out zeros\n\t\thist = hist_find i;\n\t\tblack = image_new 1 1 (get_bands hist) \n\t\t\t(get_format hist) (get_coding hist) (get_type hist) 0 0 0;\n\t\thistze = insert 0 0 black hist;\n\n\t\t// matching identity\n\t\tiden\n\t\t\t= im_identity_ushort (get_bands hist) (get_width hist),\n\t\t\t\t(get_width hist) > 256\n\t\t\t= im_identity (get_bands hist);\n\n\t\t// number of non-zero pixels\n\t\tN = mean histze * 256;\n\n\t\t// sum of pixels\n\t\tsum = mean (hist * iden) * 256;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_tile_cache_random x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (\\row [row?x']) obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\" ++ \": \" ++\n\t\tjoin_sep \", \" (map print [cond, in1, in2]))\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x \n\t\t\t= to_image_size target_width target_height \n\t\t\t\ttarget_bands target_format x;\n\n\t\t[then_image, else_image] = map to_image [then_part, else_part];\n\n\t\tblend_result_image = image_set_type target_type \n\t\t\t(im_blend cond then_image else_image);\n\t}\n}\n\n// do big first: we want to keep big's class, if possible\n// eg. big is a Plot, small is a 1x1 Image\ninsert x y small big\n\t= oo_binary'_function insert_op small big, is_class big\n\t= oo_binary_function insert_op small big, is_class small\n\t= im_insert big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ndecode im\n\t= oo_unary_function decode_op im, is_class im\n\t= decode_im im, is_image im\n\t= error (_ \"bad arguments to \" ++ \"decode\")\n{\n\tdecode_op = Operator \"decode\" \n\t\tdecode Operator_type.COMPOUND_REWRAP false;\n\n\tdecode_im im\n\t\t= im_LabQ2Lab im, get_coding im == Image_coding.LABPACK\n\t\t= im_rad2float im, get_coding im == Image_coding.RAD\n\t\t= im;\n}\n\nmeasure_draw across down measure image\n    = mark\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n\n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::  \n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n    x = map (extract 0) cods;\n    y = map (extract 1) cods;\n\n    outer = mkim [$pixel => 255] sample_width sample_height 1;\n    inner = mkim [] (sample_width - 4) (sample_height - 4) 1;\n    patch = insert 2 2 inner outer;\n\n    bg = mkim [] image.width image.height 1;\n\n    mask = Image (im_insertset bg.value patch.value x y);\n\n    image' = colour_transform_to Image_type.sRGB image;\n\n    mark = if mask then Vector [0, 255, 0] else image';\n}\n\nmeasure_sample across down measure image\n    = measures\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n                \n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::\n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n\n\timage' = decode image;\n    patches = map (\\p extract_area p?0 p?1 sample_width sample_height image') \n\t\tcods;\n    measures = Matrix (map (map mean) (map bandsplit patches));\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ninvert x\n\t= oo_unary_function invert_op x, is_class x\n\t= im_invert x, is_image x\n\t= 255 - x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"invert\")\n{\n\tinvert_op = Operator \"invert\" invert Operator_type.COMPOUND false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate interp angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_affinei_all image interp.value a (-b) b a 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\t(rotate interp) Operator_type.COMPOUND_REWRAP false;\n\ta = cos angle;\n\tb = sin angle;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_lr\")\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin_lr Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert (get_width a) 0 b a;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_tb\")\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin_tb Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert 0 (get_height a) b a;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\t// The [[real]] can contain 128 values ... squeeze them out!\n\timage = im_mask2vips (Matrix m2) == 255;\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\" ++ \": \" ++ \n\t\t\"conv (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvf mask image\n\t= oo_unary_function convf_op image, is_class image\n\t= im_conv_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convf\" ++ \": \" ++ \n\t\t\"convf (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconvf_op = Operator \"convf\" \n\t\t(convf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\naconvsep layers mask image \n\t= oo_unary_function aconvsep_op image, is_class image\n\t= im_aconvsep image (to_matrix mask) (to_real layers), is_image image\n\t= error (_ \"bad arguments to \" ++ \"aconvsep\")\n{\n\taconvsep_op = Operator \"aconvsep\" \n\t\t(aconvsep layers mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsep_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_indexed index value\n\t= oo_binary_function hist_find_indexed_op index value, is_class index\n\t= oo_binary'_function hist_find_indexed_op index value, is_class value\n\t= im_hist_indexed index value, is_image index && is_image value\n\t= error (_ \"bad arguments to \" ++ \"hist_find_indexed\")\n{\n\thist_find_indexed_op = Operator \"hist_find_indexed\" \n\t\t(compose (compose Plot_histogram) hist_find_indexed) \n\t\t\tOperator_type.COMPOUND false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h \n\t\t= (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h\n\t{\n\t\t// up the format so it can represent the whole range of\n\t\t// possible values from this mask\n\t\tfmt x\n\t\t\t= Image_format.SHORT, \n\t\t\t\tx == Image_format.UCHAR || x == Image_format.CHAR\n\t\t\t= Image_format.INT, \n\t\t\t\tx == Image_format.USHORT || x == Image_format.SHORT ||\n\t\t\t\tx == Image_format.UINT \n\t\t\t= x;\n\t}\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_inv hist \n\t= oo_unary_function hist_inv_op hist, is_class hist\n\t= inv hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_inv\")\n{\n\thist_inv_op = Operator \"hist_inv\" \n\t\thist_inv Operator_type.COMPOUND_REWRAP false;\n\n\tinv im\n\t\t= im_invertlut (to_matrix im''') len\n\t{\n\t\t// need a vertical doublemask\n\t\tim' \n\t\t\t= rot90 im, get_width im > 1 && get_height im == 1 \n\t\t\t= im, get_width im == 1 && get_height im > 1\n\t\t\t= error (_ \"not a hist\");\n\t\tlen = get_height im';\n\n\t\t// values must be scaled to 0 - 1\n\t\tim'' = im' / (max im');\n\t\t\n\t\t// add an index column on the left\n\t\t// again, must be in 0-1\n\t\ty = ((make_xy 1 len)?1) / len;\n\t\tim''' = y ++ im'';\n\t}\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= lhisteq image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n\n\t// loop over bands, if necessary\n\tlhisteq im\n\t\t= im_lhisteq im (to_real w) (to_real h), get_bands im == 1\n\t\t= (foldl1 join @ map lhisteq @ bandsplit) im;\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nreduce kernel xshr yshr image\n\t= oo_unary_function reduce_op image, is_class image\n\t= reduce_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"reduce\")\n{\n\treduce_op = Operator \"reduce\" \n\t\treduce_im Operator_type.COMPOUND_REWRAP false;\n\n\treduce_im im \n\t\t= out\n\t{\n\t\t[out] = vips_call \"reduce\" [im, xshr, yshr] [$kernel => kernel.value];\n\t}\n}\n\nsimilarity interpolate scale angle image\n\t= oo_unary_function similarity_op image, is_class image\n\t= similarity_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"similarity\")\n{\n\tsimilarity_op = Operator \"similarity\" \n\t\tsimilarity_im Operator_type.COMPOUND_REWRAP false;\n\n\tsimilarity_im im \n\t\t= out\n\t{\n\t\t[out] = vips_call \"similarity\" [im] [\n\t\t\t$interpolate => interpolate.value,\n\t\t\t$scale => scale,\n\t\t\t$angle => angle\n\t\t];\n\t}\n}\n\nresize kernel xfac yfac image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\tis_nn = kernel.type == Kernel_type.NEAREST_NEIGHBOUR;\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn \n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn \n\n\t\t// everything else ... we just pass on to vips_resize()\n\t\t= vips_resize kernel xfac' yfac' im\n\t{\n\t\tvips_resize kernel hscale vscale im \n\t\t\t= out\n\t\t{\n\t\t\t[out] = vips_call \"resize\" [im, hscale] \n\t\t\t\t[$vscale => vscale, $kernel => kernel.value];\n\t\t}\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\n\n// Given a xywh rect, flip it around so wh are always positive\nrect_normalise x y w h \n\t= [x', y', w', h']\n{\n\tx'\n\t\t= x + w, w < 0\n\t\t= x;\n\ty'\n\t\t= y + h, h < 0\n\t\t= y;\n\tw' = abs w;\n\th' = abs h;\n}\n\ndraw_flood_blob x y ink image\n\t= oo_unary_function draw_flood_blob_op image, is_class image\n\t= im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood_blob\")\n{\n\tdraw_flood_blob_op = Operator \"draw_flood_blob\" \n\t\t(draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_flood x y ink image\n\t= oo_unary_function draw_flood_op image, is_class image\n\t= im_draw_flood image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood\")\n{\n\tdraw_flood_op = Operator \"draw_flood\" \n\t\t(draw_flood x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* This version of draw_rect uses insert_noexpand and will be fast, even for\n * huge images.\n */\ndraw_rect_width x y w h f t ink image\n\t= oo_unary_function draw_rect_width_op image, is_class image\n\t= my_draw_rect_width image (to_int x) (to_int y) \n\t\t(to_int w) (to_int h) (to_int f) (to_int t) ink, \n\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_width\")\n{\n\tdraw_rect_width_op = Operator \"draw_rect_width\" \n\t\t(draw_rect_width x y w h f t ink) \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\tmy_draw_rect_width image x y w h f t ink\n\t\t= insert x' y' (block w' h') image, f == 1\n\t\t= (insert x' y' (block w' t) @ \n\t\t\tinsert (x' + w' - t) y' (block t h') @ \n\t\t\tinsert x' (y' + h' - t) (block w' t) @ \n\t\t\tinsert x' y' (block t h')) image\n\t{\n\t\tinsert = insert_noexpand;\n\t\tblock w h = image_new w h (get_bands image) (get_format image)\n\t\t\t(get_coding image) (get_type image) ink' 0 0;\n\t\tink' \n\t\t\t= Vector ink, is_list ink\n\t\t\t= ink;\n\t\t[x', y', w', h'] = rect_normalise x y w h;\n\t}\n}\n\n/* Default to 1 pixel wide edges.\n */\ndraw_rect x y w h f ink image\n\t= draw_rect_width x y w h f 1 ink image;\n\n/* This version of draw_rect uses the paintbox rect draw operation. It is an\n * inplace operation and will use bucketloads of memory.\n */\ndraw_rect_paintbox x y w h f ink image\n\t= oo_unary_function draw_rect_op image, is_class image\n\t= im_draw_rect image (to_real x) (to_real y) \n\t\t(to_real w) (to_real h) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_paintbox\")\n{\n\tdraw_rect_op = Operator \"draw_rect\" \n\t\t(draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_circle x y r f ink image\n\t= oo_unary_function draw_circle_op image, is_class image\n\t= im_draw_circle image (to_real x) (to_real y) \n\t\t(to_real r) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_circle\")\n{\n\tdraw_circle_op = Operator \"draw_circle\" \n\t\t(draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_line x1 y1 x2 y2 ink image\n\t= oo_unary_function draw_line_op image, is_class image\n\t= im_draw_line image (to_real x1) (to_real y1) \n\t\t(to_real x2) (to_real y2) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_line\")\n{\n\tdraw_line_op = Operator \"draw_line\" \n\t\t(draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (\\x x % base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (\\x idivide x base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= NULL, any (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n/* Linear regression. Return a class with the stuff we need in.\n * from s15.2, p 665 NR in C\n * \n * Also calculate R2, see eg.:\n * https://en.wikipedia.org/wiki/Coefficient_of_determination \n */\nlinreg xes yes\n    = obj\n{\n    obj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [t * y :: [t, y] <- zip2 tes yes] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes];\n\n\t\tsiga = (chi2 / (ss - 2)) ** 0.5 *\n\t\t\t((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5;\n\n\t\t// for compat with linregw, see below\n\t\tq = 1.0;\n\n\t\tR2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes];\n\t}\n\n\tss = len xes;\n\tsx = sum xes;\n\tsy = sum yes;\n\tmy = sy / ss;\n\tsxoss = sx / ss;\n\n\ttes = [x - sxoss :: x <- xes];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Weighted linear regression. Xes, yes and a list of deviations.\n */\nlinregw xes yes devs \n\t= obj\n{\n\tobj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: \n\t\t\t[x, y, sd] <- zip3 xes yes devs];\n\n\t\tsiga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (1 / st2) ** 0.5;\n\n\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\n\t\tR2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes];\n\t}\n\n\twt = [sd ** -0.5 :: sd <- devs];\n\n\tss = sum wt;\n\tsx = sum [x * w :: [x, w] <- zip2 xes wt];\n\tsy = sum [y * w :: [y, w] <- zip2 yes wt];\n\tmy = sy / len xes;\n\tsxoss = sx / ss;\n\n\ttes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Clustering: pass in a list of points, repeatedly merge the\n * closest two points until no two points are closer than the threshold.\n * Return [merged-points, corresponding-weights]. A weight is a list of the\n * indexes we merged to make that point, ie. len weight == how significant\n * this point is.\n *\n * eg. \n *\tcluster 12 [152,154,155,42,159] == \n *\t\t[[155,42],[[1,2,0,4],[3]]]\n */\ncluster thresh points\n\t= oo_unary_function cluster_op points, is_class points\n\t// can't use [0..len points - 1], in case len points == 0\n\t= merge [points, map (converse cons []) (take (len points) [0 ..])],\n\t\tis_list points\n\t= error (_ \"bad arguments to \" ++ \"cluster\")\n{\n\tcluster_op = Operator \"cluster\" \n\t\t(cluster thresh) Operator_type.COMPOUND false;\n\n\tmerge x\n\t\t= x, m < 2 || d > thresh\n\t\t= merge [points', weights']\n\t{\n\t\t[points, weights] = x;\n\t\tm = len points;\n\n\t\t// generate indexes of all possible pairs, avoiding comparing a thing \n\t\t// to itself, and assuming that dist is reflexive\n\t\t// first index is always less than 2nd index\n\t\t// the +1,+2 makes sure we have an increasing generator, otherwise we\n\t\t// can get [3 .. 4] (for example), which will make a decreasing\n\t\t// sequence\n\t\tpairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]];\n\n\t\t// distance function\n\t\t// arg is eg. [3,1], meaning get distance from point 3 to point 1\n\t\tdist x \n\t\t\t= abs (points?i - points?j)\n\t\t{\n\t\t\t[i, j] = x;\n\t\t}\n\n\t\t// smallest distance, then the two points we merge\n\t\tp = minpos (map dist pairs);\n\t\td = dist pairs?p;\n\t\t[i, j] = pairs?p;\n\n\t\t// new point and new weight\n\t\tnw = weights?i ++ weights?j;\n\t\tnp = (points?i * len weights?i + points?j * len weights?j) / len nw;\n\n\t\t// remove element i from a list\n\t\tremove i l = take i l ++ drop (i + 1) l;\n\n\t\t// remove two old points, add the new merged one\n\t\t// i < j (see \"pairs\", above)\n\t\tpoints' = np : remove i (remove j points);\n\t\tweights' = nw : remove i (remove j weights);\n\t}\n}\n\n/* Extract the area of an image around an arrow.\n * Transform the image to make the arrow horizontal, then displace by hd and\n * vd pxels, then cut out a bit h pixels high centered on the arrow.\n */\nextract_arrow hd vd h arrow\n\t= extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im'\n{\n\t// the line as a polar vector\n\tpv = polar (arrow.width, arrow.height);\n\ta = im pv;\n\n\t// smallest rotation that will make the line horizontal\n\ta'\n\t\t= 360 - a, a > 270\n\t\t= 180 - a, a > 90\n\t\t= -a;\n\n\tim' = rotate Interpolate_bilinear a' arrow.image;\n\n\t// look at the start and end of the arrow, pick the leftmost\n\tp\n\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t= (arrow.right, arrow.bottom);\n\n\t// transform that point to im' space\n\tp' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset);\n}\n\n/* You'd think these would go in _convert, but they are not really colour ops,\n * so put them here.\n */\nrad2float image\n\t= oo_unary_function rad2float_op image, is_class image\n\t= im_rad2float image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"rad2float\")\n{\n\trad2float_op = Operator \"rad2float\" \n\t\trad2float Operator_type.COMPOUND_REWRAP false;\n}\n\nfloat2rad image\n\t= oo_unary_function float2rad_op image, is_class image\n\t= im_float2rad image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"float2rad\")\n{\n\tfloat2rad_op = Operator \"float2rad\" \n\t\tfloat2rad Operator_type.COMPOUND_REWRAP false;\n}\n\nsegment x\n\t= oo_unary_function segment_op x, is_class x\n\t= image', is_image x \n\t= error (_ \"bad arguments to \" ++ \"segment\")\n{\n\tsegment_op = Operator \"segment\" \n\t\tsegment Operator_type.COMPOUND_REWRAP false;\n\n\t[image, nsegs] = im_segment x;\n\timage' = im_copy_set_meta image \"n-segments\" nsegs;\n}\n\npoint a b\n\t= oo_binary_function point_op a b, is_class a\n\t= oo_binary'_function point_op a b, is_class b\n\t= im_read_point b x y, is_image b\n\t= [b?x?y], is_matrix b\n\t= [b?x], is_real_list b && y == 0\n\t= [b?y], is_real_list b && x == 0\n\t= error (_ \"bad arguments to \" ++ \"point\")\n{\n\tpoint_op = Operator \"point\" \n\t\t(\\a\\b Vector (point a b)) Operator_type.COMPOUND false;\n\n\t(x, y) \n\t\t= a, is_complex a;\n\t\t= (a?0, a?1), is_real_list a && is_list_len 2 a\n\t\t= error \"bad position format\";\n}\n\n/* One image in, one out. \n */\nsystem_image command x\n\t= oo_unary_function system_image_op x, is_class x\n\t= system x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"system_image\")\n{\n\tsystem_image_op = Operator \"system_image\" \n\t\t(system_image command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem im\n\t\t= image_out\n\t{\n\t\t[image_out, log] = \n\t\t\tim_system_image (get_image im) \"%s.tif\" \"%s.tif\" command;\n\t}\n}\n\n/* Two images in, one out. \n */\nsystem_image2 command x1 x2\n\t= oo_binary_function system_image2_op x1 x2, is_class x1\n\t= oo_binary'_function system_image2_op x1 x2, is_class x2\n\t= system x1 x2, is_image x1 && is_image x2\n\t= error (_ \"bad arguments to \" ++ \"system_image2\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image2 command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Three images in, one out. \n */\nsystem_image3 command x1 x2 x3\n\t= oo_binary_function system_image2_op x2 x3, is_class x2\n\t= oo_binary'_function system_image2_op x2 x3, is_class x3\n\t= system x1 x2 x3, is_image x1 && is_image x2 && is_image x3\n\t= error (_ \"bad arguments to \" ++ \"system_image3\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image3 command x1) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2 x3\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2, x3], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Zero images in, one out. \n */\nsystem_image0 command \n\t= Image image_out\n{\n\t[image_out] = vips_call \"system\" [command] [\n\t\t$out => true,\n\t\t$out_format => \"%s.tif\" \n\t];\n}\n\nhough_line w h x \n\t= oo_unary_function hough_line_op x, is_class x\n\t= hline (to_real w) (to_real h) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_line\")\n{\n\though_line_op = Operator \"hough_line\" \n\t\t(hough_line w h) Operator_type.COMPOUND_REWRAP false;\n\n\thline w h x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_line\" [x] [\n\t\t\t$width => w, \n\t\t\t$height => h\n\t\t];\n\t}\n}\n\nhough_circle s mn mx x \n\t= oo_unary_function hough_circle_op x, is_class x\n\t= hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_circle\")\n{\n\though_circle_op = Operator \"hough_circle\" \n\t\t(hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false;\n\n\thcircle s mn mx x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_circle\" [x] [\n\t\t\t$scale => s, \n\t\t\t$min_radius => mn, \n\t\t\t$max_radius => mx\n\t\t];\n\t}\n}\n\nmapim interp ind in\n\t= oo_binary_function mapim_op ind in, is_class ind\n\t= oo_binary'_function mapim_op ind in, is_class in\n\t= mapim_fn ind in, is_image ind && is_image in\n\t= error (_ \"bad arguments to \" ++ \"mapim\")\n{\n\tmapim_op = Operator \"mapim\" \n\t\t(mapim interp) Operator_type.COMPOUND_REWRAP false;\n\n\tmapim_fn ind im\n\t\t= out\n\t{\n\t\t[out] = vips_call \"mapim\" [im, ind] [$interpolate => interp];\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.3/_types.def",
    "content": "/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary (\\a op.fn a x) this,\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// we can't call map_trinary directly, since it uses Group and we\n\t// don't support mutually recursive top-level functions :-(\n\t// copy-paste it here, keep in sync with the version in _stdenv\n\tmap_nary fn args\n\t\t= fn args, groups == []\n\t\t= Group (map process [0, 1 .. shortest - 1])\n\t{\n\t\tgroups = filter is_Group args;\n\t\n\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\tprocess n\n\t\t\t= NULL, any (map (is_noval n) args)\n\t\t\t= map_nary fn (map (extract n) args)\n\t\t{\n\t\t\textract n arg\n\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t= arg;\n\t\n\t\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t\t}\n\t}\n\n\t// need ite as a true trinary\n\tite a b c = if a then b else c;\n\n\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t];\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\n\t\t[op.fn this.value x,\n\t\t\top.type == Operator_type.COMPOUND]\n\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[is_list_len 3 value, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.item colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum \"Colour space\" Image_type.colour_spaces default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\n/* An option whose value is a string rather than a number.\n */\nOption_string caption labels item = class\n\tOption caption labels (index (equal item) labels) {\n\tOption_edit caption labels value \n\t\t= this.Option_string caption labels (labels?value);\n}\n\n/* Make an option from an enum.\n */\nOption_enum caption enum item = class\n\tOption_string caption enum.names item {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing item;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum caption enum (enum.names?value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNONE = 0;\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNONE = 0;\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n\tRAD = 6;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* Extract a column.\n\t */\n\tcolumn n = map (extract n) value;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (column col) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (column from);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = this.column 0; \n\tthings = this.column 1; \n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tHISTOGRAM = 10;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tARRAY = 27;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t$MULTIBAND => MULTIBAND,\n\t\t$B_W => B_W,\n\t\t$HISTOGRAM => HISTOGRAM,\n\t\t$XYZ => XYZ,\n\t\t$LAB => LAB,\n\t\t$CMYK => CMYK,\n\t\t$LABQ => LABQ,\n\t\t$RGB => RGB,\n\t\t$UCS => UCS,\n\t\t$LCH => LCH,\n\t\t$LABS => LABS,\n\t\t$sRGB => sRGB,\n\t\t$YXY => YXY,\n\t\t$FOURIER => FOURIER,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$ARRAY => ARRAY\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options generated from this, so match the order to the order in the\n\t * Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t$sRGB => sRGB,\n\t\t$Lab => LAB,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t$Mono => B_W,\n\t\t$sRGB => sRGB,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$Lab => LAB,\n\t\t$LabQ => LABQ,\n\t\t$LabS => LABS,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \n\t\t// \"Image v == 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\t// if one of then/else is an image, get the target format from that\n\t\t// otherwise, let the non-image objects set the target\n\t\ttarget_format \n\t\t\t= get_member_list has_format get_format x, \n\t\t\t\thas_member_list has_format x\n\t\t\t= NULL;\n\n\t\tto_image x = to_image_size width height target_bands target_format x;\n\n\t\t[then', else'] = map to_image x;\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if value then then' else else');\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nKernel_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tLINEAR = 1;\n\tCUBIC = 2;\n\tLANCZOS2 = 3;\n\tLANCZOS3 = 4;\n\n\t// Should introspect to get the list of interpolators :-(\n\t// We can \"dir\" on VipsInterpolate to get a list of them, but we\n\t// can't get i18n'd descriptions until we have more\n\t// introspection stuff in nip2.\n\n\t/* Table to map kernel numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Linear\", \n\t\t_ \"Cubic\",\n\t\t_ \"Lanczos, two lobes\",\n\t\t_ \"Lanczos, three lobes\"\n\t];\n\n\t/* And to vips enum nicknames.\n\t */\n\ttypes = [\n\t\t\"nearest\", \n\t\t\"linear\", \n\t\t\"cubic\", \n\t\t\"lanczos2\", \n\t\t\"lanczos3\"\n\t];\n}\n\nKernel type = class {\n\tvalue = Kernel_type.types?type;\n}\n\nKernel_linear = Kernel Kernel_type.LINEAR;\n\nKernel_picker default = class \n\tKernel kernel.value {\n\t_vislevel = 2;\n\n\tkernel = Option \"Kernel\" Kernel_type.descriptions default;\n}\n\nInterpolate_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\tLBB = 3;\n\tNOHALO = 4;\n\tVSQBS = 5;\n\n\t// Should introspect to get the list of interpolators :-(\n\t// We can \"dir\" on VipsInterpolate to get a list of them, but we\n\t// can't get i18n'd descriptions until we have more\n\t// introspection stuff in nip2.\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Bilinear\", \n\t\t_ \"Bicubic\",\n\t\t_ \"Upsize: reduced halo bicubic (LBB)\",\n\t\t_ \"Upsharp: reduced halo bicubic with edge sharpening (Nohalo)\",\n\t\t_ \"Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)\"\n\t];\n\n\t/* And to vips type names.\n\t */\n\ttypes = [\n\t\t\"VipsInterpolateNearest\",\n\t\t\"VipsInterpolateBilinear\",\n\t\t\"VipsInterpolateBicubic\",\n\t\t\"VipsInterpolateLbb\",\n\t\t\"VipsInterpolateNohalo\",\n\t\t\"VipsInterpolateVsqbs\"\n\t];\n}\n\nInterpolate type options = class {\n\tvalue = vips_object_new Interpolate_type.types?type [] options;\n}\n\nInterpolate_bilinear = Interpolate Interpolate_type.BILINEAR [];\n\nInterpolate_picker default = class \n\tInterpolate interp.value [] {\n\t_vislevel = 2;\n\n\tinterp = Option \"Interpolation\" Interpolate_type.descriptions default;\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t_ \"Perceptual\" => PERCEPTUAL,\n\t\t_ \"Relative\" => RELATIVE,\n\t\t_ \"Saturation\" => SATURATION,\n\t\t_ \"Absolute\" => ABSOLUTE\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t_ \"Point\" => POINT,\n\t\t_ \"Line\" => LINE,\n\t\t_ \"Spline\" => SPLINE,\n\t\t_ \"Bar\" => BAR\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t_ \"YYYY\" => YYYY,\n\t\t_ \"XYYY\" => XYXY,\n\t\t_ \"XYXY\" => XYXY\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n\tto_image dpi = extract_bands 0 3 \n\t\t(graph_export_image (to_real dpi) this);\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [$format => Plot_format.XYYY] value {\n}\n\n/* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate\n * empty slots, for example.\n */\nNULL = class \n\t_Object {\n\too_binary_table op x = [\n\t\t// the only operation we allow is equality .. use pointer equality,\n\t\t// this lets us test a == NULL and a != NULL\n\t\t[this === x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"equal\"],\n\t\t[this !== x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"not_equal\"]\n\t] ++ super.oo_binary_table op x;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.4/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t[_L, _a, _b] = default_value;\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n\n\tCCT_colour = class\n\t\tMenuaction (_ \"Colour from CCT\") (_ \"pick colour by CCT\") {\n\t\taction = widget 6500;\n\n\t\twidget x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tT = Scale \"CCT\" 1800 25000 x;\n\n\t\t\t_result = colour_from_temp (to_real T);\n\n\t\t\tColour_edit space value \n\t\t\t\t= widget (temp_from_colour (Colour space value));\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Convert to\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Tag as\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum (_ \"Old whitepoint\") Whitepoints \"D65\";\n\t\t\tnew_white = Option_enum (_ \"New whitepoint\") Whitepoints \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCCT_item = class\n\t\tMenuaction (_ \"Calculate temperature\")\n\t\t\t(_ \"estimate CCT using the McCamy approximation\") {\n\t\taction z = map_unary temp_from_colour z;\n\t}\n\n\tColour_item = Colour_new_item.CCT_colour;\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= print_profile, \n\t\t\thas_type image && \n\t\t\tget_type image == Image_type.CMYK &&\n\t\t\thas_bands image && \n\t\t\tget_bands image >= 4\n\t\t= monitor_profile;\n\trender_intents = Option_enum (_ \"Render intent\") Render_intent.names\n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_rad_item = class\n\tMenupullright (_ \"_Radiance\") (_ \"convert to and from Radiance packed format\") {\n\tUnpack_item = class\n\t\tMenuaction (_ \"Unpack\") \n\t\t\t(_ \"unpack Radiance format to float\") {\n\t\taction x = map_unary rad2float x;\n\t}\n\n\tPack_item = class\n\t\tMenuaction (_ \"Pack\") \n\t\t\t(_ \"pack 3-band float to Radiance format\") {\n\t\taction x = map_unary float2rad x;\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n        // get a representative image from an arg\n        get_image x\n            = get_image x.value?0, is_Group x\n            = x;\n\n        _im = get_image x; \n\t\tsample = measure_draw (to_real pacross) (to_real pdown) \n\t\t\t\t(to_real measure) _im;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure_sample (to_real pacross) (to_real pdown) \n\t\t\t\t\t(to_real measure) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.4/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 2;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 20;\n\t\t\tfs = Scale \"Sharpen flat areas by\" 0 5 0.5;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" 0 5 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tlayers = Scale \"Layers\" 1 100 10;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\", \"Approximate\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf, aconvsep layers]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\t\t\trotate = Option \"Rotate\" [\n\t\t\t\t\"Don't rotate\", \n\t\t\t\t\"4 x 45 degrees\", \n\t\t\t\t\"8 x 45 degrees\", \n\t\t\t\t\"2 x 90 degrees\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_lindetect, !separable && type == 0 && rotate == 1\n\t\t\t\t\t\t= im_compass, !separable && type == 0 && rotate == 2\n\t\t\t\t\t\t= im_gradient, !separable && type == 0 && rotate == 3\n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_conv_f, !separable && type == 1\n\t\t\t\t\t\t= im_convsep_f, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 4) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width.expr window_height.expr in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\nFilter_hough_item = class\n\tMenupullright \"_Hough Transform\" \"transform to parameter space\" {\n\tLine_item = class\n\t\tMenuaction \"_Line\" \"find straight line Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpspace_width = Expression \"Parameter space width\" 64;\n\t\t\tpspace_height = Expression \"Parameter space height\" 64;\n\n\t\t\t_result \n\t\t\t\t= map_unary line a \n\t\t\t{\n\t\t\t\tline a \n\t\t\t\t\t= hough_line \n\t\t\t\t\t\t(to_real pspace_width) (to_real pspace_height) a;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class\n\t\tMenuaction \"_Circle\" \"find circle Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Expression \"Scale down parameter space by\" 10;\n\t\t\tmin_radius = Expression \"Minimum radius\" 10;\n\t\t\tmax_radius = Expression \"Maximum radius\" 30;\n\n\t\t\t_result \n\t\t\t\t= map_unary circle a \n\t\t\t{\n\t\t\t\tcircle a \n\t\t\t\t\t= hough_circle (to_real scale) (to_real min_radius)\n\t\t\t\t\t\t(to_real max_radius) a;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_coordinate_item = class\n\tMenupullright \"_Coordinate Transform\" \"various coordinate transforms\" {\n\t// run a function which wants a complex arg on a non-complex two-band\n\t// image\n\trun_cmplx fn x\n\t\t= re x' ++ im x'\n\t{\n\t\tx' = fn (x?0, x?1);\n\t}\n\n\tPolar_item = class\n\t\tMenuaction \"_Polar\" \"transform to polar coordinates\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result \n\t\t\t\t= map_unary to_polar a \n\t\t\t{\n\t\t\t\tto_polar im \n\t\t\t\t\t= mapim interp.value map' im\n\t\t\t\t{\n\t\t\t\t\t// xy image, origin in the centre, scaled to fit image to\n\t\t\t\t\t// a circle\n\t\t\t\t\txy = make_xy im.width im.height;\n\t\t\t\t\txy' = xy - Vector [im.width / 2, im.height / 2];\n\t\t\t\t\tscale = min [im.width, im.height] / im.width;\n\t\t\t\t\txy'' = 2 * xy' / scale;\n\n\t\t\t\t\t// to polar, scale vertical axis to 360 degrees\n\t\t\t\t\tmap = run_cmplx polar xy'';\n\t\t\t\t\tmap' = map * Vector [1, im.height / 360];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tRectangular_item = class\n\t\tMenuaction \"_Rectangular\" \"transform to rectangular coordinates\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result \n\t\t\t\t= map_unary to_rect a \n\t\t\t{\n\t\t\t\tto_rect im \n\t\t\t\t\t= mapim interp.value map'' im\n\t\t\t\t{\n\t\t\t\t\t// xy image, vertical scaled to 360 degrees\n\t\t\t\t\txy = make_xy im.width im.height;\n\t\t\t\t\txy' = xy * Vector [1, 360 / im.height];\n\n\t\t\t\t\t// to rect, scale to image rect\n\t\t\t\t\tmap = run_cmplx rectangular xy';\n\t\t\t\t\tscale = min [im.width, im.height] / im.width;\n\t\t\t\t\tmap' = map * scale / 2;\n\n\t\t\t\t\tmap'' = map' + Vector [im.width / 2, im.height / 2];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image\" \"use an image to blend two objects\" {\n\t\taction a b c = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ti = Toggle \"Invert mask\" false;\n\n\t\t\t_result \n\t\t\t\t= map_trinary process a b c\n\t\t\t{\n\t\t\t\tprocess a b c \n\t\t\t\t\t= blend condition in1 in2, !i\n\t\t\t\t\t= blend (invert condition) in1 in2\n\t\t\t\t{\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t\t= false,\n\t\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t\t= true;\n\t\t\t\t\t[condition, in1, in2] = sortc compare [a, b, c];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"_Alpha\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t_ \"Normal\" => NORMAL,\n\t\t\t_ \"If Lighter\" => IFLIGHTER,\n\t\t\t_ \"If Darker\" => IFDARKER,\n\t\t\t_ \"Multiply\" => MULTIPLY,\n\t\t\t_ \"Add\" => ADD,\n\t\t\t_ \"Subtract\" => SUBTRACT,\n\t\t\t_ \"Screen\" => SCREEN,\n\t\t\t_ \"Burn\" => BURN,\n\t\t\t_ \"Soft Light\" => SOFTLIGHT,\n\t\t\t_ \"Hard Light\" => HARDLIGHT,\n\t\t\t_ \"Lighten\" => LIGHTEN,\n\t\t\t_ \"Darken\" => DARKEN,\n\t\t\t_ \"Dodge\" => DODGE,\n\t\t\t_ \"Reflect\" => REFLECT,\n\t\t\t_ \"Freeze\" => FREEZE,\n\t\t\t_ \"Bitwise OR\" => OR,\n\t\t\t_ \"Bitwise AND\" => AND\n\t\t];\n\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum \"Blend mode\" names \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\t[mono, colour] = \n\t\t\t\t\tsortc (const (is_colour_type @ get_type)) [a, b];\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t_ \"Grey\",\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t_ \"North-west\",\n\t\t\t\t_ \"North\",\n\t\t\t\t_ \"North-east\",\n\t\t\t\t_ \"West\",\n\t\t\t\t_ \"Centre\",\n\t\t\t\t_ \"East\",\n\t\t\t\t_ \"South-west\",\n\t\t\t\t_ \"South\",\n\t\t\t\t_ \"South-east\",\n\t\t\t\t_ \"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nAutotrace_item = class \n\tMenuaction \"_Trace\" \"convert a bitmap to an SVG file\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tdespeckle = Scale \"Despeckle level\" 1 20 1;\n\t\tline = Scale \"Line threshold\" 1 20 1;\n\t\tcenter = Toggle \"Trace centreline\" false;\n\t\tscale = Scale \"SVG scale\" 0.1 10 1;\n\n\t\tcommand \n\t\t\t= \"autotrace %s \" ++ join_sep \" \" \n\t\t\t\t[ofmt, ofile, desp, lint, cent]\n\t\t{\n\t\t\tprog = search_for_error \"autotrace\"; \n\t\t\tofmt = \"-output-format svg\";\n\t\t\tofile = \"-output-file %s\";\n\t\t\tdesp = \"-despeckle-level \" ++ print despeckle.value;\n\t\t\tlint = \"-line-threshold \" ++ print line.value;\n\t\t\tcent = if center then \"-centerline \" else \"\";\n\t\t}\n\n\t\t_result \n\t\t\t= Image output\n\t\t{\n\t\t\t[output] = vips_call \"system\" \n\t\t\t\t[command] \n\t\t\t\t[$in => [x.value],\n\t\t\t\t $in_format => \"%s.ppm\", \n\t\t\t\t $out => true,\n\t\t\t\t $out_format => \"%s.svg[scale=\" ++ print scale.value ++ \"]\"\n\t\t\t\t];\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.4/Histogram.def",
    "content": "Hist_new_item = class\n\tMenupullright \"_New\" \"new histogram\" {\n\tHist_item = class\n\t\tMenuaction \"_Identity\" \"make an identity histogram\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\t_result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d);\n\t\t}\n\t}\n\n\tHist_new_from_matrix = Matrix_buildlut_item; \n\n\tHist_from_image_item = class\n\t\tMenuaction \"Ta_g Image As Histogram\" \"set image Type to Histogram\" {\n\t\taction x = hist_tag x;\n\t}\n\n\tTone_item = class \n\t\tMenuaction \"_Tone Curve\" \"make a new tone mapping curve\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\t_result \n\t\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t\t{\n\t\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_convert_to_hist_item = class \n\tMenuaction \"Con_vert to Histogram\" \"convert anything to a histogram\" {\n\taction x = hist_tag (to_image x);\n}\n\nHist_find_item = class \n\tMenupullright \"_Find\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n\n\tIndexed_item = class\n\t\tMenuaction \"_Indexed\" \n\t\t\t\"use a 1-band index image to pick bins for an n-band image\" {\n\t\taction x y \n\t\t\t= map_binary map x y\n\t\t{\n\t\t\tmap a b\n\t\t\t\t= hist_find_indexed index im\n\t\t\t{\n\t\t\t\t[im, index] = sortc (const is_index) [a, b];\n\n\t\t\t\tis_index x\n\t\t\t\t\t= has_image x && b == 1 && \n\t\t\t\t\t\t(f == Image_format.UCHAR || f == Image_format.USHORT)\n\t\t\t\t{\n\t\t\t\t\tim = get_image x;\n\t\t\t\t\tb = get_bands x;\n\t\t\t\t\tf = get_format x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\t[im, hist] = sortc (const is_hist) [a, b];\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Integrate\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate\" \n\t\t\"find point-to-point differences (inverse of Integrate)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_inv_item = class \n\tMenuaction \"In_vert\" \"invert a histogram\" {\n\taction x = map_unary hist_inv x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\tarea = extract_arrow \n\t\t\t\t\tdisplace.value vdisplace.value width.value arrow;\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize Kernel_linear 1 (1 / width.value) area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary (extract_arrow \n\t\t\t\tdisplace.value vdisplace.value width.value) x;\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcaption = Expression \"Chart caption\" \"none\";\n\t\tformat = Option_enum \"Format\" Plot_format.names \"YYYY\";\n\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\t\txcaption = Expression \"X axis caption\" \"none\";\n\t\tycaption = Expression \"Y axis caption\" \"none\";\n\t\tseries_captions = Expression \"Series captions\" [\"Band 0\"];\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => style.value, $format => format.value] ++ \n\t\t\t\t\trange ++ captions;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\tcaptions \n\t\t\t\t= concat (map test caption_options) ++ \n\t\t\t\t  [$series_captions => series_captions.expr]\n\t\t\t{\n\t\t\t\tcaption_options = [\n\t\t\t\t\t$caption => caption.expr,\n\t\t\t\t\t$xcaption => xcaption.expr,\n\t\t\t\t\t$ycaption => ycaption.expr\n\t\t\t\t];\n\t\t\t\ttest x\n\t\t\t\t\t= [], value == \"none\"\n\t\t\t\t\t= [option_name => value]\n\t\t\t\t{\n\t\t\t\t\t[option_name, value] = x;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow 0 0 1 x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.4/Image.def",
    "content": "Image_new_item = class Menupullright \"_New\" \"make new things\" {\n\tImage_black_item = class Menuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \"Image type\"\n\t\t\t\tImage_type.type_names \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region on image using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\t[target, x] = sortc compare [a, b];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\nImage_number_format_item = class\n\tMenupullright \"_Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_header_item = class \n\tMenupullright \"_Header\" \"do stuff to the image header\" {\n\n\tImage_get_item = class\n\t\tMenupullright \"_Get\" \"get header fields\" {\n\n\t\t// the header fields we can get\n\t\tfields = class {\n\t\t\ttype = 0;\n\t\t\twidth = 1;\n\t\t\theight = 2;\n\t\t\tformat = 3;\n\t\t\tbands = 4;\n\t\t\txres = 5;\n\t\t\tyres = 6;\n\t\t\txoffset = 7;\n\t\t\tyoffset = 8;\n\t\t\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t$width => width,\n\t\t\t\t$height => height,\n\t\t\t\t$bands => bands,\n\t\t\t\t$format => format,\n\t\t\t\t$type => type,\n\t\t\t\t$xres => xres,\n\t\t\t\t$yres => yres,\n\t\t\t\t$xoffset => xoffset,\n\t\t\t\t$yoffset => yoffset,\n\t\t\t\t$coding => coding\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum (_ \"Field\") field_names name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tCustom_item = class\n\t\t\tMenuaction \"C_ustom\" \"get any header field\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tfield = String \"Field\" \"Xsize\";\n\t\t\t\tparse = Option \"Parse\" [\n\t\t\t\t\t\"No parsing\",\n\t\t\t\t\t\"Parse string as integer\",\n\t\t\t\t\t\"Parse string as real\",\n\t\t\t\t\t\"Parse string as hh:mm:ss\"\n\t\t\t\t] 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary (wrap @ process @ get_header field.value) x\n\t\t\t\t{\n\t\t\t\t\tparse_str parse str = parse (split is_space str)?0;\n\n\t\t\t\t\tparse_field name cast parse x\n\t\t\t\t\t\t= cast x, is_number x\n\t\t\t\t\t\t= parse_str parse x, is_string x\n\t\t\t\t\t\t= error (\"not \" ++ name);\n\n\t\t\t\t\tget_int = parse_field \"int\" \n\t\t\t\t\t\tcast_signed_int parse_int;\n\t\t\t\t\tget_float = parse_field \"float\" \n\t\t\t\t\t\tcast_float parse_float;\n\t\t\t\t\tget_time = parse_field \"hh:mm:ss\" \n\t\t\t\t\t\tcast_signed_int parse_time;\n\n\t\t\t\t\twrap x\n\t\t\t\t\t\t= Real x, is_real x\n\t\t\t\t\t\t= Vector x, is_real_list x\n\t\t\t\t\t\t= Image x, is_image x\n\t\t\t\t\t\t= Bool x, is_bool x\n\t\t\t\t\t\t= Matrix x, is_matrix x\n\t\t\t\t\t\t= String \"String\" x, is_string x\n\t\t\t\t\t\t= List x, is_list x\n\t\t\t\t\t\t= x;\n\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tget_int, \n\t\t\t\t\t\tget_float,\n\t\t\t\t\t\tget_time\n\t\t\t\t\t]?parse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum \"Image type\" Image_type.type_names \n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_cache_item = class\n\tMenuaction \"C_ache\" \"cache calculated image pixels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttile_width = Number \"Tile width\" 128;\n\t\ttile_height = Number \"Tile height\" 128;\n\t\tmax_tiles = Number \"Maximum number of tiles to cache\" (-1);\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= cache (to_real tile_width) (to_real tile_height) \n\t\t\t\t\t(to_real max_tiles) image;\n\t\t}\n\t}\n}\n\n#separator\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\t// we can't use id here since we want to \"declass\"\n\t\t\t\t\t\t// the members of x ... consider if x is a crop class,\n\t\t\t\t\t\t// for example, we don't want to inherit from crop, we\n\t\t\t\t\t\t// want to make a new image class\n\t\t\t\t\t\trot180 @ rot180,\n\t\t\t\t\t\trot90,\n\t\t\t\t\t\trot180,\n\t\t\t\t\t\trot270\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate interp angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary straighten x\n\t\t\t\t{\n\t\t\t\t\tstraighten arrow\n\t\t\t\t\t\t= rotate interp angle'' arrow.image\n\t\t\t\t\t{\n\t\t\t\t\t\tx = arrow.width;\n\t\t\t\t\t\ty = arrow.height;\n\t\t\n\t\t\t\t\t\tangle = im (polar (x, y));\n\t\t\n\t\t\t\t\t\tangle'\n\t\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t\t= angle;\n\t\t\n\t\t\t\t\t\tangle''\n\t\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize kernel xfactor yfactor image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\taspect = Toggle \"Break aspect ratio\" false;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize kernel h v image, aspect\n\t\t\t\t\t\t= resize kernel fac fac image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac > yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\tmin_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac < yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\t[h, v] = [\n\t\t\t\t\t\t\tmax_factor, \n\t\t\t\t\t\t\tmin_factor, \n\t\t\t\t\t\t\t[xfac, 1], \n\t\t\t\t\t\t\t[1, yfac]]?which;\n\n\t\t\t\t\t\tfac \n\t\t\t\t\t\t\t= h, v == 1\n\t\t\t\t\t\t\t= v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_within_item = class\n\t\t\tMenuaction \"Size _Within\" \"size to fit within a rectangle\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\t// the rects we size to fit within\n\t\t\t\t_rects = [\n\t\t\t\t\t[2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], \n\t\t\t\t\t[1280, 1024], [1024, 768], [800, 600], [640, 480] \n\t\t\t\t];\n\n\t\t\t\twithin = Option \"Fit within (pixels)\" (\n\t\t\t\t\t[print w ++ \" x \" ++ print h :: [w, h] <- _rects] ++\n\t\t\t\t\t[\"Custom\"]\n\t\t\t\t) 4;\n\t\t\t\tcustom_width = Expression \"Custom width\" 1000;\n\t\t\t\tcustom_height = Expression \"Custom height\" 1000;\n\t\t\t    size = Option \"Page size\" [\n\t\t\t\t\t\"Full page\", \"Half page\", \"Quarter page\" \n\t\t\t\t] 0;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t \t_result\n\t\t\t\t \t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\txdiv = [1, 2, 2]?size;\n\t\t\t\t\tydiv = [1, 1, 2]?size;\n\t\t\t\t\tallrect = _rects ++ [\n\t\t\t\t\t\t[custom_width.expr, custom_height.expr]\n\t\t\t\t\t];\n\t\t\t\t\t[width, height] = allrect?within;\n\n\t\t\t\t\tprocess x\n\t\t\t\t\t\t= resize kernel fac fac x, fac < 1\n\t\t\t\t\t\t= x\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = (width / xdiv) / x.width;\n\t\t\t\t\t\tyfac = (height / ydiv) / x.height;\n\t\t\t\t\t\tfac = min_pair xfac yfac;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_map_item = class\n\t\tMenuaction \"_Map\" \"map an image through a 2D transform image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result\n\t\t\t\t= map_binary trans a b\n\t\t\t{\n\t\t\t\ttrans a b\n\t\t\t\t\t= mapim interp.value in index\n\t\t\t\t{\n\t\t\t\t\t// get the index image first\n\t\t\t\t\t[index, in] = sortc (const is_twocomponent) [a, b];\n\n\t\t\t\t\t// is a two-component image, ie. one band complex, or\n\t\t\t\t\t// two-band non-complex\n\t\t\t\t\tis_twocomponent x\n\t\t\t\t\t\t= is_nonc x || is_c x;\n\t\t\t\t\tis_nonc x\n\t\t\t\t\t\t= has_bands x && get_bands x == 2 && \n\t\t\t\t\t\t\thas_format x && !is_complex_format (get_format x);\n\t\t\t\t\tis_c x\n\t\t\t\t\t\t= has_bands x && get_bands x == 1 && \n\t\t\t\t\t\t\thas_format x && is_complex_format (get_format x);\n\t\t\t\t\tis_complex_format f\n\t\t\t\t\t\t= f == Image_format.COMPLEX || \n\t\t\t\t\t\t\tf == Image_format.DPCOMPLEX;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\" [\"Nearest\", \"Bilinear\"] 1;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_trn {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t[sample', trn, err] = transform_search \n\t\t\t\t\tmax_err max_iter order interp wrap\n\t\t\t\t\tsample reference;\n\t\t\t\ttransformed_image = Image sample';\n\t\t\t\t_trn = Transform trn reference.width reference.height;\n\t\t\t\tfinal_error = err;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\t[i, t] = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tBandwise_item = Image_join_item.Bandwise_item;\n\n    sep1 = Menuseparator;\n\n\tBandand_item = class\n\t\tMenuaction \"Bitwise Band AND\" \"bitwise AND of image bands\" {\n\t\taction x = bandand x;\n\t}\n\n\tBandor_item = class\n\t\tMenuaction \"Bitwise Band OR\" \"bitwise OR of image bands\" {\n\t\taction x = bandor x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldl1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x \n\t\t= crop x [l, t, w, h]\n\t{\n\t\tfields = [\n\t\t\t[has_left, get_left, 0],\n\t\t\t[has_top, get_top, 0],\n\t\t\t[has_width, get_width, 100],\n\t\t\t[has_height, get_height, 100]\n\t\t];\n\n\t\t[l, t, w, h] \n\t\t\t= map get_default fields\n\t\t{\n\t\t\tget_default line\n\t\t\t\t= get x, has x\n\t\t\t\t= default\n\t\t\t{\n\t\t\t\t[has, get, default] = line;\n\t\t\t}\n\t\t}\n\t}\n\n\tcrop x geo = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tl = Expression \"Crop left\" ((int) (geo?0 + geo?2 / 4));\n\t\tt = Expression \"Crop top\" ((int) (geo?1 + geo?3 / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (geo?2 / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (geo?3 / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t[_a', _b'] = sortc _pred [a, b];\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_draw_item = class \n\tMenupullright \"_Draw\" \"draw lines, circles, rectangles, floods\" {\n\tLine_item = class Menuaction \"_Line\" \"draw line on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tx1 = Expression \"Start x\" 0;\n\t\t\ty1 = Expression \"Start y\" 0;\n\t\t\tx2 = Expression \"End x\" 100;\n\t\t\ty2 = Expression \"End y\" 100;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary line x\n\t\t\t{\n\t\t\t\tline im \n\t\t\t\t\t= draw_line x1 y1 x2 y2 i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tRect_item = class Menuaction \"_Rectangle\" \"draw rectangle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\trx = Expression \"Left\" 50;\n\t\t\try = Expression \"Top\" 50;\n\t\t\trw = Expression \"Width\" 100;\n\t\t\trh = Expression \"Height\" 100;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\tt = Scale \"Line thickness\" 1 50 3;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary rect x\n\t\t\t{\n\t\t\t\trect im \n\t\t\t\t\t= draw_rect_width rx ry rw rh f t i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class Menuaction \"_Circle\" \"draw circle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcx = Expression \"Centre x\" 100;\n\t\t\tcy = Expression \"Centre y\" 100;\n\t\t\tr = Expression \"Radius\" 50;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary circle x\n\t\t\t{\n\t\t\t\tcircle im \n\t\t\t\t\t= draw_circle cx cy r f i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tFlood_item = class Menuaction \"_Flood\" \"flood bounded area of image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsx = Expression \"Start x\" 100;\n\t\t\tsy = Expression \"Start y\" 100;\n\n\t\t\te = Option \"Flood while\" [\n\t\t\t\t\"Not equal to ink\",\n\t\t\t\t\"Equal to start point\"\n\t\t\t] 0;\n\n\t\t\t// pick a default ink that won't flood, if we can\n\t\t\ti \n\t\t\t\t= Expression \"Ink\" default_ink\n\t\t\t{\n\t\t\t\tdefault_ink\n\t\t\t\t\t= [0], ! has_image x\n\t\t\t\t\t= pixel;\n\t\t\t\tpixel = map mean (bandsplit (extract_area sx sy 1 1 im));\n\t\t\t\tim = get_image x;\n\t\t\t}\n\n\t\t\t_result \n\t\t\t\t= map_unary flood x\n\t\t\t{\n\t\t\t\tflood im \n\t\t\t\t\t= draw_flood sx sy i.expr im, e == 0\n\t\t\t\t\t= draw_flood_blob sx sy i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tDraw_scalebar_item = class Menuaction \"_Scale\" \"draw scale bar\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpx = Expression \"Left\" 50;\n\t\t\tpy = Expression \"Top\" 50;\n\t\t\twid = Expression \"Width\" 100;\n\t\t\tthick = Scale \"Line thickness\" 1 50 3;\n\t\t\ttext = String \"Dimension text\" \"50μm\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\tpos = Option \"Position Text\" [\"Above\", \"Below\"] 1;\n\t\t\tvp = Option \"Dimension by\" [\n\t\t\t\t\"Inner Vertical Edge\", \n\t\t\t\t\"Centre of Vertical\", \n\t\t\t\t\"Outer Vertical Edge\"\n\t\t\t] 1;\n            dpi = Expression \"DPI\" 100;\n            ink = Colour \"Lab\" [50,0,0];\n      \n            _result\n                = map_unary process x\n            {\n                process im\n                    = blend (Image scale) ink' im\n                {\n                    // make an ink compatible with the image\n                    ink' = colour_transform_to (get_type im) ink;\n\n                    x = to_real px;\n                    y = to_real py;\n                    w = to_real wid;\n                    d = to_real dpi;\n\n                    t = floor thick;\n\n                    bg = image_new (get_width im) (get_height im) (get_bands im)\n                        (get_format im) (get_coding im) (get_type im) 0 0 0;\n                    draw_block x y w t im =\n                        draw_rect_width x y w t true 1 [255] im;\n                    label = im_text text.value font.value w 1 d;\n                    lw = get_width label;\n                    lh = get_height label;\n                    ly = [y - lh - t, y + 2 * t]?pos;\n                    vx = [\n\t\t\t\t\t\t[x - t, x + w],\n\t\t\t\t\t\t[x - t / 2, x + w - t / 2],\n\t\t\t\t\t\t[x, x + w - t]\n\t\t\t\t\t]?vp;\n\n\t\t\t\t\tscale = (draw_block x y w t @\n\t\t\t\t\t\tdraw_block vx?0 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tdraw_block vx?1 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tinsert_noexpand (x + w / 2 - lw / 2) ly label)\n\t\t\t\t\t\tbg;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise Join\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t// we can't use map_unary since chop-into-tiles returns a group of\n\t\t\t// groups and we want to be able to reassemble that\n\t\t\t// TODO: chop-into-tiles should return an array class which\n\t\t\t// displays as group but does not have the looping behaviour?\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n\n\tArrayFL_item = class\n\t\tMenuaction \"_Array from List\"\n\t\t\t\"join a list of images into a single image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tncol = Number \"Max. Number of Columns\" 1;\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t_l \n\t\t\t\t= split_lines ncol.value x.value, is_Group x\n\t\t\t\t= split_lines ncol.value x;\n\n\t\t\t_result\n\t\t\t\t= (image_set_origin 0 0 @\n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value\n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list _l));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tNoise_item = class\n\t\tMenupullright \"_Noise\" \"various noise generators\" {\n\t\tGaussian_item = class \n\t\t\tMenuaction \"_Gaussian\" \"make an image of gaussian noise\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t\t_result = Image (im_gaussnoise \n\t\t\t\t\t(to_real nwidth) (to_real nheight) \n\t\t\t\t\tmean.value deviation.value);\n\t\t\t}\n\t\t}\n\n\t\tFractal_item = class \n\t\t\tMenuaction \"_Fractal\" \"make a fractal noise image\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t\t}\n\t\t}\n\n\t\tPerlin_item = class \n\t\t\tMenuaction \"_Perlin\" \"Perlin noise image\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\t\tcell_size = Expression \"Cell size (pixels)\" 8;\n\t\t\t\teight = Toggle \"Eight bit output\" true;\n\n\t\t\t\t_result \n\t\t\t\t\t= 128 * im + 128, eight\n\t\t\t\t\t= im\n\t\t\t\t{\n\t\t\t\t\tim = perlin cell_size nwidth nheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tWorley_item = class \n\t\t\tMenuaction \"_Worley\" \"Worley noise image\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnwidth = Expression \"Image width (pixels)\" 512;\n\t\t\t\tnheight = Expression \"Image height (pixels)\" 512;\n\t\t\t\tcell_size = Expression \"Cell size (pixels)\" 256;\n\n\t\t\t\t_result \n\t\t\t\t\t= worley cell_size nwidth nheight;\n\t\t\t}\n\t\t}\n\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n\tColour_atlas_item = class\n\tMenuaction \"_Colour Atlas\"\n\t\t\"make a grid of patches grouped around a colour\" {\n\t\taction = class \n\t\t\t_result {   \n\t\t\t_vislevel = 3;\n       \n\t\t\tstart = Colour_picker \"Lab\" [50,0,0];\n\t\t\tnstep = Expression \"Number of steps\" 9;\n\t\t\tssize = Expression \"Step size\" 10; \n\t\t\tpsize = Expression \"Patch size\" 32;\n\t\t\tsepsize = Expression \"Separator size\" 4;\n\t\n\t\t\t_result\n\t\t\t\t= colour_transform_to (get_type start) blocks'''\n\t\t\t{\n\t\t\t\tsize = (to_real nstep * 2 + 1) * to_real psize - \n\t\t\t\t\tto_real sepsize;\n\t\t\t\txy = make_xy size size; \n\n\t\t\t\txy_grid = (xy % to_real psize) < \n\t\t\t\t\t(to_real psize - to_real sepsize);\n\t\t\t\tgrid = xy_grid?0 & xy_grid?1;\n\n\t\t\t\tblocks = (int) (to_real ssize * ((int) (xy / to_real psize)));\n\t\t\t\tlab_start = colour_transform_to Image_type.LAB start;\n\t\t\t\tblocks' = blocks - to_real nstep * to_real ssize + \n\t\t\t\t\tVector (tl lab_start.value);\n\t\t\t\tblocks'' = hd lab_start.value ++ Image blocks';\n\t\t\t\tblocks''' \n\t\t\t\t\t= image_set_type Image_type.LAB blocks'', Image grid\n\t\t\t\t\t= 0;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.4/Magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate Magick.def\n   13-Apr-2014 snibgo\n     Put \"new image\" items into sub-menu.\n     New class VirtualPixlBack.\n   17-Apr-2014 snibgo\n     Many small changes.\n     A few new menu options.\n     Created sub-menu for multi-input operations.\n   3-May-2014 jcupitt\n     Put quotes around ( in shadow to help unix\n\n   Last update: 17-Apr-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n*/\n\n// We don't need Noop.\n/*===\nMagick_noop_item = class\n\tMenuaction \"_Noop\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_testPar_item = class\n\tMenuaction \"_TestPar\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"( +clone ) +append \",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/* Removed Read_item and Write_item, much better to use nip2 load/save image.\n * Plus they can load all libMagick formats anyway.\n */\n\n\n// Put \"new image\" items into sub-menu\nMagick_NewImageMenu_item = class\n\tMenupullright \"_New image\" \"make a new image\" {\n\n\tMagick_newcanvas_item = class\n\t\tMenuaction \"_Solid colour\" \"make image of solid colour\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tcolour = Magick.generalcol_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"\\\"canvas:\" ++ colour._flag ++ \"\\\"\", \n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_builtin_item = class\n\t\tMenuaction \"_Built-in image\" \"create a built-in image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbuiltin = Magick.builtin_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tbuiltin._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_gradient_item = class\n\t\tMenuaction \"_Gradient\" \"make a linear gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\ttopColour = Magick.generalcol_widget;\n\t\t\tbottomColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"gradient:\", \n\t\t\t\t\ttopColour._flag, \"-\", bottomColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_hald_item = class\n\t\tMenuaction \"_Hald-clut image\" \"create an identity hald-clut image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torder = Expression \"order\" 8;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"hald:\" ++ print order.expr,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_pattern_item = class\n\t\tMenuaction \"_Pattern\" \"create pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tpattern = Magick.pattern_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tpattern._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_plasma_item = class\n\t\tMenuaction \"_Plasma image\" \"create plasma image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\t// FIXME? ColourA-ColourB.\n\t\t\t// FIXME? Allow plasma:fractal?\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"plasma:\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_radialgradient_item = class\n\t\tMenuaction \"_Radial gradient\" \n\t\t\t\"make a radial gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tinnerColour = Magick.generalcol_widget;\n\t\t\touterColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"radial-gradient:\", \n\t\t\t\t\tinnerColour._flag, \"-\", outerColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n}  // end Magick_NewImageMenu_item\n\n\nMagick_MultiMenu_item = class\n\tMenupullright \"_Multiple inputs\" \"make an image from multiple images\" {\n\n\tMagick_composite_item = class\n\t\tMenuaction \"_Composite\" \"composite two images (without mask)\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag,\n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_compositeMask_item = class\n\t\tMenuaction \"_Composite masked\" \"composite two images (with mask)\" {\n\t\taction x y z = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag, \n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system3 command x y z; \n\t\t}\n\t}\n\n\t// FIXME: other operations like remap that take another image as arguments are:\n\t// mask (pointless?), texture, tile (pointless?)\n\n\t// FIXME: operations that take a filename that isn't an image:\n\t// cdl, profile\n\n\tMagick_clut_item = class\n\t\tMenuaction \"_Clut\" \"replace values using second image as colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// FIXME: uses -intensity \"when mapping greyscale CLUT image to alpha channel if set by -channels\"\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_haldclut_item = class\n\t\tMenuaction \"_Hald clut\" \"replace values using second image as Hald colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-hald-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\n\t// Encipher and decipher: key files can be text or image files.\n\n\tMagick_encipher_item = class\n\t\tMenuaction \"_Encipher/Decipher\" \"encipher or decipher an image image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname = Pathname \"Read key file\" \"\";\n\t\t\tisDecipher = Toggle \"Decipher\" false;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname.value == \"\" then \"\" else (\n\t\t\t\t\t( if isDecipher then \"-decipher \" else \"-encipher \") ++\n\t\t\t\t\t( \"\\\"\" ++ pathname.value ++ \"\\\"\" )\n\t\t\t\t),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_profile_item = class\n\t\tMenuaction \"_Profile\" \"assigns/applies an ICC profile\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname1 = Pathname \"Read profile file\" \"\";\n\t\t\tpathname2 = Pathname \"Read profile file\" \"\";\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname1.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname1.value ++ \"\\\"\"),\n\t\t\t\tif pathname2.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname2.value ++ \"\\\"\"),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_remap_item = class\n\t\tMenuaction \"_Remap\" \"reduce colours to those in another image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-remap\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n}  // end Magick_MultiMenu_item\n\n\nMagick_image_type_item = class\n\tMenuaction \"_Image Type\" \"change image type\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\timagetype = Magick.imagetype_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\timagetype._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nsep2 = Menuseparator;\n\nMagick_alpha_item = class\n\tMenuaction \"_Alpha\" \"add/remove alpha channel\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\talpha = Magick.alpha_widget; \n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\talpha._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_annotate_item = class\n\tMenuaction \"_Annotate\" \"add text annotation\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttext = Magick.text_widget;\n\t\tfont = Magick.Font_widget;\n\t\tgeometry = Magick.AnnotGeometry_widget; \n\t\tgravity = Magick.gravity_widget; \n\t\tforeground = Magick.foreground_widget;\n\t\tundercol = Magick.undercol_widget;\n\t\tantialias = Magick.antialias_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfont._flag,\n\t\t\tantialias._flag,\n\t\t\tgravity._flag,\n\t\t\tforeground._flag,\n\t\t\tundercol._flag,\n\t\t\t\"-annotate\", \n\t\t\tgeometry._flag, \n\t\t\t\"\\\"\" ++ text.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoGamma_item = class\n\tMenuaction \"_AutoGamma\" \"automatic gamma\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-gamma\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoLevel_item = class\n\tMenuaction \"_AutoLevel\" \"automatic level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-level\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_blurSharpMenu_item = class\n\tMenupullright \"_Blur/Sharpen\" \"blur and sharpen\" {\n\n\tMagick_adaptive_blur_item = class\n\t\tMenuaction \"_Adaptive Blur\" \"blur less near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\t// note: adaptive-blur doesn't regard VP.\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-adaptive-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blur_item = class\n\t\tMenuaction \"_Blur\" \"blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_gaussianBlur_item = class\n\t\tMenuaction \"_Gaussian Blur\" \"blur with a Gaussian operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-gaussian-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_motionBlur_item = class\n\t\tMenuaction \"_Motion Blur\" \"simulate motion blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tangle = Scale \"angle\" (-360) 360 0;\n\t\t\tchannels = Magick.ch_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-motion-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_rotationalBlur_item = class\n\t\tMenuaction \"_RotationalBlur\" \"blur around the centre\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-radial-blur\", \n\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_selectiveBlur_item = class\n\t\tMenuaction \"_Selective Blur\" \"blur where contrast is less than or equal to threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-selective-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++  \"+\" ++\n\t\t\t\t\tprint threshold.value ++ \"%%\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMagick_adaptive_sharpen_item = class\n\t\tMenuaction \"_Adaptive Sharpen\" \"sharpen more near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\t\"-adaptive-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_sharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"sharpen\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_unsharpen_item = class\n\t\tMenuaction \"_Unsharp\" \"sharpen with unsharp mask\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tgain = Scale \"Gain\" (-10) 10 1;\n\t\t\tthreshold = Scale \"Threshold\" 0 1 0.05;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-unsharp\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint gain.value ++ \"+\" ++\n\t\t\t\t\tprint threshold.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end BlurSharpMenu_item\n\n\nMagick_border_item = class\n\tMenuaction \"_Border\" \"add border of given colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcompose = Magick.compose_widget;\n\t\twidth = Expression \"Width\" 3;\n\t\tbordercol = Magick.bordercol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag,\n\t\t\tbordercol._flag,\n\t\t\t\"-border\", \n\t\t\tprint width.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_brightCont_item = class\n\tMenuaction \"_Brightness-contrast\" \"adjust the brightness and/or contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbri = Scale \"brightness\" (-100) 100 0;\n\t\tcon = Scale \"contrast\" (-100) 100 0;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-brightness-contrast\", \n\t\t\tprint bri.value ++ \"x\" ++ print con.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// Note: canny requires ImageMagick 6.8.9-0 or later.\n\nMagick_canny_item = class\n\tMenuaction \"_Canny\" \"detect a wide range of edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tlowPc = Scale \"lower percent\" 0 100 10;\n\t\thighPc = Scale \"lower percent\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-canny\", \n\t\t\tconcat [\"\\\"\",\n\t\t\t\tprint radius.value ++ \"x\" ++ \n\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\tprint lowPc.value ++ \"%%+\" ++\n\t\t\t\tprint highPc.value ++ \"%%\" ++ \"\\\"\"\n\t\t\t],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_charcoal_item = class\n\tMenuaction \"_Charcoal\" \"simulate a charcoal drawing\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tfactor = Scale \"factor\" 0 50 1;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-charcoal\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_chop_item = class\n\tMenuaction \"_Chop\" \"remove pixels from the interior\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-chop\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorize_item = class\n\tMenuaction \"_Colorize\" \"colorize by given amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tval = Scale \"value\" 0 100 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-colorize\", \n\t\t\tprint val.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colors_item = class\n\tMenuaction \"_Colors\" \"reduce number of colors\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\t\tquantize = Magick.colorspace_widget;\n\t\tcolors = Expression \"Colours\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-quantize\", quantize._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\tdither._flag,\n\t\t\t\"-colors\", \n\t\t\tprint colors.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: color-matrix?\n\nMagick_colorspace_item = class\n\tMenuaction \"_Colourspace\" \"convert to arbitrary colourspace\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolsp = Magick.colorspace_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-colorspace\",\n\t\t\tcolsp._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorspaceGray_item = class\n\tMenuaction \"_Colourspace gray\" \"convert to gray using given intensity method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-colorspace gray\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrast_item = class\n\tMenuaction \"_Contrast\" \"increase or reduce the contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tisReduce = Toggle \"reduce contrast\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t(if isReduce then \"+\" else \"-\") ++ \"contrast\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrastStretch_item = class\n\tMenuaction \"_Contrast stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-contrast-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: convolve (bias, kernel)\n\nMagick_crop_item = class\n\tMenuaction \"_Crop\" \"cut out a rectangular region\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-crop\",\n\t\t\tgeometry._flag,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_deskew_item = class\n\tMenuaction \"_Deskew\" \"straighten the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\t// FIXME: toggle auto-crop?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-deskew\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_despeckle_item = class\n\tMenuaction \"_Despeckle\" \"reduce the speckles\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-despeckle\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_distort_item = class\n\tMenuaction \"_Distort\" \"distort using a method and arguments\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tdistort = Magick.distort_widget;\n\t\targs = String \"Arguments\" \"1,0\";\n\t\tisPlus = Toggle \"Extend to show entire image\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t(if isPlus then \"+\" else \"-\") ++ \"distort\",\n\t\t\tdistort._flag,\n\t\t\targs.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_draw_item = class\n\tMenuaction \"_Draw\" \"annotate with one or more graphic primitives\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\targs = String \"Arguments\" \"line 0,0 9,9 rectangle 10,10 20,20\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-draw\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_edge_item = class\n\tMenuaction \"_Edge\" \"detect edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-edge\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_emboss_item = class\n\tMenuaction \"_Emboss\" \"emboss\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-emboss\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_enhance_item = class\n\tMenuaction \"_Enhance\" \"enhance a noisy image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-enhance\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_equalize_item = class\n\tMenuaction \"_Equalize\" \"equalize the histogram\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-equalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_evaluate_item = class\n\tMenuaction \"_Evaluate\" \"evaluate an expression on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\toperation = Magick.evaluate_widget;\n\t\tval = Expression \"value\" 5;\n\t\tisPc = Toggle \"Value is percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag, \n\t\t\toperation._flag, \n\t\t\tprint val.expr ++ if isPc then \"%%\" else \"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_extent_item = class\n\tMenuaction \"_Extent\" \"set the image size and offset\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-extent\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_FlipFlopMenu_item = class\n\tMenupullright \"_Flip/flop\" \"flip/flop/transverse/transpose\" {\n\n\tMagick_flip_item = class\n\t\tMenuaction \"_Flip vertically\" \"mirror upside-down\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flip\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_flop_item = class\n\t\tMenuaction \"_Flop horizontally\" \"mirror left-right\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flop\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transpose_item = class\n\t\tMenuaction \"_Transpose\" \"mirror along the top-left to bottom-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transpose +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transverse_item = class\n\t\tMenuaction \"_Transverse\" \"mirror along the bottom-left to top-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transverse +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end Magick_FlipFlopMenu_item\n\n\nMagick_floodfill_item = class\n\tMenuaction \"_Floodfill\" \"recolour neighbours that match\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tfuzz = Magick.fuzz_widget;\n\t\tcoordinate = Magick.coordinate_widget;\n\n\t\t// -draw \"color x,y floodfill\"\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-draw \\\" color\",\n\t\t\tcoordinate._flag,\n\t\t\t\"floodfill \\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_frame_item = class\n\tMenuaction \"_Frame\" \"surround with border or beveled frame\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tborder = Magick.bordercol_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tmatte = Magick.mattecol_widget;\n\t\tgeometry = Magick.FrameGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tborder._flag, \n\t\t\tmatte._flag, \n\t\t\t\"-frame\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_function_item = class\n\tMenuaction \"_Function\" \"evaluate a function on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfunction = Magick.function_widget;\n\t\t// FIXME: explain values; use sensible defaults.\n\t\tvalues = String \"values\" \"0,0,0,0\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-function\", \n\t\t\tfunction._flag, \n\t\t\tvalues.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_fx_item = class\n\tMenuaction \"_Fx\" \"apply a mathematical expression\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\targs = String \"Expression\" \"u*1/2\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\tinterpolate._flag,\n\t\t\tvirtpixback._flag,\n\t\t\t\"-fx\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gamma_item = class\n\tMenuaction \"_Gamma\" \"apply a gamma correction\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tgamma = Magick.gamma_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-gamma\",\n\t\t\tprint gamma.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradient_item = class\n\tMenuaction \"_Gradient\" \"apply a linear gradient\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolourA = Magick.generalcol_widget;\n\t\tcolourB = Magick.generalcol_widget;\n\n\t\tposition = Option \"colourA is at\" [\n\t\t\t\t\"top\", \"bottom\", \n\t\t\t\t\"left\", \"right\", \n\t\t\t\t\"top-left\", \"top-right\", \n\t\t\t\t\"bottom-left\", \"bottom-right\"] 0;\n\t\t_baryArg\n\t\t\t= concat [\"0,0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 0\n\t\t\t= concat [\"0,0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 1\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],0,\", colourB._flag], position.value == 2\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],0,\", colourA._flag], position.value == 3\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourB._flag], position.value == 4\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 5\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 6\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourA._flag], position.value == 7\n\t\t\t= \"dunno\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color barycentric \\\"\" ++ _baryArg ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradientCorn_item = class\n\tMenuaction \"_Gradient corners\" \n\t\t\"apply a bilinear gradient between the corners\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour_top_left = Magick.generalcol_widget;\n\t\tcolour_top_right = Magick.generalcol_widget;\n\t\tcolour_bottom_left = Magick.generalcol_widget;\n\t\tcolour_bottom_right = Magick.generalcol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color bilinear \\\"\" ++\n\t\t\t\t\"0,0,\" ++ colour_top_left._flag ++\n\t\t\t\t\",%%[fx:w-1],0\" ++ colour_top_right._flag ++\n\t\t\t\t\",0,%%[fx:h-1]\" ++ colour_bottom_left._flag ++\n\t\t\t\t\",%%[fx:w-1],%%[fx:h-1]\" ++ colour_bottom_right._flag ++ \"\\\"\",\n\t\t\t\"+depth\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_histogram_item = class\n\tMenuaction \"_Histogram\" \"make a histogram image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-define histogram:unique-colors=false histogram:\" ++\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_implode_item = class\n\tMenuaction \"_Implode\" \"implode pixels about the center\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfactor = Scale \"factor\" 0 20 1;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\t// FIXME: virtual-pixel?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tinterpolate._flag,\n\t\t\t\"-implode\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_level_item = class\n\tMenuaction \"_Level\" \"adjust the level of channels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"black point\" (-100) 200 0;\n\t\twht = Scale \"white point\" (-100) 200 100;\n\t\tgam = Scale \"gamma\" 0 30 1;\n\t\tisPc = Toggle \"Levels are percent\" true;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \",\" ++ \n\t\t\t\tprint wht.value ++ (if isPc then \"%%\" else \"\") ++ \",\" ++ \n\t\t\t\tprint gam.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_levelCols_item = class\n\tMenuaction \"_Level colors\" \"adjust levels to given colours\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcolour_black = Magick.generalcol_widget;\n\t\tcolour_white = Magick.generalcol_widget;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level-colors\",\n\t\t\t\"\\\"\" ++ colour_black._flag ++ \",\" ++ colour_white._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_linearStretch_item = class\n\tMenuaction \"_Linear stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-linear-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_magnify_item = class\n\tMenuaction \"_Magnify\" \"double the size of the image with pixel art scaling\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-magnify\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_modulate_item = class\n\tMenuaction \"_Modulate\" \"modulate brightness, saturation and hue\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmodcolsp = Magick.ModColSp_widget;\n\t\tbright = Scale \"brightness\" 0 200 100;\n\t\tsat = Scale \"saturation\" 0 200 100;\n\t\thue = Scale \"hue\" 0 200 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tmodcolsp._flag,\n\t\t\t\"-modulate\",\n\t\t\tprint bright.value ++ \",\" ++ print sat.value ++ \",\" ++ \n\t\t\t\tprint hue.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_monochrome_item = class\n\tMenuaction \"_Monochrome\" \"transform to black and white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// FIXME: also intensity?\n\n\t\tintensity = Magick.intensity_widget;\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tdither._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\t\"-monochrome\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_morphology_item = class\n\t// See http://www.imagemagick.org/Usage/morphology/\n\tMenuaction \"_Morphology\" \"apply a morphological method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmethod = Magick.morphmeth_widget;\n\t\titer = Expression \"Iterations (-1=repeat until done)\" 1;\n\n\t\tkernel = Magick.kernel_widget;\n\t\t// FIXME: custom kernel eg \"3x1+2+0:1,0,0\"\n\t\t//   width x height + offsx + offsy : {w*h values}\n\t\t//   each value is 0.0 to 1.0 or \"NaN\" or \"-\"\n\n\t\t// kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0\n\t\t// but\n\t\t//   ring takes: radius1, radius2, scale\n\t\t//   rectangle and comet take: width x height + offsx + offsy\n\t\t//   blur takes: radius x sigma\n\t\t// FIXME: for now, simply allow any string input.\n\t\tkernel_arg = String \"Kernel arguments\" \"\";\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-morphology\",\n\t\t\tmethod._flag ++ \":\" ++ print iter.expr, \n\t\t\tkernel._flag ++\n\t\t\t(if kernel_arg.value == \"\" then \"\" else \":\") ++ kernel_arg.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_negate_item = class\n\tMenuaction \"_Negate\" \"negate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-negate\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_addNoise_item = class\n\tMenuaction \"_add Noise\" \"add noise\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tattenuate = Scale \"attenuate\" 0 1.0 1.0;\n\t\tnoise = Magick.noise_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-attenuate\", \n\t\t\tprint attenuate.value,\n\t\t\tnoise._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_normalize_item = class\n\tMenuaction \"_Normalize\" \"normalize\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-normalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_opaque_item = class\n\tMenuaction \"_Opaque\" \"change this colour to the fill colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfill = Magick.foreground_widget;\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfill._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"opaque\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_paint_item = class\n\tMenuaction \"_Paint\" \"simulate an oil painting\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"radius\" 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-paint\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/*=== FIXME Bug; remove for now.\nPolaroid_item = class\n\tMenuaction \"_Polaroid\" \"simulate a polaroid picture\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle\" (-90) 90 20;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-polaroid\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_posterize_item = class\n\tMenuaction \"_Posterize\" \"reduce to (n) levels per channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tlevels = Expression \"levels\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-posterize\",\n\t\t\tprint levels.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_raise_item = class\n\tMenuaction \"_Raise\" \"lighten or darken image edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthk = Expression \"Thickness\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-raise\",\n\t\t\tprint thk.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_resize_item = class\n\tMenuaction \"_Resize\" \"resize to given width and height\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfilter = Magick.filter_widget;\n\t\ttype = Magick.ResizeType_widget;\n\t\twidth = Scale \"Width\" 1 100 10;\n\t\theight = Scale \"Height\" 1 100 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfilter._flag,\n\t\t\t\"-\" ++ type._flag,\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"!\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_roll_item = class\n\tMenuaction \"_Roll\" \"roll an image horizontally or vertically\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trollx = Expression \"X\" 3;\n\t\trolly = Expression \"Y\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-roll\",\n\t\t\t(if rollx.expr >= 0 then \"+\" else \"\") ++ print rollx.expr ++\n\t\t\t(if rolly.expr >= 0 then \"+\" else \"\") ++ print rolly.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_rotate_item = class\n\tMenuaction \"_Rotate\" \"rotate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"+distort\",\n\t\t\t\"SRT\",\n\t\t\tprint angle.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -segment, but cluster-threshold should be percentage of image area.\n\nMagick_sepia_item = class\n\tMenuaction \"_Sepia tone\" \"simulate a sepia-toned photo\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sepia-tone\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shade_item = class\n\tMenuaction \"_Shade\" \"shade with a distant light source\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tazimuth = Scale \"Azimuth (degrees)\" (-360) 360 0;\n\t\televation = Scale \"Elevation (degrees)\" 0 90 45;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shade\",\n\t\t\tprint azimuth.value ++ \"x\" ++ print elevation.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shadow_item = class\n\tMenuaction \"_Shadow\" \"simulate a shadow\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshadowCol = Magick.generalcol_widget;\n\t\topacity = Scale \"Opacity (percent)\" 0 100 75;\n\t\tsigma = Scale \"Sigma\" 0 30 2;\n\t\t// FIXME: make offsets a single widget?\n\t\toffsx = Scale \"X-offset\" (-20) 20 4;\n\t\toffsy = Scale \"Y-offset\" (-20) 20 4;\n\t\tarePc = Toggle \"offsets are percentages\" false;\n\n\t\t// FIXME: raw operation creates page offset, which vips dislikes.\n\t\t// So we take this futher, compositing with source.\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"(\\\" +clone\",\n\t\t\t\"-background\", \"\\\"\" ++ shadowCol._flag ++ \"\\\"\",\n\t\t\t\"-shadow\",\n\t\t\tconcat [\n\t\t\t\t\"\\\"\",\n\t\t\t\tprint opacity.value, \"x\", print sigma.value,\n\t\t\t\t(if offsx.value >= 0 then \"+\" else \"\"), print offsx.value,\n\t\t\t\t(if offsy.value >= 0 then \"+\" else \"\"), print offsy.value,\n\t\t\t\t(if arePc then \"%%\" else \"\"),\n\t\t\t\t\"\\\"\"\n\t\t\t],\n\t\t\t\"\\\")\\\" +swap -background None -layers merge\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shave_item = class\n\tMenuaction \"_Shave\" \"shave pixels from the edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 0 50 10;\n\t\theight = Scale \"Height\" 0 50 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shave\",\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shear_item = class\n\tMenuaction \"_Shear\" \"shear along the x-axis and/or y-axis\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-shear\",\n\t\t\tprint shearX.expr ++ \"x\" ++ print shearY.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sigmoid_item = class\n\tMenuaction \"_Sigmoid\" \"increase or decrease mid-tone contrast sigmoidally\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcontrast = Scale \"contrast\" 0 30 3;\n\t\tmidpoint = Scale \"mid-point (percent)\" 0 100 50;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"sigmoidal-contrast\",\n\t\t\t\"\\\"\" ++ print contrast.value ++ \"x\" ++ \n\t\t\t\tprint midpoint.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sketch_item = class\n\tMenuaction \"_Sketch\" \"simulate a pencil sketch\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tangle = Scale \"angle\" (-360) 360 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sketch\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if angle >= 0 then (\"+\" ++ print angle.value) else \"\"),\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_solarize_item = class\n\tMenuaction \"_Solarize\" \"negate all pixels above a threshold level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-solarize\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -sparse-color needs abitrary list of {x,y,colour}.\n\nMagick_splice_item = class\n\tMenuaction \"_Splice\" \"splice a colour into the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-splice\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_spread_item = class\n\tMenuaction \"_Spread\" \"displace pixels by random amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tamount = Expression \"Amount (pixels)\" 5;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"-spread\",\n\t\t\tprint amount.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_statistic_item = class\n\tMenuaction \"_Statistic\" \"replace each pixel with statistic from neighbourhood\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width\" 5;\n\t\theight = Expression \"Height\" 5;\n\t\tstatisticType = Magick.StatType_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-statistic\", \n\t\t\tstatisticType._flag, \n\t\t\tprint width.expr ++ \"x\" ++ print height.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_swirl_item = class\n\tMenuaction \"_Swirl\" \"swirl around the centre\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Magick.angle_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-swirl\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_thresholdMenu_item = class\n\tMenupullright \"_Threshold\" \"make black or white\" {\n\n\tMagick_threshold_item = class\n\t\tMenuaction \"_Threshold\" \"apply black/white threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-threshold\", \n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blackThreshold_item = class\n\t\tMenuaction \"_Black threshold\" \"where below threshold set to black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-black-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_whiteThreshold_item = class\n\t\tMenuaction \"_White threshold\" \"where above threshold set to white\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-white-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_latThreshold_item = class\n\t\tMenuaction \"_Local Adaptive Threshold\" \"where above average plus offset set to white, otherwise black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twidth = Expression \"Width\" 10;\n\t\t\theight = Expression \"Height\" 10;\n\t\t\toffset = Scale \"Offset (percent)\" (-100) 100 0;\n\t\t\t// note: \"-lat\" doesn't respond to channels\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-lat\",\n\t\t\t\tconcat [\"\\\"\", print width.expr, \"x\", print height.expr, \n\t\t\t\t\t(if offset.value >= 0 then \"+\" else \"\"), print offset.value,\n\t\t\t\t\t\"%%\\\"\"\n\t\t\t\t],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_randThreshold_item = class\n\t\tMenuaction \"_Random Threshold\" \"between specified limits, apply random threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tlow = Scale \"Low threshold\" 0 100 10;\n\t\t\thigh = Scale \"High threshold\" 0 100 90;\n\t\t\tisPc = Toggle \"Thresholds are percent\" true;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-random-threshold\", \n\t\t\t\t\"\\\"\" ++ print low.value ++ \"x\" ++ print high.value ++\n\t\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end ThresholdMenu_item\n\n\n// Note: alternatives include:\n// convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif\n\nMagick_tile_item = class\n\tMenuaction \"_Tile\" \"fill given size with tiled image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tsize = Magick.Size_widget;\n\n\t\tcommand = Magick.command [\n\t\t\tsize._flag,\n\t\t\t\"tile:\" ++ \"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_tint_item = class\n\tMenuaction \"_Tint\" \"apply a tint\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tamount = Scale \"amount (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-tint\",\n\t\t\t// snibgo note: although the amount is a percentage, it doesn't need \"%\" character.\n\t\t\tprint amount.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_transparent_item = class\n\tMenuaction \"_Transparent\" \"make this colour transparent\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"transparent\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_trim_item = class\n\tMenuaction \"_Trim\" \"trims away border\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfuzz = Magick.fuzz_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-trim +repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_uniqueCols_item = class\n\tMenuaction \"_Unique colours\" \"discard all but one of any pixel color\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-unique-colors\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_vignette_item = class\n\tMenuaction \"_Vignette\" \"soften the edges in vignette style\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\trx = Scale \"Rolloff x (percent)\" 0 100 10;\n\t\try = Scale \"Rolloff y (percent)\" 0 100 10;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-vignette\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if rx.value >= 0 then \"+\" else \"\") ++ print rx.value ++\n\t\t\t\t(if ry.value >= 0 then \"+\" else \"\") ++ print ry.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_wave_item = class\n\tMenuaction \"_Wave\" \"shear the columns into a sine wave\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tamplitude = Scale \"Amplitude (pixels)\" 0 100 10;\n\t\twavelength = Scale \"Wavelength (pixels)\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-wave\",\n\t\t\tprint amplitude.value ++ \"x\" ++ print wavelength.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\n"
  },
  {
    "path": "share/nip2/compat/8.4/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/8.4\n\nstart_DATA = \\\n\tMath.def \\\n\tImage.def \\\n\tMagick.def \\\n\tColour.def \\\n\tTasks.def \\\n\tObject.def \\\n\tFilter.def \\\n\tMatrix.def \\\n\tWidgets.def \\\n\tHistogram.def \\\n\tPreferences.ws \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_convert.def \\\n\t_generate.def \\\n\t_list.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\t_Object.def \\\n\t_magick.def \\\n\t_types.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/8.4/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_AND\" \"bitwise AND of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_OR\" \"bitwise OR of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"_XOR\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_NOT\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBandand_item = Image_band_item.Bandand_item; \n\n\tBandor_item = Image_band_item.Bandor_item; \n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tDifference_item = class \n\t\tMenuaction \"_Difference\" \"difference of two lists\" {\n\t\taction a b = map_binary difference a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tValue_item = class \n\t\tMenuaction \"_Value\" \"value of point in object\" {\n\t\taction a = class _result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tposition = Expression \"Coordinate\" (0, 0);\n\t\n\t\t\t_result = map_binary point position.expr a;\n\t\t}\n\t}\n\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tSkew_item = class \n\t\tMenuaction \"S_kew\" \"skew of image or list or vector\" {\n\t\taction a = map_unary skew a;\n\t}\n\n\tKurtosis_item = class \n\t\tMenuaction \"Kurtosis\" \"kurtosis of image or list or vector\" {\n\t\taction a = map_unary kurtosis a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \n\t\t\t\"position of centre of gravity of histogram\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = linreg xes yes;\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = linregw xes yes devs;\n\t}\n\n\tCluster_item = class \n\t\tMenuaction \"_Cluster\" \"cluster a list of numbers\" {\n\t\taction l = class {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tthresh = Expression \"Threshold\" 10;\n\t\n\t\t\t[_r, _w] = cluster thresh.expr l;\n\t\n\t\t\tresult = _r;\n\t\t\tweights = _w;\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.4/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_identity_item = class \n\t\tMenuaction \"_Identity\" \"make an identity matrix\" {\n\t\taction = identity (identity_matrix 5);\n\t\t\n\t\tidentity v = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix (identity_matrix (to_real s)), to_real s != len v;\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = identity value;\n\t\t}\n\t}\n\n\tMatrix_series_item = class \n\t\tMenuaction \"_Series\" \"make a series\" {\n\t\taction = series (mkseries 0 1 5);\n\n\t\tmkseries s t e \n\t\t\t= transpose [[to_real s, to_real s + to_real t .. to_real e]];\n\n\t\tseries v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t_s = v?0?0;\n\t\t\t_t = v?1?0 - v?0?0;\n\t\t\t_e = (last v)?0;\n\n\t\t\ts = Expression \"Start value\" _s;\n\t\t\tt = Expression \"Step by\" _t;\n\t\t\te = Expression \"End value\" _e;\n\n\t\t\t_result \n\t\t\t\t= Matrix (mkseries s t e), \n\t\t\t\t\t\tto_real s != _s || to_real t != _t || to_real e != _e\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = series value;\n\t\t}\n\t}\n\n\tMatrix_square_item = class \n\t\tMenuaction \"_Square\" \"make a square matrix\" {\n\t\taction = square (mksquare 5);\n\n\t\tmksquare s = replicate s (take s [1, 1 ..]);\n\n\t\tsquare v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == to_real s\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mksquare (to_real s); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = square value;\n\t\t}\n\t}\n\n\tMatrix_circular_item = class \n\t\tMenuaction \"_Circular\" \"make a circular matrix\" {\n\t\taction = circle (mkcircle 3);\n\n\t\tmkcircle r\n\t\t\t\t= map2 (map2 pyth) xes yes\n\t\t{\n\t\t\tline = [-r .. r];\n\t\t\txes = replicate (2 * r + 1) line;\n\t\t\tyes = transpose xes;\n\t\t\tpyth a b \n\t\t\t\t\t= 1, (a**2 + b**2) ** 0.5 <= r\n\t\t\t\t\t= 0;\n\t\t}\n\n\t\tcircle v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tr = Expression \"Radius\" ((len v - 1) / 2);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mkcircle (to_real r); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = circle value;\n\t\t}\n\t}\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\nMatrix_sort_item = class \n\tMenuaction \"_Sort\" \"sort by column or row\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\to = Option (_ \"Orientation\") [\n\t\t\t_ \"Sort by column\",\n\t\t\t_ \"Sort by row\"\n\t\t] 0;\n\t\ti = Expression (_ \"Sort on index\") 0;\n\t\td = Option (_ \"Direction\") [\n\t\t\t_ \"Ascending\",\n\t\t\t_ \"Descending\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary sort x\n\t\t{\n\t\t\tidx = to_real i;\n\t\t\tpred a b \n\t\t\t\t= a?idx <= b?idx, d == 0\n\t\t\t\t= a?idx >= b?idx;\n\t\t\tsort x\n\t\t\t\t= (x.Matrix_base @ sortc pred) x.value,\n\t\t\t\t\to == 0\n\t\t\t\t= (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value;\n\t\t}\n\t}\n}\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ \n\t\t\t\t\trange;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.4/Object.def",
    "content": "Object_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nObject_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nObject_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nObject_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nObject_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.4/Preferences.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"680\" window_height=\"800\" filename=\"$VIPSHOME/share/$PACKAGE/start/Preferences.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"100\" lpane_open=\"false\" rpane_position=\"400\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"Preferences\">\n    <Column x=\"0\" y=\"3067\" open=\"false\" selected=\"false\" sform=\"false\" next=\"99\" name=\"B\" caption=\"Interface column -- don't touch this!\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"CSV_SEPARATOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"O1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PRINT_CARTIESIAN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F10.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"USE_GRAPHICSMAGICK\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D45.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_PANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"237\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"788\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"700\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"100\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RELOAD\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D42.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_STATUSBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR_STYLE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MATRIX_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_RECOMP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"N2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_MAX_UNDO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[-1,0,1,5,10]?N1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_FONT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"N4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_INTERLACE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_LINELENGTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D41.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A6.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE_FILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PPM_MODE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"G1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_LAYOUT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C16.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C18.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_MULTI_RES\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_FORMAT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_PREDICTOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_BIGTIFF\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_START\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D25.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_SEARCH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D2.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_TMP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_SLIDER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D28.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_REGION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D29.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_AUTO_WS_SAVE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D30.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_DISPLAY_LED\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLKITBROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_MAX_HEAP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D38.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PIN_FILESEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_STATUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CONVERSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_RULERS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CROSSHAIR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL_HQ\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E21.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_TRACE_FUNCTIONS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"H1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_DEVICE\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CHANNEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_BRIGHTNESS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_COLOUR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CONTRAST\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_HUE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_FRAMES\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J13.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_MONO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J14.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_LEFT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_TOP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_ASPECT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_MAX_BLEND_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_REFINE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_WINDOW_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_OBJECT_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_BALANCE_GAMMA\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"680\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER_REMOTE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"POPUP_NEW_ROWS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_HISTORY_MAX\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D43.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_CPUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D44.value\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2831\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"I\" caption=\"Mosaic defaults\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Maximum blend width&quot; 0 100 10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Refine tie-points&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search windows this size&quot; 30\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search for objects this size&quot; 10\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Image gamma for mosaic balance&quot; 1 3 1.6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2495\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"J\" caption=\"Video for linux\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"J2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;Device&quot; &quot;/dev/video&quot;\"/>\n            <Pathname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Channel&quot; [&quot;TV&quot;, &quot;Composite 1&quot;, &quot;Composite 2&quot;, &quot;Composite 3&quot;] 1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Brightness&quot; 0 32767 23000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Colour&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Contrast&quot; 0 32767 27000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Hue&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Number of frames to average&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Grab monochrome&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2208\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"K\" caption=\"General video capture\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"K1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Crop video: \" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Crop video&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop left&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop top&quot; 6\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number  &quot;Crop width&quot; 747\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop height&quot; 570\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Aspect ratio (stretch vertically\\nby this much)&quot; 1.202\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2072\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"M\" caption=\"PNG save options\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"M1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Compression&quot; (map print [0..9]) 6\"/>\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Interlace&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1970\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"G\" caption=\"PPM/PGM/PBM save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"PPM mode\" labelsn=\"2\" labels0=\"Binary\" labels1=\"ASCII\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Mode&quot; [&quot;Binary&quot;, &quot;ASCII&quot;] 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1620\" open=\"true\" selected=\"true\" sform=\"false\" next=\"27\" name=\"C\" caption=\"TIFF save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Compression&quot; [&quot;None&quot;, &quot;LZW&quot;, &quot;Zip (deflate)&quot;, &quot;PACKBITS&quot;, &quot;JPEG&quot;, &quot;CCITTFAX4&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;JPEG quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Deflate/LZW predictor&quot; [&quot;None&quot;,&quot;Horizontal difference&quot;,&quot;Floating-point&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Layout\" labelsn=\"2\" labels0=\"Strip\" labels1=\"Tile\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Layout&quot; [&quot;Strip&quot;, &quot;Tile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile width&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile height&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Multi-res&quot; [&quot;Single image&quot;, &quot;Image pyramid&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Format&quot; [&quot;No truncation&quot;,&quot;Save 1 band 8 bit images as 1 bit&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Save as BigTIFF&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1518\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"O\" caption=\"CSV save\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"String &quot;Separator character&quot; &quot;\\t&quot;\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1348\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"A\" caption=\"JPEG save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;ICC profile&quot; [&quot;Use image profile, if any&quot;, &quot;Embed profile from file&quot;, &quot;Don't attach a profile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Pathname/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;ICC profile file&quot; &quot;$VIPSHOME/share/nip2/data/sRGB.icm&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1144\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"F\" caption=\"Widgets\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Pin up file requestors&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Main window toolbar&quot; [&quot;Default style&quot;, &quot;Icon only&quot;, &quot;Text only&quot;, &quot;Icon and text&quot;, &quot;Icon and text to right&quot;] 0\"/>\n            <Option caption=\"Main window toolbar\" labelsn=\"5\" labels0=\"Default style\" labels1=\"Icon only\" labels2=\"Text only\" labels3=\"Icon and text\" labels4=\"Icon and text to right\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display LEDs in workspace&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display complex numbers as coordinates&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1044\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"H\" caption=\"Debug options\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Disassemble functions\" value=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;untitled&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"906\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"L\" caption=\"Help browser\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"L2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Command to start browser&quot; &quot;firefox&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Go-to-page argument&quot; &quot;-remote 'openURL(%s)'&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"734\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"N\" caption=\"Paintbox \">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Max undo steps\" labelsn=\"5\" labels0=\"Unlimited\" labels1=\"None\" labels2=\"1\" labels3=\"5\" labels4=\"10\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Max undo steps&quot; [&quot;Unlimited&quot;, &quot;None&quot;, &quot;1&quot;, &quot;5&quot;, &quot;10&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Fontname &quot;Default paintbox font&quot; &quot;Sans 12&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Fontname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update during paint&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"458\" open=\"true\" selected=\"false\" sform=\"false\" next=\"27\" name=\"E\" caption=\"Image display\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"E20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use crosshair cursor in image windows&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Thumbnail size&quot; 64\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;High-quality thumbnails&quot; false\"/>\n            <Toggle/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window width&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window height&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto image window pop up&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"46\" name=\"D\" caption=\"Calculation\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Data path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;data&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;data&quot;], &quot;.&quot;]\"/>\n            <Expression caption=\"Data path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Temporary files&quot; (path_relative [&quot;$SAVEDIR&quot;, &quot;tmp&quot;])\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Start path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;start&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;start&quot;]]\"/>\n            <Expression caption=\"Start path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D28\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update sliders during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update sliders during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D29\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update regions during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update regions during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D30\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto workspace save&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D42\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto-reload on file change&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D41\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Text display length (characters)&quot; 80\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D38\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Heap size (per workspace)&quot; 600000\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D43\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of VIPS functions to memoise&quot; 20000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D44\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of CPUs to use (0 for autodetect)&quot; 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D45\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use GraphicsMagick for Magick menu&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/compat/8.4/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\n\tCsv_import_item = class\n\t\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tstart_line = Expression \"Start at line\" 1;\n\t\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_csv2vips filename)\n\t\t\t{\n\t\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\t\tescape x \n\t\t\t\t\t= foldr prefix [] x\n\t\t\t\t{\n\t\t\t\t\tprefix x l\n\t\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t\t= x : l;\n\t\t\t\t}\n\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tRaw_import_item = class\n\t\tMenuaction \"_Raw Import\" \"read a file of binary values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tacross = Expression \"Pixels across\" 100;\n\t\t\tdown = Expression \"Pixels down\" 100;\n\t\t\tbytes = Expression \"Bytes per pixel\" 3;\n\t\t\tskip = Expression \"Skip over initial bytes\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_binfile path.value \n\t\t\t\t\tacross.expr down.expr bytes.expr skip.expr)\n\t\t\t{\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// interpret Analyze header for layout and calibration\n\tAnalyze7_header_item = class\n\t\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\t\"examine the Analyze header and set layout and value\" {\n\t\taction x \n\t\t\t= x'''\n\t\t{\n\t\t\t// read bits of header\n\t\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\t\tdim0 = dim 0 x;\n\t\t\tdim1 = dim 1 x;\n\t\t\tdim2 = dim 2 x;\n\t\t\tdim3 = dim 3 x;\n\t\t\tdim4 = dim 4 x;\n\t\t\tdim5 = dim 5 x;\n\t\t\tdim6 = dim 6 x;\n\t\t\tdim7 = dim 7 x;\n\t\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\t\n\t\t\t// oops, now a nop\n\t\t\tx' = x;\n\t\n\t\t\t// lay out higher dimensions width-ways\n\t\t\tx'' \n\t\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\t\tdim0 == 7\n\t\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\t\n\t\t\t// multiply by scale factor to get kBeq\n\t\t\tx''' = x'' * (cal_max / glmax);\n\t\t}\n\t}\n\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\t[image, patch] = sortc larger [a, b];\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n\t\t\tsample = measure_draw 6 4 (to_real measure) image;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\tmode = Option \"Input LUT\" [\n\t\t\t\t\"Linearize from chart greyscale\",\n\t\t\t\t\"Fit intercept from chart greyscale\",\n\t\t\t\t\"Linear input, set brightness from chart\",\n\t\t\t\t\"Linear input\"\n\t\t\t] 0;\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = measure_sample 6 4 (to_real measure) image;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb \n\t\t\t\t= Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0\n\t\t\t\t= Matrix [0: intercepts, replicate (_camera.width + 1) 1], \n\t\t\t\t\tmode == 1\n\t\t\t\t= Matrix [[0, 0], [1, 1]]\n\t\t\t{\n\t\t\t\tintercepts = [(linreg _true_grey_Y' cam).intercept :: \n\t\t\t\t\tcam <- transpose _camera_grey'];\n\t\t\t}\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\t// plot from 0 explicitly so we see the effect of mode1 (intercept\n\t\t\t// from greyscale)\n\t\t\tlinearising_lut = Plot [$ymin => 0] _linear_lut;\n\n\t\t\t// map an image though the lineariser\n\t\t\tlinear x\n\t\t\t\t= hist_map linearising_lut.value x, mode == 0 || mode == 1\n\t\t\t\t= x;\n\n\t\t\t// map the chart measurements though the lineariser\n\t\t\t_camera' = (to_matrix @ linear @ to_image) _camera;\n\n\t\t\t// solve for RGB -> XYZ\n\t\t\t// normalise: the 2nd row is what makes Y, so divide by that to\n\t\t\t// get Y in 0-1.\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\t_full_M = transpose (_pinv * (transpose _camera' * _true_XYZ));\n\t\t\tM = _full_M / scale;\n\t\t\tscale = sum _full_M.value?1;\n\n\t\t\t// now turn the camera to LAB and calculate dE76\n\t\t\t_camera'' = (to_matrix @ \n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @ \n\t\t\t\trecomb M @ \n\t\t\t\tmultiply scale @\n\t\t\t\tto_image) _camera';\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tavg_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0 && i < len macbeth_names\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\n\t\t\t// normalise brightness ... in linear mode, we optionally don't\n\t\t\t// set the brightness from the Macbeth chart\n\t\t\tnorm x \n\t\t\t\t= x * scale, mode != 3\n\t\t\t\t= x;\n\n\t\t\t// convert RGB camera to Lab\n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tnorm @\n\t\t\t\trecomb M @\n\t\t\t\tcast_float @\n\t\t\t\tlinear) image.value;\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b = class\n\t\t\t(map_binary process a b) {\n\t\t\tprocess a b\n\t\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t\t{\n\t\t\t\t// the name of the calib object we need\n\t\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t\t// get the Calibrate_chart arg first\n\t\t\t\t[image, calib] = sortc (const (is_instanceof calib_name)) \n\t\t\t\t\t[a, b];\n\n\t\t\t\tresult = (Image @\n\t\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\t\tcalib.norm @\n\t\t\t\t\trecomb calib.M @\n\t\t\t\t\tcast_float @\n\t\t\t\t\tcalib.linear) image.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [$style => style.value] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\t!is_list_len 2 images\n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = all (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize Kernel_linear xfactor yfactor scale_im;\n\t\t\t_offset_im = resize Kernel_linear xfactor yfactor offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.4/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.4/_Object.def",
    "content": "/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0|1|2|3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \n\tjoin_sep \"|\" Image_type.colour_spaces.names];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide|VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad properties for \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"where\" ++ \"\\n\" ++ arg_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make arg type notes\n\targ_types = join_sep \"\\n\" (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"\\n\" ++ _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = join_sep \"\\n\" all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if those fail as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if that fails as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary'_function op a b\n\t= matches1?0, matches1 != []\n\t= matches2?0, op.symmetric && matches2 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0, matches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t// these should always be defined\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x = oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x = oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op = oo_unary_function (oo_unary_lookup op) this;\n\n\too_binary_table op x = [];\n\too_unary_table op = [];\n}\n"
  },
  {
    "path": "share/nip2/compat/8.4/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= Image x.value, is_Plot x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n// like to_image, but we do 1x1 pixel + x, then embed it up\n// always make an unwrapped image for speed ... this gets used by ifthenelse\n// and stuff like that\n// format can be NULL, meaning set format from x\nto_image_size width height bands format x\n\t= x, is_image x\n\t= x.value, is_Image x\n\t= im''\n{\n\t// we want x to set the target format if we don't have one, so we\n\t// can't use image_new\n\tim = im_black 1 1 bands + x;\n\tim'\n\t\t= clip2fmt format im, format != NULL\n\t\t= im;\n\tim'' = embed 1 0 0 width height im';\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && is_list_len 3 x\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\nto_int x = (int) (to_real x);\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The outermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x \n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), !is_list_len 2 parts \n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, !is_list_len 4 parts \n\t= sign * (abs ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", \n\t\tmember \".0123456789\",\n\t\tmember \"eE\", \n\t\tmember \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tsign \n\t\t= 1, ipart > 0\n\t\t= -1;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), !is_list_len 5 parts \n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t$D93 => D93_whitepoint,\n\t$D75 => D75_whitepoint,\n\t$D65 => D65_whitepoint,\n\t$D55 => D55_whitepoint,\n\t$D50 => D50_whitepoint,\n\t$A => A_whitepoint,\n\t$B => B_whitepoint,\n\t$C => C_whitepoint,\n\t$E => E_whitepoint,\n\t$D3250 => D3250_whitepoint\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, image_set_type GREY16 @ im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\t[RGB16, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l = join_sep path_separator l;\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 > 1 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n/* Return $PATH, reformatted as [[\"comp1\", \"comp2\"], [\"comp1\", \"comp2\"] ..]\n */\nsystem_search_path\n\t= [vipsbin] ++\n\t\tmap path_parse (split (equal path_sep) (expand \"$PATH\"))\n{\n\t/* On some platforms we ship vips with a few extra progs. Search\n \t * $VIPSHOME/bin first.\n\t */\n\tvipsbin = path_parse (expand \"$VIPSHOME\") ++ [\"bin\"];\n\n\tpath_sep\n\t\t= ':', expand \"$SEP\" == \"/\"\n\t\t= ';';\n}\n\n/* Search $PATH for the first occurence of name, or \"\". \n */\nsearch_for name\n\t= hits?0, hits != []\n\t= \"\"\n{\n\texe_name = name ++ expand \"$EXEEXT\";\n\tform_path p = path_absolute (p ++ [exe_name]);\n\tpaths = map form_path system_search_path;\n\thits = dropwhile (equal []) (map search paths);\n}\n\n/* Search $PATH for the first occurence of name, error on failure. \n */\nsearch_for_error name\n\t= path, path != \"\"\n\t= error (exe_name ++ \" not found on your search path. \" ++\n\t\t\"Check you have installed the program and it is on your PATH.\")\n{\n\texe_name = name ++ expand \"$EXEEXT\";\n\tpath = search_for name;\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.4/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= embed 1 0 0 w h im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black 1 1 (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\nmkim options x y b\n    = Image (image_new x y b\n        (opt $format) (opt $coding) (opt $type)\n        (opt $pixel)\n        (opt $xoffset) (opt $yoffset))\n{\n    opt = get_option options [\n        $format => Image_format.UCHAR,\n        $coding => Image_coding.NOCODING,\n        $type => Image_type.sRGB,\n        $pixel => 0,\n        $xoffset => 0,\n        $yoffset => 0\n    ];\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = im_gauss_imask_sep (radius / 3) 0.2;\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n/* Make a colour from a temperature.\n */\ncolour_from_temp T\n\t= error (_ \"T out of range\"), T < 1667 || T > 25000\n\t= Colour \"Yxy\" [50, x, y]\n{\n\t// Kim et all approximation\n\t// see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation\n\tx\n\t\t= -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 +\n\t\t\t0.8776956 * 10 ** 3 / T + 0.179910, T < 4000\n\t\t= -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 +\n\t\t\t0.2226347 * 10 ** 3 / T + 0.240390;\n\n\ty \n\t\t= -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + \n\t\t\t2.18555832 * x - 0.20219638, T < 2222\n\t\t= -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + \n\t\t\t2.09137015 * x - 0.16748867, T < 4000\n\t\t=  3.0817580 * x ** 3 - 5.87338670 * x ** 2 +\n\t\t\t3.75112997 * x - 0.37001483;\n}\n\ntemp_from_colour z\n\t= T\n{\n\tc = colour_transform_to Image_type.YXY (to_colour z);\n\tx = c.value?1;\n\ty = c.value?2;\n\n\t// McCamy's approximation, see eg. \n\t// http://en.wikipedia.org/wiki/Color_temperature#Approximation\n\n\txe = 0.332;\n\tye = 0.1858;\n\tn = (x - xe) / (y - ye);\n\tT = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33;\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.4/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 1;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" \n\t] 4;\n\n\tcontrol_selection mask im no\n\t\t= [\n\t\t\tif mask then im * 1.2 else im * 1,\n\t\t\tif mask then im * 0.8 else im * 1,\n\t\t\tif mask then 0 else im,\n\t\t\tif mask then 255 else im,\n\t\t\tif mask then im else 0,\n\t\t\tif mask then im else 255,\n\t\t\tmask\n\t\t]?no;\n\n\tRectangle = class\n        Menuaction \"_Rectangle\"\n            \"use an Arrow or Region x to define a rectangle\"\n        {\n        action x = class\n            _result {\n            _vislevel = 3;\n\n            control = _control;   \n\n            _result = control_selection mask im control\n                  {\n                \tim = x.image;\n                \tmask = Image m\n                    {\n\t\t\t\t\t\trx     \n\t\t\t\t\t\t\t= x.region_rect, is_Region x\n\t\t\t\t\t\t\t= x;\n\t\t\t\t\t\tb     = image_new im.width im.height 1 0 0 1 0 0 0;\n\t\t\t\t\t\tw     = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0;\n\t\t\t\t\t\tm     = insert_noexpand rx.nleft rx.ntop w b; \n                     }\n                   }\n            }\n        }\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = get_image a;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = get_image ((pt_list.value)?0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tSegment_item = class\n\t\tMenuaction \"_Segment\" \"break image into disjoint regions\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsegments\n\t\t\t\t= Expression \"Number of disjoint regions\" \n\t\t\t\t\t(map_unary (get_header \"n-segments\") _result);\n\n\t\t\t_result = map_unary segment x;\n\t\t}\n\t}\n\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize Kernel_linear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize Kernel_linear f1 1 b1\n\t\t\t\t\t{b1 = resize Kernel_linear 1 f2 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/8.4/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           im_gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = Image (get_image line);\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = Image (get_image (pt_l?0));\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t};\n\nMount_options _ctype _ppcm = class \n  {\n  _vislevel = 3;\n  apply = Toggle \"Apply mount options\" false;\n  ls = Expression \"Lower mount section bigger by (cm)\" 0;\n  mount_colour = Colour _ctype [0, 0, 0];\n  _los = ls.expr * _ppcm;\n  };\n\nFrame_variables comp = class\n  {\n  _vislevel = 3;\n\n  scale_factor = Expression \"scale the size of the frame by\" 1;\n\n  /* These sliders define the fraction of the frames width or height is extracted\n   * to produce each of the particular regions.\n   */\n  corner_section = Scale \"Corner section\" 0.1 1 0.5;\n  edge_section = Scale \"Edge section\" 0.1 1 0.2, comp > 0\n\t\t\t\t  = \"Only required for complex frames\";\n  middle_section = Scale \"Middle section\" 0.1 1 0.2;\n  blend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n  option = Toggle \"Use mirror of left-side to make right\" true;\n  };\n\n"
  },
  {
    "path": "share/nip2/compat/8.4/_list.def",
    "content": "/* any l: or all the elements of list l together\n *\n * any (map (equal 0) list) == true, if any element of list is zero.\n * any :: [bool] -> bool\n */\nany = foldr logical_or false;\n\n/* all l: and all the elements of list l together\n *\n * all (map (==0) list) == true, if every element of list is zero.\n * all :: [bool] -> bool\n */\nall = foldr logical_and true;\n\n/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* delete eq x l: delete the first x from l\n *\n * delete equal 'b' \"abcdb\" == \"acdb\"\n * delete :: (* -> bool) -> * -> [*] -> [*]\n */\ndelete eq a l\n\t= [], l == []\n\t= y, eq a b\n\t= b : delete eq a y\n{\n\tb:y = l;\n}\n\n/* difference eq a b: delete b from a\n *\n * difference equal \"asdf\" \"ad\" == \"sf\"\n * difference :: (* -> bool) -> [*] -> [*] -> [*]\n */\ndifference = foldl @ converse @ delete;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn x, fn a\n\t= l\n{\n\ta:x = l;\n}\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* flatten x: flatten a list of lists of things into a simple list\n *\n * flatten :: [[*]] -> [*]\n */\nflatten x\n\t= foldr flat [] x, is_list x\n\t= x\n{\n\tflat x sofar\n\t\t= foldr flat sofar x, is_list x\n\t\t= x : sofar;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st x) xs\n{\n\tx:xs = l;\n}\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn x xs\n{\n\tx:xs = l;\n}\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn x (foldr fn st xs)\n{\n\tx:xs = l;\n}\n\n/* foldr1 fn l: like foldr, but use the last element as the start value\n *\n * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= x, xs == []\n\t= fn x (foldr1 fn xs)\n{\n\tx:xs = l;\n}\n\n/* Search a list for an element, returning its index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn x\n\t\t= search xs (n + 1)\n\t\t{\n\t\t\tx:xs = l;\n\t\t}\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= x : init xs\n{\n\tx:xs = l;\n}\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* join_sep sep l: join a list with a separator\n *\n * join_sep \", \" (map print [1 .. 4]) == \"1, 2, 3, 4\"\n * join_sep :: [*] -> [[*]] -> [*]\n */\njoin_sep sep l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ sep ++ b;\n}\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= x, xs == []\n\t= last xs\n{\n\tx:xs = l;\n}\n\n/* len l: length of list l\n * (see also is_list_len and friends in predicate.def)\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta:b:x = l;\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = any (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge p l r\n\t= [], p == [] || l == [] || r == []\n\t= a : merge z x y, c\n\t= b : merge z x y\n{\n\ta:x = l;\n\tb:y = r;\n\tc:z = p;\n}\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta:x = l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scanl fn st l: apply (foldl fn r) to every initial segment of a list\n *\n * scanl add 0 [1,2,3] == [1,3,6]\n * scanl :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscanl fn st l\n\t= st, l == []\n\t= st' : scanl fn st' xs\n{\n\tx:xs = l;\n\tst' = fn st x;\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta:x = l1;\n\t\tb:y = l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/8.4/_magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate _magick.def\n\t Add 0-ary and 2-ary system\n\t Put utility funcs into a Magick class\n   11-Apr-2014 snibgo\n     Added VirtualPixelBack for cases where background is only relevant when VP=Background\n   17-Apr-2014 snibgo\n     Many small changes.\n   2-May-2014 jcupitt\n     Added Magick.version\n   30-June-2014\n   \t Put single-quotes around command exe to help win\n   1-July-2014\n     Automatically fall back to gm if we can't find convert\n   17-July-2014\n     better GM support\n\n\n   Last update: 17-July-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n\n*/\n\n/* Put these in a class to avoid filling the main namespace with IM stuff.\n */\n\nMagick = class {\n\n\t// first gm on path, or \"\"\n\tgm_path = search_for \"gm\";\n\n\t// first convert on $PATH, or \"\"\n\t// we check for the convert we ship first\n\tconvert_path \n\t\t= vips_convert, vips_convert != \"\"\n\t\t= search_for \"convert\"\n\t{\n\t\t// the convert we ship with the vips binary on some platforms, or \"\"\n\t\tvips_convert \n\t\t\t= search (path_absolute convert)\n\t\t{\n\t\t\tvipshome = path_parse (expand \"$VIPSHOME\");\n\t\t\tconvert = vipshome ++ [\"bin\", \"convert\" ++ expand \"$EXEEXT\"];\n\t\t}\n\t}\n\n\tuse_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK;\n\n\t// Are we in GM or IM mode? \n\tuse_gm \n\t\t= true, use_gm_pref && gm_path != \"\"\n\t\t= false, !use_gm_pref && convert_path != \"\"\n\t\t= false, convert_path != \"\"\n\t\t= true, gm_path != \"\"\n\t\t= error \"neither IM nor GM executable found\";\n\n\tcommand_path\n\t\t= gm_path, use_gm\n\t\t= convert_path;\n\n\t// try to get the version as eg. [6, 7, 7, 10]\n\t// GM versions are smaller, typically [1, 3, 18]\n\tversion\n\t\t= map parse_int (split (member \".-\") version_string)\n\t{\n\t\t[output] = vips_call \"system\" \n\t\t\t[\"'\" ++ command_path ++ \"' -version\"] [$log=>true];\n\t\tversion_string \n\t\t\t= (split (equal ' ') output)?1, use_gm\n\t\t\t= (split (equal ' ') output)?2;\n\t}\n\n\t// make a command-line ... args is a [str] we join with spaces\n\tcommand args \n\t\t= \"'\" ++ command_path ++ \"' \" ++ join_sep \" \" args'\n\t{\n\t\targs'\n\t\t\t= [\"convert\"] ++ args, use_gm\n\t\t\t= args;\n\t}\n\n\t// capabilities ... different versions support different features, we \n\t// turn features on and off based on these\n\n\t// would probably be better to test for caps somehow\n\thas_intensity\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\thas_channel\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\n\tsystem0 cmd = system_image0 cmd;\n\tsystem cmd x = map_unary (system_image cmd) x;\n\tsystem2 cmd x y = map_binary (system_image2 cmd) x y;\n\tsystem3 cmd x y z = map_trinary (system_image3 cmd) x y z;\n\n\tradius_widget = Scale \"Radius\" 0 100 10;\n\tsigma_widget = Scale \"Sigma\" 0.1 10 1;\n\tangle_widget = Scale \"Angle (degrees)\" (-360) 360 0;\n\ttext_widget = String \"Text to draw\" \"AaBbCcDdEe\";\n\n\tgamma_widget = Scale \"Gamma\" 0 10 1;\n\tcolors_widget = Scale \"Colors\" 1 10 3;\n\tresize_widget = Scale \"Resize (percent)\" 0 500 100;\n\tfuzz_widget = Scale \"Fuzz (percent)\" 0 100 0;\n\tblur_rad_widget = Scale \"Radius (0=auto)\" 0 100 0;\n\n\t// a colour with no enclosing quotes ... use this if we know there are\n\t// some quotes at an outer level\n\tprint_colour_nq triple\n\t\t= concat [\"#\", concat (map fmt triple)]\n\t{\n\t\tfmt x = reverse (take 2 (reverse (print_base 16 (x + 256))));\n\t}\n\n\t// we need the quotes because # is the comment character in *nix\n\tprint_colour triple = \"\\\"\" ++ print_colour_nq triple ++ \"\\\"\";\n\n\tForeground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-fill \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Foreground triple;\n\t}\n\tforeground_widget = Foreground [0, 0, 0];\n\n\tGeneralCol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = print_colour_nq triple;\n\n\t\tColour_edit space triple = this.GeneralCol triple;\n\t}\n\tgeneralcol_widget = GeneralCol [0, 0, 0];\n\n\tBackground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" false;\n\n\t\t_flag = \"-background \" ++ if isNone then \"None\" else print_colour triple;\n\n\t\tColour_edit space triple = this.Background triple;\n\t}\n\tbackground_widget = Background [255, 255, 255];\n\n\tBordercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-bordercolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Bordercol triple;\n\t}\n\tbordercol_widget = Bordercol [0, 0, 0];\n\n\tMattecol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-mattecolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Mattecol triple;\n\t}\n\tmattecol_widget = Mattecol [189, 189, 189];\n\n\t// FIXME: Undercolour, like many others, can have alpha channel.\n\t// How does user input this? With a slider?\n\tUndercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" true;\n\n\t\t_flag = if isNone then \"\" else (\"-undercolor \" ++ print_colour triple);\n\n\t\tColour_edit space triple = this.Undercol triple;\n\t}\n\tundercol_widget = Undercol [0, 0, 0];\n\n\tchangeCol_widget = class {\n\t\t_vislevel = 3;\n\n\t\tcolour = GeneralCol [0, 0, 0];\n\t\tfuzz = fuzz_widget;\n\t\tnonMatch = Toggle \"change non-matching colours\" false;\n\t}\n\n\tAlpha alpha = class\n\t\tOption_string \"Alpha\" [\n\t\t\t\"On\", \n\t\t\t\"Off\", \n\t\t\t\"Set\", \n\t\t\t\"Opaque\", \n\t\t\t\"Transparent\", \n\t\t\t\"Extract\", \n\t\t\t\"Copy\", \n\t\t\t\"Shape\", \n\t\t\t\"Remove\", \n\t\t\t\"Background\"\n\t\t] alpha {\n\n\t\t_flag = \"-alpha \" ++ alpha;\n\n\t\tOption_edit caption labels value = this.Alpha labels?value;\n\t}\n\talpha_widget = Alpha \"On\";\n\n\tAntialias value = class\n\t\tToggle \"Antialias\" value {\n\n\t\t_flag\n\t\t\t= \"-antialias\", value\n\t\t\t= \"+antialias\";\n\n\t\tToggle_edit caption value = this.Antialias value;\n\t}\n\tantialias_widget = Antialias true;\n\n\tBuiltin builtin = class\n\t\tOption_string \"Builtin\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"rose:\",\n\t\t\t\"logo:\",\n\t\t\t\"wizard:\",\n\t\t\t\"granite:\",\n\t\t\t\"netscape:\"\n\t\t] builtin {\n\n\t\t_flag = builtin;\n\n\t\tOption_edit caption labels value = this.Builtin labels?value;\n\t}\n\tbuiltin_widget = Builtin \"rose:\";\n\n\n\tchannels_widget = class {\n\t\t// FIXME? Can we grey-out alpha when we have no alpha channel,\n\t\t//        show CMY(K) instead of RGB(K) etc?\n\t\t// Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA.\n\t\tChanR valueR = class\n\t\t\tToggle \"Red\" valueR {\n\n\t\t\t_flag\n\t\t\t\t= \"R\", valueR\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueR = this.ChanR valueR;\n\t\t}\n\t\tchannelR = ChanR true;\n\n\t\tChanG valueG = class\n\t\t\tToggle \"Green\" valueG {\n\n\t\t\t_flag\n\t\t\t\t= \"G\", valueG\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueG = this.ChanG valueG;\n\t\t}\n\t\tchannelG = ChanG true;\n\n\t\tChanB valueB = class\n\t\t\tToggle \"Blue\" valueB {\n\n\t\t\t_flag\n\t\t\t\t= \"B\", valueB\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueB = this.ChanB valueB;\n\t\t}\n\t\tchannelB = ChanB true;\n\n\t\tChanK valueK = class\n\t\t\tToggle \"Black\" valueK {\n\n\t\t\t_flag\n\t\t\t\t= \"K\", valueK\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueK = this.ChanK valueK;\n\t\t}\n\t\tchannelK = ChanK true;\n\n\t\tChanA valueA = class\n\t\t\tToggle \"Alpha\" valueA {\n\n\t\t\t_flag\n\t\t\t\t= \"A\", valueA\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueA = this.ChanA valueA;\n\t\t}\n\t\tchannelA = ChanA false;\n\n\t\tChanSy valueSy = class\n\t\t\tToggle \"Sync\" valueSy {\n\n\t\t\t_flag\n\t\t\t\t= \",sync\", valueSy\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueSy = this.ChanSy valueSy;\n\t\t}\n\t\tchannelSy = ChanSy true;\n\n\t\t_rgbka = concat [channelR._flag,\n\t\t\t\tchannelG._flag,\n\t\t\t\tchannelB._flag,\n\t\t\t\tchannelK._flag,\n\t\t\t\tchannelA._flag\n\t\t\t];\n\n\t\t_flag\n\t\t\t= \"\", _rgbka == \"\" || !has_channel\n\t\t\t= concat [ \"-channel \",\n\t\t\t\t_rgbka,\n\t\t\t\tchannelSy._flag \n\t\t\t\t];\n\t}\n\n\tch_widget = channels_widget;\n\n\tColorspace colsp = class\n\t\tOption_string \"Colorspace\" [\n\t\t\t\"CIELab\",\n\t\t\t\"CMY\",\n\t\t\t\"CMYK\",\n\t\t\t\"Gray\",\n\t\t\t\"HCL\",\n\t\t\t\"HCLp\",\n\t\t\t\"HSB\",\n\t\t\t\"HSI\",\n\t\t\t\"HSL\",\n\t\t\t\"HSV\",\n\t\t\t\"HWB\",\n\t\t\t\"Lab\",\n\t\t\t\"LCH\",\n\t\t\t\"LCHab\",\n\t\t\t\"LCHuv\",\n\t\t\t\"LMS\",\n\t\t\t\"Log\",\n\t\t\t\"Luv\",\n\t\t\t\"OHTA\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601YCbCr\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709YCbCr\",\n\t\t\t\"RGB\",\n\t\t\t\"scRGB\",\n\t\t\t\"sRGB\",\n\t\t\t\"Transparent\",\n\t\t\t\"XYZ\",\n\t\t\t\"YCbCr\",\n\t\t\t\"YDbDr\",\n\t\t\t\"YCC\",\n\t\t\t\"YIQ\",\n\t\t\t\"YPbPr\",\n\t\t\t\"YUV\"\n\t\t] colsp {\n\n\t\t_flag = colsp;\n\n\t\tOption_edit caption labels value = this.Colorspace labels?value;\n\t}\n\tcolorspace_widget = Colorspace \"sRGB\";\n\n\tCompose comp = class\n\t\tOption_string \"Compose method\" [\n\t\t\t\"Atop\", \n\t\t\t\"Blend\", \n\t\t\t\"Blur\", \n\t\t\t\"Bumpmap\", \n\t\t\t\"ChangeMask\", \n\t\t\t\"Clear\", \n\t\t\t\"ColorBurn\", \n\t\t\t\"ColorDodge\", \n\t\t\t\"Colorize\", \n\t\t\t\"CopyBlack\", \n\t\t\t\"CopyBlue\", \n\t\t\t\"CopyCyan\", \n\t\t\t\"CopyGreen\", \n\t\t\t\"Copy\", \n\t\t\t\"CopyMagenta\", \n\t\t\t\"CopyOpacity\", \n\t\t\t\"CopyRed\", \n\t\t\t\"CopyYellow\", \n\t\t\t\"Darken\", \n\t\t\t\"DarkenIntensity\", \n\t\t\t\"DivideDst\", \n\t\t\t\"DivideSrc\", \n\t\t\t\"Dst\", \n\t\t\t\"Difference\", \n\t\t\t\"Displace\", \n\t\t\t\"Dissolve\", \n\t\t\t\"Distort\", \n\t\t\t\"DstAtop\", \n\t\t\t\"DstIn\", \n\t\t\t\"DstOut\", \n\t\t\t\"DstOver\", \n\t\t\t\"Exclusion\", \n\t\t\t\"HardLight\", \n\t\t\t\"Hue\", \n\t\t\t\"In\", \n\t\t\t\"Lighten\", \n\t\t\t\"LightenIntensity\", \n\t\t\t\"LinearBurn\", \n\t\t\t\"LinearDodge\", \n\t\t\t\"LinearLight\", \n\t\t\t\"Luminize\", \n\t\t\t\"Mathematics\", \n\t\t\t\"MinusDst\", \n\t\t\t\"MinusSrc\", \n\t\t\t\"Modulate\", \n\t\t\t\"ModulusAdd\", \n\t\t\t\"ModulusSubtract\", \n\t\t\t\"Multiply\", \n\t\t\t\"None\", \n\t\t\t\"Out\", \n\t\t\t\"Overlay\", \n\t\t\t\"Over\", \n\t\t\t\"PegtopLight\", \n\t\t\t\"PinLight\", \n\t\t\t\"Plus\", \n\t\t\t\"Replace\", \n\t\t\t\"Saturate\", \n\t\t\t\"Screen\", \n\t\t\t\"SoftLight\", \n\t\t\t\"Src\", \n\t\t\t\"SrcAtop\", \n\t\t\t\"SrcIn\", \n\t\t\t\"SrcOut\", \n\t\t\t\"SrcOver\", \n\t\t\t\"VividLight\", \n\t\t\t\"Xor\"\n\t\t] comp {\n\n\t\t_flag = \"-compose \" ++ comp;\n\n\t\tOption_edit caption labels value = this.Compose labels?value;\n\t}\n\tcompose_widget = Compose \"Over\";\n\t// FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string.\n\n\t// FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack\n\n\tcoordinate_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\n\t\t_flag = concat [print x.expr, \",\", print y.expr];\n\t};\n\n\tDistort distort = class\n\t\tOption_string \"Distort\" [\n\t\t\t\"Affine\",\n\t\t\t\"AffineProjection\",\n\t\t\t\"ScaleRotateTranslate\",\n\t\t\t\"SRT\",\n\t\t\t\"Perspective\",\n\t\t\t\"PerspectiveProjection\",\n\t\t\t\"BilinearForward\",\n\t\t\t\"BilinearReverse\",\n\t\t\t\"Polynomial\",\n\t\t\t\"Arc\",\n\t\t\t\"Polar\",\n\t\t\t\"DePolar\",\n\t\t\t\"Barrel\",\n\t\t\t\"BarrelInverse\",\n\t\t\t\"Shepards\",\n\t\t\t\"Resize\"\n\t\t] distort {\n\n\t\t_flag = distort;\n\n\t\tOption_edit caption labels value = this.Distort labels?value;\n\t}\n\tdistort_widget = Distort \"SRT\";\n\n\tDither dither = class\n\t\tOption_string \"Dither\" [\n\t\t\t\"None\",\n\t\t\t\"FloydSteinberg\",\n\t\t\t\"Riemersma\"\n\t\t] dither {\n\n\t\t_flag = \"-dither \" ++ dither;\n\n\t\tOption_edit caption labels value = this.Dither labels?value;\n\t}\n\tdither_widget = Dither \"FloydSteinberg\";\n\n\tEvaluate eval = class\n\t\tOption_string \"Evaluate operation\" [\n\t\t\t\"Abs\",\n\t\t\t\"Add\",\n\t\t\t\"AddModulus\",\n\t\t\t\"And\",\n\t\t\t\"Cos\",\n\t\t\t\"Cosine\",\n\t\t\t\"Divide\",\n\t\t\t\"Exp\",\n\t\t\t\"Exponential\",\n\t\t\t\"GaussianNoise\",\n\t\t\t\"ImpulseNoise\",\n\t\t\t\"LaplacianNoise\",\n\t\t\t\"LeftShift\",\n\t\t\t\"Log\",\n\t\t\t\"Max\",\n\t\t\t\"Mean\",\n\t\t\t\"Median\",\n\t\t\t\"Min\",\n\t\t\t\"MultiplicativeNoise\",\n\t\t\t\"Multiply\",\n\t\t\t\"Or\",\n\t\t\t\"PoissonNoise\",\n\t\t\t\"Pow\",\n\t\t\t\"RightShift\",\n\t\t\t\"Set\",\n\t\t\t\"Sin\",\n\t\t\t\"Sine\",\n\t\t\t\"Subtract\",\n\t\t\t\"Sum\",\n\t\t\t\"Threshold\",\n\t\t\t\"ThresholdBlack\",\n\t\t\t\"ThresholdWhite\",\n\t\t\t\"UniformNoise\",\n\t\t\t\"Xor\"\n\t\t] eval {\n\n\t\t_flag = \"-evaluate \" ++ eval;\n\n\t\tOption_edit caption labels value = this.Evaluate labels?value;\n\t}\n\tevaluate_widget = Evaluate \"Add\";\n\n\tFilter filt = class\n\t\tOption_string \"Filter\" [\n\t\t\t\"default\",\n\t\t\t\"Bartlett\",\n\t\t\t\"Blackman\",\n\t\t\t\"Bohman\",\n\t\t\t\"Box\",\n\t\t\t\"Catrom\",\n\t\t\t\"Cosine\",\n\t\t\t\"Cubic\",\n\t\t\t\"Gaussian\",\n\t\t\t\"Hamming\",\n\t\t\t\"Hann\",\n\t\t\t\"Hermite\",\n\t\t\t\"Jinc\",\n\t\t\t\"Kaiser\",\n\t\t\t\"Lagrange\",\n\t\t\t\"Lanczos\",\n\t\t\t\"Lanczos2\",\n\t\t\t\"Lanczos2Sharp\",\n\t\t\t\"LanczosRadius\",\n\t\t\t\"LanczosSharp\",\n\t\t\t\"Mitchell\",\n\t\t\t\"Parzen\",\n\t\t\t\"Point\",\n\t\t\t\"Quadratic\",\n\t\t\t\"Robidoux\",\n\t\t\t\"RobidouxSharp\",\n\t\t\t\"Sinc\",\n\t\t\t\"SincFast\",\n\t\t\t\"Spline\",\n\t\t\t\"Triangle\",\n\t\t\t\"Welch\"\n\t\t] filt {\n\n\t\t_flag = if filt == \"default\" then \"\" else \"-filter \" ++ filt;\n\n\t\tOption_edit caption labels value = this.Filter labels?value;\n\t}\n\tfilter_widget = Filter \"default\";\n\n\tFunction func = class\n\t\tOption_string \"Function\" [\n\t\t\t\"Polynomial\",\n\t\t\t\"Sinusoid\",\n\t\t\t\"Arcsin\",\n\t\t\t\"Arctan\"\n\t\t] func {\n\n\t\t_flag = func;\n\n\t\tOption_edit caption labels value = this.Function labels?value;\n\t}\n\tfunction_widget = Function \"Polynomial\";\n\n//  \"Polynomial (a[n], a[n-1], ... a[1], a[0])\",\n//  \"Sinusoid (freq, phase, amp, bias)\",\n//  \"Arcsin (width, centre, range, bias)\",\n//  \"Arctan (slope, centre, range, bias)\"\n\n\tGravity gravity = class\n\t\tOption_string \"Gravity\" [\n\t\t\t\"None\",\n\t\t\t\"Center\",\n\t\t\t\"East\",\n\t\t\t\"Forget\",\n\t\t\t\"NorthEast\",\n\t\t\t\"North\",\n\t\t\t\"NorthWest\",\n\t\t\t\"SouthEast\",\n\t\t\t\"South\",\n\t\t\t\"SouthWest\",\n\t\t\t\"West\",\n\t\t\t\"Static\"\n\t\t] gravity {\n\n\t\t_flag = \"-gravity \" ++ gravity;\n\n\t\tOption_edit caption labels value = this.Gravity labels?value;\n\t}\n\tgravity_widget = Gravity \"Center\";\n\n\tImageType imagetype = class\n\t\tOption_string \"Image type\" [\n\t\t\t\"Bilevel\",\n\t\t\t\"ColorSeparation\",\n\t\t\t\"ColorSeparationAlpha\",\n\t\t\t\"ColorSeparationMatte\",\n\t\t\t\"Grayscale\",\n\t\t\t\"GrayscaleAlpha\",\n\t\t\t\"GrayscaleMatte\",\n\t\t\t\"Optimize\",\n\t\t\t\"Palette\",\n\t\t\t\"PaletteBilevelAlpha\",\n\t\t\t\"PaletteBilevelMatte\",\n\t\t\t\"PaletteAlpha\",\n\t\t\t\"PaletteMatte\",\n\t\t\t\"TrueColorAlpha\",\n\t\t\t\"TrueColorMatte\",\n\t\t\t\"TrueColor\"\n\t\t] imagetype {\n\n\t\t_flag = \"-type \" ++ imagetype;\n\n\t\tOption_edit caption labels value = this.ImageType labels?value;\n\t}\n\timagetype_widget = ImageType \"TrueColor\";\n\n\tIntensity intensity = class\n\t\tOption_string \"Intensity (gray conversion)\" [\n\t\t\t\"Average\",\n\t\t\t\"Brightness\",\n\t\t\t\"Lightness\",\n\t\t\t\"MS\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601Luminance\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709Luminance\",\n\t\t\t\"RMS\"\n\t\t] intensity {\n\n\t\t_flag \n\t\t\t= \"-intensity \" ++ intensity, has_intensity\n\t\t\t= \"\";\n\n\t\tOption_edit caption labels value = this.Intensity labels?value;\n\t}\n\tintensity_widget = Intensity \"Rec709Luminance\";\n\n\tInterpolate interp = class\n\t\tOption_string \"Interpolate\" [\n\t\t\t\"default\",\n\t\t\t\"Average\",\n\t\t\t\"Average4\",\n\t\t\t\"Average9\",\n\t\t\t\"Average16\",\n\t\t\t\"Background\",\n\t\t\t\"Bilinear\",\n\t\t\t\"Blend\",\n\t\t\t\"Integer\",\n\t\t\t\"Mesh\",\n\t\t\t\"Nearest\",\n\t\t\t\"NearestNeighbor\",\n\t\t\t\"Spline\"\n\t\t] interp {\n\n\t\t_flag = if interp == \"default\" then \"\" else \"-interpolate \" ++ interp;\n\n\t\tOption_edit caption labels value = this.Interpolate labels?value;\n\t}\n\tinterpolate_widget = Interpolate \"default\";\n\n\tKernel kernel = class\n\t\tOption_string \"Kernel\" [\n\t\t\t\"Unity\",\n\t\t\t\"Gaussian\",\n\t\t\t\"DoG\",\n\t\t\t\"LoG\",\n\t\t\t\"Blur\",\n\t\t\t\"Comet\",\n\t\t\t\"Binomial\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Sobel\",\n\t\t\t\"FreiChen\",\n\t\t\t\"Roberts\",\n\t\t\t\"Prewitt\",\n\t\t\t\"Compass\",\n\t\t\t\"Kirsch\",\n\t\t\t\"Diamond\",\n\t\t\t\"Square\",\n\t\t\t\"Rectangle\",\n\t\t\t\"Disk\",\n\t\t\t\"Octagon\",\n\t\t\t\"Plus\",\n\t\t\t\"Cross\",\n\t\t\t\"Ring\",\n\t\t\t\"Peaks\",\n\t\t\t\"Edges\",\n\t\t\t\"Corners\",\n\t\t\t\"Diagonals\",\n\t\t\t\"LineEnds\",\n\t\t\t\"LineJunctions\",\n\t\t\t\"Ridges\",\n\t\t\t\"ConvexHull\",\n\t\t\t\"ThinSe\",\n\t\t\t\"Skeleton\",\n\t\t\t\"Chebyshev\",\n\t\t\t\"Manhattan\",\n\t\t\t\"Octagonal\",\n\t\t\t\"Euclidean\"\n\t\t\t// FIXME: custom kernel\n\t\t] kernel {\n\n\t\t_flag = kernel;\n\n\t\tOption_edit caption labels value = this.Kernel labels?value;\n\t}\n\tkernel_widget = Kernel \"Unity\";\n\n\tModColSp msp = class\n\t\tOption_string \"modulate colorspace\" [\n\t\t\t\"HCL\", \n\t\t\t\"HCLp\", \n\t\t\t\"HSB\", \n\t\t\t\"HSI\", \n\t\t\t\"HSL\", \n\t\t\t\"HSV\", \n\t\t\t\"HWB\", \n\t\t\t\"LCH\"\n\t\t] msp {\n\n\t\t_flag = \"-set option:modulate:colorspace \" ++ msp;\n\n\t\tOption_edit caption labels value = this.ModColSp labels?value;\n\t}\n\tModColSp_widget = ModColSp \"HSL\";\n\n\tMorphMeth morph = class\n\t\tOption_string \"Method\" [\n\t\t\t\"Correlate\",\n\t\t\t\"Convolve\",\n\t\t\t\"Dilate\",\n\t\t\t\"Erode\",\n\t\t\t\"Close\",\n\t\t\t\"Open\",\n\t\t\t\"DilateIntensity\",\n\t\t\t\"ErodeIntensity\",\n\t\t\t\"CloseIntensity\",\n\t\t\t\"OpenIntensity\",\n\t\t\t\"Smooth\",\n\t\t\t\"EdgeOut\",\n\t\t\t\"EdgeIn\",\n\t\t\t\"Edge\",\n\t\t\t\"TopHat\",\n\t\t\t\"BottomHat\",\n\t\t\t\"HitAndMiss\",\n\t\t\t\"Thinning\",\n\t\t\t\"Thicken\",\n\t\t\t\"Distance\",\n\t\t\t\"IterativeDistance\"\n\t\t] morph {\n\n\t\t_flag = morph;\n\n\t\tOption_edit caption labels value = this.MorphMeth labels?value;\n\t}\n\tmorphmeth_widget = MorphMeth \"Dilate\";\n\n\tNoise noise = class\n\t\tOption_string \"Noise\" [\n\t\t\t\"Gaussian\",\n\t\t\t\"Impulse\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Multiplicative\",\n\t\t\t\"Poisson\",\n\t\t\t\"Random\",\n\t\t\t\"Uniform\"\n\t\t] noise {\n\n\t\t_flag = \"+noise \" ++ noise;\n\n\t\tOption_edit caption labels value = this.Noise labels?value;\n\t}\n\tnoise_widget = Noise \"Gaussian\";\n\n\tPattern pattern = class\n\t\tOption_string \"Noise\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"bricks\",\n\t\t\t\"checkerboard\",\n\t\t\t\"circles\",\n\t\t\t\"crosshatch\",\n\t\t\t\"crosshatch30\",\n\t\t\t\"crosshatch45\",\n\t\t\t\"gray0\",\n\t\t\t\"gray5\",\n\t\t\t\"gray10\",\n\t\t\t\"gray15\",\n\t\t\t\"gray20\",\n\t\t\t\"gray25\",\n\t\t\t\"gray30\",\n\t\t\t\"gray35\",\n\t\t\t\"gray40\",\n\t\t\t\"gray45\",\n\t\t\t\"gray50\",\n\t\t\t\"gray55\",\n\t\t\t\"gray60\",\n\t\t\t\"gray65\",\n\t\t\t\"gray70\",\n\t\t\t\"gray75\",\n\t\t\t\"gray80\",\n\t\t\t\"gray85\",\n\t\t\t\"gray90\",\n\t\t\t\"gray95\",\n\t\t\t\"gray100\",\n\t\t\t\"hexagons\",\n\t\t\t\"horizontal\",\n\t\t\t\"horizontal2\",\n\t\t\t\"horizontal3\",\n\t\t\t\"horizontalsaw\",\n\t\t\t\"hs_bdiagonal\",\n\t\t\t\"hs_cross\",\n\t\t\t\"hs_diagcross\",\n\t\t\t\"hs_fdiagonal\",\n\t\t\t\"hs_horizontal\",\n\t\t\t\"hs_vertical\",\n\t\t\t\"left30\",\n\t\t\t\"left45\",\n\t\t\t\"leftshingle\",\n\t\t\t\"octagons\",\n\t\t\t\"right30\",\n\t\t\t\"right45\",\n\t\t\t\"rightshingle\",\n\t\t\t\"smallfishscales\",\n\t\t\t\"vertical\",\n\t\t\t\"vertical2\",\n\t\t\t\"vertical3\",\n\t\t\t\"verticalbricks\",\n\t\t\t\"verticalleftshingle\",\n\t\t\t\"verticalrightshingle\",\n\t\t\t\"verticalsaw\"\n\t\t] pattern {\n\n\t\t_flag = \"pattern:\" ++ pattern;\n\n\t\tOption_edit caption labels value = this.Pattern labels?value;\n\t}\n\tpattern_widget = Pattern \"bricks\";\n\n\tResizeType resizet = class\n\t\tOption_string \"Resize type\" [\n\t\t\t\"resize\", \n\t\t\t\"scale\",\n\t\t\t\"sample\",\n\t\t\t\"adaptive-resize\"\n\t\t] resizet {\n\n\t\t_flag = resizet;\n\n\t\tOption_edit caption labels value = this.ResizeType labels?value;\n\t}\n\tResizeType_widget = ResizeType \"resize\";\n\n\tSize_widget = class {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width (pixels)\" 64;\n\t\theight = Expression \"Height (pixels)\" 64;\n\n\t\t_flag = \"-size \" ++\n\t\t\tprint width.expr ++ \"x\" ++ print height.expr;\n\n\t};\n\n\tStatType statt = class\n\t\tOption_string \"Statistic type\" [\n\t\t\t\"Gradient\", \n\t\t\t\"Maximum\", \n\t\t\t\"Mean\", \n\t\t\t\"Median\", \n\t\t\t\"Minimum\", \n\t\t\t\"Mode\", \n\t\t\t\"Nonpeak\", \n\t\t\t\"StandardDeviation\"\n\t\t] statt {\n\n\t\t_flag = statt;\n\n\t\tOption_edit caption labels value = this.StatType labels?value;\n\t}\n\tStatType_widget = StatType \"Mean\";\n\n\tVirtualPixel vp = class\n\t\tOption_string \"Virtual pixel\" [\n\t\t\t\"Background\", \n\t\t\t\"Black\", \n\t\t\t\"CheckerTile\", \n\t\t\t\"Dither\", \n\t\t\t\"Edge\", \n\t\t\t\"Gray\", \n\t\t\t\"HorizontalTile\", \n\t\t\t\"HorizontalTileEdge\", \n\t\t\t\"Mirror\", \n\t\t\t\"None\",\n\t\t\t\"Random\",\n\t\t\t\"Tile\",\n\t\t\t\"Transparent\",\n\t\t\t\"VerticalTile\",\n\t\t\t\"VerticalTileEdge\",\n\t\t\t\"White\"\n\t\t] vp {\n\n\t\t_flag = \"-virtual-pixel \" ++ vp;\n\n\t\t_isBackground = (vp == \"Background\");\n\n\t\tOption_edit caption labels value = this.VirtualPixel labels?value;\n\t}\n\tVirtualPixel_widget = VirtualPixel \"Edge\";\n\n\tVirtualPixelBack_widget = class {\n\t\tvirtpix = Magick.VirtualPixel_widget;\n\t\tbackground = Magick.background_widget;\n\t\t_flag = (if virtpix._isBackground then (background._flag ++ \" \") else \"\")\n\t\t\t++ virtpix._flag;\n\t}\n\n\tGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tAnnotGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print shearX.expr, \"x\", print shearY.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tOffsetGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag = concat [format hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tWhxyGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFrameGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\toutbev = Expression \"Outer bevel thickness\" 0;\n\t\tinbev = Expression \"Inner bevel thickness\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat outbev, format inbev]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFont_widget = class {\n\t\t_vislevel = 3;\n\n\t\tfamily = Option_string \"Family\" [\n\t\t\t\"Arial\",\n\t\t\t\"ArialBlack\",\n\t\t\t\"AvantGarde\",\n\t\t\t\"BitstreamCharter\",\n\t\t\t\"Bookman\",\n\t\t\t\"CenturySchoolbook\",\n\t\t\t\"ComicSansMS\",\n\t\t\t\"Courier\",\n\t\t\t\"CourierNew\",\n\t\t\t\"DejaVuSans\",\n\t\t\t\"DejaVuSansMono\",\n\t\t\t\"DejaVuSerif\",\n\t\t\t\"Dingbats\",\n\t\t\t\"FreeMono\",\n\t\t\t\"FreeSans\",\n\t\t\t\"FreeSerif\",\n\t\t\t\"Garuda\",\n\t\t\t\"Georgia\",\n\t\t\t\"Helvetica\",\n\t\t\t\"HelveticaNarrow\",\n\t\t\t\"Impact\",\n\t\t\t\"LiberationMono\",\n\t\t\t\"LiberationSans\",\n\t\t\t\"LiberationSerif\",\n\t\t\t\"NewCenturySchlbk\",\n\t\t\t\"Palatino\",\n\t\t\t\"Purisa\",\n\t\t\t\"Symbol\",\n\t\t\t\"Times\",\n\t\t\t\"TimesNewRoman\",\n\t\t\t\"Ubuntu\",\n\t\t\t\"Verdana\",\n\t\t\t\"Webdings\"\n\t\t] \"Arial\";\n\t\tstyle = Option_string \"Style\" [\n\t\t\t\"Any\", \"Italic\", \"Normal\", \"Oblique\"\n\t\t] \"Normal\";\n\t\tweight = Scale \"Weight\" 1 800 400;\n\t\tsize = Scale \"Point size\" 1 100 12;\n\t\tstretch = Option_string \"Stretch\" [\n\t\t\t\"Any\", \"Condensed\", \"Expanded\", \"ExtraCondensed\", \"ExtraExpanded\", \n\t\t\t\"Normal\", \"SemiCondensed\", \"SemiExpanded\", \"UltraCondensed\", \n\t\t\t\"UltraExpanded\"\n\t\t] \"Normal\";\n\n\t\t_flag = join_sep \" \" [\n\t\t\t\t\"-family\", family.item,\n\t\t\t\t\"-weight\", print weight.value,\n\t\t\t\t\"-pointsize\", print size.value,\n\t\t\t\t\"-style\", style.item,\n\t\t\t\t\"-stretch\", stretch.item];\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.4/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = any (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && all (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* Test list length ... quicker than len x == n for large lists.\n */\nis_list_len n x\n\t= true, x == [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len (n - 1) (tl x);\n\nis_list_len_more n x\n\t= true, x != [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len_more (n - 1) (tl x);\n\nis_list_len_more_equal n x\n\t= true, n == 0\n\t= false, x == [] \n\t= is_list_len_more_equal (n - 1) (tl x);\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, all (map is_obj l)\n\t= true, all (map is_list l) &&\n\t\tall (map (not @ is_obj) l) &&\n\t\tall (map is_rectangular l) &&\n\t\tis_list_len_more 0 l &&\n\t\tall (map (is_list_len (len (hd l))) (tl l))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && is_list_len (len (hd l)) l;\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_NULL x = is_instanceof \"NULL\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Plot x = is_instanceof \"Plot\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && all (map xy l)\n{\n\txy l = is_real_list l && is_list_len 2 l;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && any (map is_Group l)\n\t= any (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= oo_unary_function get_type_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_type\")\n{\n\tget_type_op = Operator \"get_type\" get_type \n\t\tOperator_type.COMPOUND false;\n\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\t// can have alpha, hence we let bands be one more than you might think\n\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.GREY16, type == Image_type.GREY16 && is_bands 1\n\t\t= Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && \n\t\t\t(width == 1 || height == 1)\n\t\t= Image_type.B_W, is_bands 1 \n\t\t= Image_type.CMYK, type == Image_type.CMYK && is_bands 4\n\t\t= type, is_colorimetric && is_bands 3\n\t\t= Image_type.sRGB, !is_colorimetric && is_bands 3\n\t\t= Image_type.MULTIBAND, !is_colorimetric && !is_bands 3\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\n\t\t// is bands n, with an optional alpha (ie. can be n + 1 too)\n\t\tis_bands n = bands == n || bands == n + 1;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= oo_unary_function get_format_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_format\")\n{\n\tget_format_op = Operator \"get_format\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= oo_unary_function get_bits_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bits\")\n{\n\tget_bits_op = Operator \"get_bits\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= oo_unary_function get_bands_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bands\")\n{\n\tget_bands_op = Operator \"get_bands\" get_bands \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= oo_unary_function get_coding_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_coding\")\n{\n\tget_coding_op = Operator \"get_coding\" get_coding \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= oo_unary_function get_xres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xres\")\n{\n\tget_xres_op = Operator \"get_xres\" get_xres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= oo_unary_function get_yres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yres\")\n{\n\tget_yres_op = Operator \"get_yres\" get_yres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= oo_unary_function get_xoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xoffset\")\n{\n\tget_xoffset_op = Operator \"get_xoffset\" get_xoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= oo_unary_function get_yoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yoffset\")\n{\n\tget_yoffset_op = Operator \"get_yoffset\" get_yoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= oo_unary_function get_image_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_image\")\n{\n\tget_image_op = Operator \"get_image\" get_image \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= oo_unary_function get_number_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_number\")\n{\n\tget_number_op = Operator \"get_number\" get_number \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= oo_unary_function get_real_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_real\")\n{\n\tget_real_op = Operator \"get_real\" get_real \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= oo_unary_function get_width_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_width\")\n{\n\tget_width_op = Operator \"get_width\" get_width \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= oo_unary_function get_height_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_height\")\n{\n\tget_height_op = Operator \"get_height\" get_height \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= oo_unary_function get_left_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_left\")\n{\n\tget_left_op = Operator \"get_left\" get_left \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= oo_unary_function get_top_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_top\")\n{\n\tget_top_op = Operator \"get_top\" get_top \n\t\tOperator_type.COMPOUND false;\n}\n\n// like has/get member, but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.4/_stdenv.def",
    "content": "/* optional args to functions\n */\n\nget_option options defaults f\n\t= error (_ \"unknown parameter \" ++ f), hits == []\n\t= hits?0\n{\n\thits = [v :: [n, v] <- options ++ defaults; n == f];\n}\n\n/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\nidivide a b = (int) ((int) a / (int) b);\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\n// 'difference' is defined in _list\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the function we call for \"a -> v\" expressions\nmksvpair s v\n\t= [s, v], is_string s\n\t= error \"not str on lhs of ->\";\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error (\"unimplemented vector operation: \" ++ op_name)\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n// make a name value pair\nmknvpair n v\n\t= [n, v], is_string n\n\t= error \"not [char] on LHS of =>\";\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined, has_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nbandand x\n\t= oo_unary_function bandand_op x, is_class x\n\t= foldr1 bitwise_and (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandand\")\n{\n\tbandand_op = Operator \"bandand\" bandand Operator_type.COMPOUND_REWRAP false;\n}\n\nbandor x\n\t= oo_unary_function bandor_op x, is_class x\n\t= foldr1 bitwise_or (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandor\")\n{\n\tbandor_op = Operator \"bandor\" bandor Operator_type.COMPOUND_REWRAP false;\n}\n\nsum x\n\t= oo_unary_function sum_op x, is_class x\n\t= im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x\n\t= sum_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"sum\")\n{\n\tsum_op = Operator \"sum\" sum Operator_type.COMPOUND false;\n\n\t// add elements in a nested-list thing\n\tsum_list l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nproduct x\n\t= oo_unary_function product_op x, is_class x\n\t= product_list x, is_list x \n\t// (product image) doesn't make much sense :(\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"product\")\n{\n\tproduct_op = Operator \"product\" product Operator_type.COMPOUND false;\n\n\tproduct_list l\n\t\t= foldr prod 1 l\n\t{\n\t\tprod x total\n\t\t\t= total * product x, is_list x\n\t\t\t= total * x;\n\t}\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\nskew x\n\t= oo_unary_function skew_op x, is_class x\n\t= sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x \n\t= sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"skew\")\n{\n\tskew_op = Operator \"skew\" skew Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN \n\t\t= w * h * b, is_image x'\n\t\t= len x';\n}\n\nkurtosis x\n\t= oo_unary_function kurtosis_op x, is_class x\n\t= sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x \n\t= sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"kurtosis\")\n{\n\tkurtosis_op = Operator \"kurtosis\" kurtosis Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN\n\t\t= len x', is_list x';\n\t\t= w * h * b;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image_hist x, is_image x && \n\t\t(fmt == Image_format.UCHAR || fmt == Image_format.USHORT)\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tfmt = get_format x;\n\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean, for any image type\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n\n\t// image mean for 8 and 16-bit unsigned images\n\t// we can use a histogram, yay, and save a pass through the image\n\tmeanze_image_hist i\n\t\t= sum / N\n\t{\n\t\t// histogram, knock out zeros\n\t\thist = hist_find i;\n\t\tblack = image_new 1 1 (get_bands hist) \n\t\t\t(get_format hist) (get_coding hist) (get_type hist) 0 0 0;\n\t\thistze = insert 0 0 black hist;\n\n\t\t// matching identity\n\t\tiden\n\t\t\t= im_identity_ushort (get_bands hist) (get_width hist),\n\t\t\t\t(get_width hist) > 256\n\t\t\t= im_identity (get_bands hist);\n\n\t\t// number of non-zero pixels\n\t\tN = mean histze * 256;\n\n\t\t// sum of pixels\n\t\tsum = mean (hist * iden) * 256;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_tile_cache_random x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (\\row [row?x']) obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\" ++ \": \" ++\n\t\tjoin_sep \", \" (map print [cond, in1, in2]))\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x \n\t\t\t= to_image_size target_width target_height \n\t\t\t\ttarget_bands target_format x;\n\n\t\t[then_image, else_image] = map to_image [then_part, else_part];\n\n\t\tblend_result_image = image_set_type target_type \n\t\t\t(im_blend cond then_image else_image);\n\t}\n}\n\n// do big first: we want to keep big's class, if possible\n// eg. big is a Plot, small is a 1x1 Image\ninsert x y small big\n\t= oo_binary'_function insert_op small big, is_class big\n\t= oo_binary_function insert_op small big, is_class small\n\t= im_insert big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ndecode im\n\t= oo_unary_function decode_op im, is_class im\n\t= decode_im im, is_image im\n\t= error (_ \"bad arguments to \" ++ \"decode\")\n{\n\tdecode_op = Operator \"decode\" \n\t\tdecode Operator_type.COMPOUND_REWRAP false;\n\n\tdecode_im im\n\t\t= im_LabQ2Lab im, get_coding im == Image_coding.LABPACK\n\t\t= im_rad2float im, get_coding im == Image_coding.RAD\n\t\t= im;\n}\n\nmeasure_draw across down measure image\n    = mark\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n\n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::  \n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n    x = map (extract 0) cods;\n    y = map (extract 1) cods;\n\n    outer = mkim [$pixel => 255] sample_width sample_height 1;\n    inner = mkim [] (sample_width - 4) (sample_height - 4) 1;\n    patch = insert 2 2 inner outer;\n\n    bg = mkim [] image.width image.height 1;\n\n    mask = Image (im_insertset bg.value patch.value x y);\n\n    image' = colour_transform_to Image_type.sRGB image;\n\n    mark = if mask then Vector [0, 255, 0] else image';\n}\n\nmeasure_sample across down measure image\n    = measures\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n                \n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::\n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n\n\timage' = decode image;\n    patches = map (\\p extract_area p?0 p?1 sample_width sample_height image') \n\t\tcods;\n    measures = Matrix (map (map mean) (map bandsplit patches));\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ninvert x\n\t= oo_unary_function invert_op x, is_class x\n\t= im_invert x, is_image x\n\t= 255 - x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"invert\")\n{\n\tinvert_op = Operator \"invert\" invert Operator_type.COMPOUND false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate interp angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_affinei_all image interp.value a (-b) b a 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\t(rotate interp) Operator_type.COMPOUND_REWRAP false;\n\ta = cos angle;\n\tb = sin angle;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_lr\")\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin_lr Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert (get_width a) 0 b a;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_tb\")\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin_tb Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert 0 (get_height a) b a;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\t// The [[real]] can contain 128 values ... squeeze them out!\n\timage = im_mask2vips (Matrix m2) == 255;\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\" ++ \": \" ++ \n\t\t\"conv (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvf mask image\n\t= oo_unary_function convf_op image, is_class image\n\t= im_conv_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convf\" ++ \": \" ++ \n\t\t\"convf (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconvf_op = Operator \"convf\" \n\t\t(convf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\naconvsep layers mask image \n\t= oo_unary_function aconvsep_op image, is_class image\n\t= im_aconvsep image (to_matrix mask) (to_real layers), is_image image\n\t= error (_ \"bad arguments to \" ++ \"aconvsep\")\n{\n\taconvsep_op = Operator \"aconvsep\" \n\t\t(aconvsep layers mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsep_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_indexed index value\n\t= oo_binary_function hist_find_indexed_op index value, is_class index\n\t= oo_binary'_function hist_find_indexed_op index value, is_class value\n\t= im_hist_indexed index value, is_image index && is_image value\n\t= error (_ \"bad arguments to \" ++ \"hist_find_indexed\")\n{\n\thist_find_indexed_op = Operator \"hist_find_indexed\" \n\t\t(compose (compose Plot_histogram) hist_find_indexed) \n\t\t\tOperator_type.COMPOUND false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h \n\t\t= (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h\n\t{\n\t\t// up the format so it can represent the whole range of\n\t\t// possible values from this mask\n\t\tfmt x\n\t\t\t= Image_format.SHORT, \n\t\t\t\tx == Image_format.UCHAR || x == Image_format.CHAR\n\t\t\t= Image_format.INT, \n\t\t\t\tx == Image_format.USHORT || x == Image_format.SHORT ||\n\t\t\t\tx == Image_format.UINT \n\t\t\t= x;\n\t}\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_inv hist \n\t= oo_unary_function hist_inv_op hist, is_class hist\n\t= inv hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_inv\")\n{\n\thist_inv_op = Operator \"hist_inv\" \n\t\thist_inv Operator_type.COMPOUND_REWRAP false;\n\n\tinv im\n\t\t= im_invertlut (to_matrix im''') len\n\t{\n\t\t// need a vertical doublemask\n\t\tim' \n\t\t\t= rot90 im, get_width im > 1 && get_height im == 1 \n\t\t\t= im, get_width im == 1 && get_height im > 1\n\t\t\t= error (_ \"not a hist\");\n\t\tlen = get_height im';\n\n\t\t// values must be scaled to 0 - 1\n\t\tim'' = im' / (max im');\n\t\t\n\t\t// add an index column on the left\n\t\t// again, must be in 0-1\n\t\ty = ((make_xy 1 len)?1) / len;\n\t\tim''' = y ++ im'';\n\t}\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= lhisteq image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false;\n\n\t// loop over bands, if necessary\n\tlhisteq im\n\t\t= im_lhisteq im (to_real w) (to_real h), get_bands im == 1\n\t\t= (foldl1 join @ map lhisteq @ bandsplit) im;\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nreduce kernel xshr yshr image\n\t= oo_unary_function reduce_op image, is_class image\n\t= reduce_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"reduce\")\n{\n\treduce_op = Operator \"reduce\" \n\t\treduce_im Operator_type.COMPOUND_REWRAP false;\n\n\treduce_im im \n\t\t= out\n\t{\n\t\t[out] = vips_call \"reduce\" [im, xshr, yshr] [$kernel => kernel.value];\n\t}\n}\n\nsimilarity interpolate scale angle image\n\t= oo_unary_function similarity_op image, is_class image\n\t= similarity_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"similarity\")\n{\n\tsimilarity_op = Operator \"similarity\" \n\t\tsimilarity_im Operator_type.COMPOUND_REWRAP false;\n\n\tsimilarity_im im \n\t\t= out\n\t{\n\t\t[out] = vips_call \"similarity\" [im] [\n\t\t\t$interpolate => interpolate.value,\n\t\t\t$scale => scale,\n\t\t\t$angle => angle\n\t\t];\n\t}\n}\n\nresize kernel xfac yfac image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\tis_nn = kernel.type == Kernel_type.NEAREST_NEIGHBOUR;\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn \n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn \n\n\t\t// everything else ... we just pass on to vips_resize()\n\t\t= vips_resize kernel xfac' yfac' im\n\t{\n\t\tvips_resize kernel hscale vscale im \n\t\t\t= out\n\t\t{\n\t\t\t[out] = vips_call \"resize\" [im, hscale] \n\t\t\t\t[$vscale => vscale, $kernel => kernel.value];\n\t\t}\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\n\n// Given a xywh rect, flip it around so wh are always positive\nrect_normalise x y w h \n\t= [x', y', w', h']\n{\n\tx'\n\t\t= x + w, w < 0\n\t\t= x;\n\ty'\n\t\t= y + h, h < 0\n\t\t= y;\n\tw' = abs w;\n\th' = abs h;\n}\n\ndraw_flood_blob x y ink image\n\t= oo_unary_function draw_flood_blob_op image, is_class image\n\t= im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood_blob\")\n{\n\tdraw_flood_blob_op = Operator \"draw_flood_blob\" \n\t\t(draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_flood x y ink image\n\t= oo_unary_function draw_flood_op image, is_class image\n\t= im_draw_flood image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood\")\n{\n\tdraw_flood_op = Operator \"draw_flood\" \n\t\t(draw_flood x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* This version of draw_rect uses insert_noexpand and will be fast, even for\n * huge images.\n */\ndraw_rect_width x y w h f t ink image\n\t= oo_unary_function draw_rect_width_op image, is_class image\n\t= my_draw_rect_width image (to_int x) (to_int y) \n\t\t(to_int w) (to_int h) (to_int f) (to_int t) ink, \n\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_width\")\n{\n\tdraw_rect_width_op = Operator \"draw_rect_width\" \n\t\t(draw_rect_width x y w h f t ink) \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\tmy_draw_rect_width image x y w h f t ink\n\t\t= insert x' y' (block w' h') image, f == 1\n\t\t= (insert x' y' (block w' t) @ \n\t\t\tinsert (x' + w' - t) y' (block t h') @ \n\t\t\tinsert x' (y' + h' - t) (block w' t) @ \n\t\t\tinsert x' y' (block t h')) image\n\t{\n\t\tinsert = insert_noexpand;\n\t\tblock w h = image_new w h (get_bands image) (get_format image)\n\t\t\t(get_coding image) (get_type image) ink' 0 0;\n\t\tink' \n\t\t\t= Vector ink, is_list ink\n\t\t\t= ink;\n\t\t[x', y', w', h'] = rect_normalise x y w h;\n\t}\n}\n\n/* Default to 1 pixel wide edges.\n */\ndraw_rect x y w h f ink image\n\t= draw_rect_width x y w h f 1 ink image;\n\n/* This version of draw_rect uses the paintbox rect draw operation. It is an\n * inplace operation and will use bucketloads of memory.\n */\ndraw_rect_paintbox x y w h f ink image\n\t= oo_unary_function draw_rect_op image, is_class image\n\t= im_draw_rect image (to_real x) (to_real y) \n\t\t(to_real w) (to_real h) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_paintbox\")\n{\n\tdraw_rect_op = Operator \"draw_rect\" \n\t\t(draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_circle x y r f ink image\n\t= oo_unary_function draw_circle_op image, is_class image\n\t= im_draw_circle image (to_real x) (to_real y) \n\t\t(to_real r) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_circle\")\n{\n\tdraw_circle_op = Operator \"draw_circle\" \n\t\t(draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_line x1 y1 x2 y2 ink image\n\t= oo_unary_function draw_line_op image, is_class image\n\t= im_draw_line image (to_real x1) (to_real y1) \n\t\t(to_real x2) (to_real y2) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_line\")\n{\n\tdraw_line_op = Operator \"draw_line\" \n\t\t(draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (\\x x % base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (\\x idivide x base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= NULL, any (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n/* Linear regression. Return a class with the stuff we need in.\n * from s15.2, p 665 NR in C\n * \n * Also calculate R2, see eg.:\n * https://en.wikipedia.org/wiki/Coefficient_of_determination \n */\nlinreg xes yes\n    = obj\n{\n    obj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [t * y :: [t, y] <- zip2 tes yes] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes];\n\n\t\tsiga = (chi2 / (ss - 2)) ** 0.5 *\n\t\t\t((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5;\n\n\t\t// for compat with linregw, see below\n\t\tq = 1.0;\n\n\t\tR2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes];\n\t}\n\n\tss = len xes;\n\tsx = sum xes;\n\tsy = sum yes;\n\tmy = sy / ss;\n\tsxoss = sx / ss;\n\n\ttes = [x - sxoss :: x <- xes];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Weighted linear regression. Xes, yes and a list of deviations.\n */\nlinregw xes yes devs \n\t= obj\n{\n\tobj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: \n\t\t\t[x, y, sd] <- zip3 xes yes devs];\n\n\t\tsiga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (1 / st2) ** 0.5;\n\n\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\n\t\tR2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes];\n\t}\n\n\twt = [sd ** -0.5 :: sd <- devs];\n\n\tss = sum wt;\n\tsx = sum [x * w :: [x, w] <- zip2 xes wt];\n\tsy = sum [y * w :: [y, w] <- zip2 yes wt];\n\tmy = sy / len xes;\n\tsxoss = sx / ss;\n\n\ttes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Clustering: pass in a list of points, repeatedly merge the\n * closest two points until no two points are closer than the threshold.\n * Return [merged-points, corresponding-weights]. A weight is a list of the\n * indexes we merged to make that point, ie. len weight == how significant\n * this point is.\n *\n * eg. \n *\tcluster 12 [152,154,155,42,159] == \n *\t\t[[155,42],[[1,2,0,4],[3]]]\n */\ncluster thresh points\n\t= oo_unary_function cluster_op points, is_class points\n\t// can't use [0..len points - 1], in case len points == 0\n\t= merge [points, map (converse cons []) (take (len points) [0 ..])],\n\t\tis_list points\n\t= error (_ \"bad arguments to \" ++ \"cluster\")\n{\n\tcluster_op = Operator \"cluster\" \n\t\t(cluster thresh) Operator_type.COMPOUND false;\n\n\tmerge x\n\t\t= x, m < 2 || d > thresh\n\t\t= merge [points', weights']\n\t{\n\t\t[points, weights] = x;\n\t\tm = len points;\n\n\t\t// generate indexes of all possible pairs, avoiding comparing a thing \n\t\t// to itself, and assuming that dist is reflexive\n\t\t// first index is always less than 2nd index\n\t\t// the +1,+2 makes sure we have an increasing generator, otherwise we\n\t\t// can get [3 .. 4] (for example), which will make a decreasing\n\t\t// sequence\n\t\tpairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]];\n\n\t\t// distance function\n\t\t// arg is eg. [3,1], meaning get distance from point 3 to point 1\n\t\tdist x \n\t\t\t= abs (points?i - points?j)\n\t\t{\n\t\t\t[i, j] = x;\n\t\t}\n\n\t\t// smallest distance, then the two points we merge\n\t\tp = minpos (map dist pairs);\n\t\td = dist pairs?p;\n\t\t[i, j] = pairs?p;\n\n\t\t// new point and new weight\n\t\tnw = weights?i ++ weights?j;\n\t\tnp = (points?i * len weights?i + points?j * len weights?j) / len nw;\n\n\t\t// remove element i from a list\n\t\tremove i l = take i l ++ drop (i + 1) l;\n\n\t\t// remove two old points, add the new merged one\n\t\t// i < j (see \"pairs\", above)\n\t\tpoints' = np : remove i (remove j points);\n\t\tweights' = nw : remove i (remove j weights);\n\t}\n}\n\n/* Extract the area of an image around an arrow.\n * Transform the image to make the arrow horizontal, then displace by hd and\n * vd pxels, then cut out a bit h pixels high centered on the arrow.\n */\nextract_arrow hd vd h arrow\n\t= extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im'\n{\n\t// the line as a polar vector\n\tpv = polar (arrow.width, arrow.height);\n\ta = im pv;\n\n\t// smallest rotation that will make the line horizontal\n\ta'\n\t\t= 360 - a, a > 270\n\t\t= 180 - a, a > 90\n\t\t= -a;\n\n\tim' = rotate Interpolate_bilinear a' arrow.image;\n\n\t// look at the start and end of the arrow, pick the leftmost\n\tp\n\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t= (arrow.right, arrow.bottom);\n\n\t// transform that point to im' space\n\tp' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset);\n}\n\n/* You'd think these would go in _convert, but they are not really colour ops,\n * so put them here.\n */\nrad2float image\n\t= oo_unary_function rad2float_op image, is_class image\n\t= im_rad2float image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"rad2float\")\n{\n\trad2float_op = Operator \"rad2float\" \n\t\trad2float Operator_type.COMPOUND_REWRAP false;\n}\n\nfloat2rad image\n\t= oo_unary_function float2rad_op image, is_class image\n\t= im_float2rad image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"float2rad\")\n{\n\tfloat2rad_op = Operator \"float2rad\" \n\t\tfloat2rad Operator_type.COMPOUND_REWRAP false;\n}\n\nsegment x\n\t= oo_unary_function segment_op x, is_class x\n\t= image', is_image x \n\t= error (_ \"bad arguments to \" ++ \"segment\")\n{\n\tsegment_op = Operator \"segment\" \n\t\tsegment Operator_type.COMPOUND_REWRAP false;\n\n\t[image, nsegs] = im_segment x;\n\timage' = im_copy_set_meta image \"n-segments\" nsegs;\n}\n\npoint a b\n\t= oo_binary_function point_op a b, is_class a\n\t= oo_binary'_function point_op a b, is_class b\n\t= im_read_point b x y, is_image b\n\t= [b?x?y], is_matrix b\n\t= [b?x], is_real_list b && y == 0\n\t= [b?y], is_real_list b && x == 0\n\t= error (_ \"bad arguments to \" ++ \"point\")\n{\n\tpoint_op = Operator \"point\" \n\t\t(\\a\\b Vector (point a b)) Operator_type.COMPOUND false;\n\n\t(x, y) \n\t\t= a, is_complex a;\n\t\t= (a?0, a?1), is_real_list a && is_list_len 2 a\n\t\t= error \"bad position format\";\n}\n\n/* One image in, one out. \n */\nsystem_image command x\n\t= oo_unary_function system_image_op x, is_class x\n\t= system x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"system_image\")\n{\n\tsystem_image_op = Operator \"system_image\" \n\t\t(system_image command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem im\n\t\t= image_out\n\t{\n\t\t[image_out, log] = \n\t\t\tim_system_image (get_image im) \"%s.tif\" \"%s.tif\" command;\n\t}\n}\n\n/* Two images in, one out. \n */\nsystem_image2 command x1 x2\n\t= oo_binary_function system_image2_op x1 x2, is_class x1\n\t= oo_binary'_function system_image2_op x1 x2, is_class x2\n\t= system x1 x2, is_image x1 && is_image x2\n\t= error (_ \"bad arguments to \" ++ \"system_image2\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image2 command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Three images in, one out. \n */\nsystem_image3 command x1 x2 x3\n\t= oo_binary_function system_image2_op x2 x3, is_class x2\n\t= oo_binary'_function system_image2_op x2 x3, is_class x3\n\t= system x1 x2 x3, is_image x1 && is_image x2 && is_image x3\n\t= error (_ \"bad arguments to \" ++ \"system_image3\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image3 command x1) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2 x3\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2, x3], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Zero images in, one out. \n */\nsystem_image0 command \n\t= Image image_out\n{\n\t[image_out] = vips_call \"system\" [command] [\n\t\t$out => true,\n\t\t$out_format => \"%s.tif\" \n\t];\n}\n\nhough_line w h x \n\t= oo_unary_function hough_line_op x, is_class x\n\t= hline (to_real w) (to_real h) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_line\")\n{\n\though_line_op = Operator \"hough_line\" \n\t\t(hough_line w h) Operator_type.COMPOUND_REWRAP false;\n\n\thline w h x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_line\" [x] [\n\t\t\t$width => w, \n\t\t\t$height => h\n\t\t];\n\t}\n}\n\nhough_circle s mn mx x \n\t= oo_unary_function hough_circle_op x, is_class x\n\t= hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_circle\")\n{\n\though_circle_op = Operator \"hough_circle\" \n\t\t(hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false;\n\n\thcircle s mn mx x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_circle\" [x] [\n\t\t\t$scale => s, \n\t\t\t$min_radius => mn, \n\t\t\t$max_radius => mx\n\t\t];\n\t}\n}\n\nmapim interp ind in\n\t= oo_binary_function mapim_op ind in, is_class ind\n\t= oo_binary'_function mapim_op ind in, is_class in\n\t= mapim_fn ind in, is_image ind && is_image in\n\t= error (_ \"bad arguments to \" ++ \"mapim\")\n{\n\tmapim_op = Operator \"mapim\" \n\t\t(mapim interp) Operator_type.COMPOUND_REWRAP false;\n\n\tmapim_fn ind im\n\t\t= out\n\t{\n\t\t[out] = vips_call \"mapim\" [im, ind] [$interpolate => interp];\n\t}\n}\n\nperlin cell width height\n\t= Image im\n{\n\t[im] = vips_call \"perlin\" [to_real width, to_real height] [\n\t\t$cell_size => to_real cell \n\t];\n}\n\nworley cell width height\n\t= Image im\n{\n\t[im] = vips_call \"worley\" [to_real width, to_real height] [\n\t\t$cell_size => to_real cell \n\t];\n}\n"
  },
  {
    "path": "share/nip2/compat/8.4/_types.def",
    "content": "/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary (\\a op.fn a x) this,\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// we can't call map_trinary directly, since it uses Group and we\n\t// don't support mutually recursive top-level functions :-(\n\t// copy-paste it here, keep in sync with the version in _stdenv\n\tmap_nary fn args\n\t\t= fn args, groups == []\n\t\t= Group (map process [0, 1 .. shortest - 1])\n\t{\n\t\tgroups = filter is_Group args;\n\t\n\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\tprocess n\n\t\t\t= NULL, any (map (is_noval n) args)\n\t\t\t= map_nary fn (map (extract n) args)\n\t\t{\n\t\t\textract n arg\n\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t= arg;\n\t\n\t\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t\t}\n\t}\n\n\t// need ite as a true trinary\n\tite a b c = if a then b else c;\n\n\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t];\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\n\t\t[op.fn this.value x,\n\t\t\top.type == Operator_type.COMPOUND]\n\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[is_list_len 3 value, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.item colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum \"Colour space\" Image_type.colour_spaces default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\n/* An option whose value is a string rather than a number.\n */\nOption_string caption labels item = class\n\tOption caption labels (index (equal item) labels) {\n\tOption_edit caption labels value \n\t\t= this.Option_string caption labels (labels?value);\n}\n\n/* Make an option from an enum.\n */\nOption_enum caption enum item = class\n\tOption_string caption enum.names item {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing item;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum caption enum (enum.names?value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNONE = 0;\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNONE = 0;\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n\tRAD = 6;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* Extract a column.\n\t */\n\tcolumn n = map (extract n) value;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (column col) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (column from);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = this.column 0; \n\tthings = this.column 1; \n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tHISTOGRAM = 10;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tARRAY = 27;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t$MULTIBAND => MULTIBAND,\n\t\t$B_W => B_W,\n\t\t$HISTOGRAM => HISTOGRAM,\n\t\t$XYZ => XYZ,\n\t\t$LAB => LAB,\n\t\t$CMYK => CMYK,\n\t\t$LABQ => LABQ,\n\t\t$RGB => RGB,\n\t\t$UCS => UCS,\n\t\t$LCH => LCH,\n\t\t$LABS => LABS,\n\t\t$sRGB => sRGB,\n\t\t$YXY => YXY,\n\t\t$FOURIER => FOURIER,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$ARRAY => ARRAY\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options generated from this, so match the order to the order in the\n\t * Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t$sRGB => sRGB,\n\t\t$Lab => LAB,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t$Mono => B_W,\n\t\t$sRGB => sRGB,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$Lab => LAB,\n\t\t$LabQ => LABQ,\n\t\t$LabS => LABS,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \n\t\t// \"Image v == 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\t// if one of then/else is an image, get the target format from that\n\t\t// otherwise, let the non-image objects set the target\n\t\ttarget_format \n\t\t\t= get_member_list has_format get_format x, \n\t\t\t\thas_member_list has_format x\n\t\t\t= NULL;\n\n\t\tto_image x = to_image_size width height target_bands target_format x;\n\n\t\t[then', else'] = map to_image x;\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if value then then' else else');\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nKernel_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tLINEAR = 1;\n\tCUBIC = 2;\n\tLANCZOS2 = 3;\n\tLANCZOS3 = 4;\n\n\t// Should introspect to get the list of interpolators :-(\n\t// We can \"dir\" on VipsInterpolate to get a list of them, but we\n\t// can't get i18n'd descriptions until we have more\n\t// introspection stuff in nip2.\n\n\t/* Table to map kernel numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Linear\", \n\t\t_ \"Cubic\",\n\t\t_ \"Lanczos, two lobes\",\n\t\t_ \"Lanczos, three lobes\"\n\t];\n\n\t/* And to vips enum nicknames.\n\t */\n\ttypes = [\n\t\t\"nearest\", \n\t\t\"linear\", \n\t\t\"cubic\", \n\t\t\"lanczos2\", \n\t\t\"lanczos3\"\n\t];\n}\n\nKernel type = class {\n\tvalue = Kernel_type.types?type;\n}\n\nKernel_linear = Kernel Kernel_type.LINEAR;\n\nKernel_picker default = class \n\tKernel kernel.value {\n\t_vislevel = 2;\n\n\tkernel = Option \"Kernel\" Kernel_type.descriptions default;\n}\n\nInterpolate_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\tLBB = 3;\n\tNOHALO = 4;\n\tVSQBS = 5;\n\n\t// Should introspect to get the list of interpolators :-(\n\t// We can \"dir\" on VipsInterpolate to get a list of them, but we\n\t// can't get i18n'd descriptions until we have more\n\t// introspection stuff in nip2.\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Bilinear\", \n\t\t_ \"Bicubic\",\n\t\t_ \"Upsize: reduced halo bicubic (LBB)\",\n\t\t_ \"Upsharp: reduced halo bicubic with edge sharpening (Nohalo)\",\n\t\t_ \"Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)\"\n\t];\n\n\t/* And to vips type names.\n\t */\n\ttypes = [\n\t\t\"VipsInterpolateNearest\",\n\t\t\"VipsInterpolateBilinear\",\n\t\t\"VipsInterpolateBicubic\",\n\t\t\"VipsInterpolateLbb\",\n\t\t\"VipsInterpolateNohalo\",\n\t\t\"VipsInterpolateVsqbs\"\n\t];\n}\n\nInterpolate type options = class {\n\tvalue = vips_object_new Interpolate_type.types?type [] options;\n}\n\nInterpolate_bilinear = Interpolate Interpolate_type.BILINEAR [];\n\nInterpolate_picker default = class \n\tInterpolate interp.value [] {\n\t_vislevel = 2;\n\n\tinterp = Option \"Interpolation\" Interpolate_type.descriptions default;\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t_ \"Perceptual\" => PERCEPTUAL,\n\t\t_ \"Relative\" => RELATIVE,\n\t\t_ \"Saturation\" => SATURATION,\n\t\t_ \"Absolute\" => ABSOLUTE\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t_ \"Point\" => POINT,\n\t\t_ \"Line\" => LINE,\n\t\t_ \"Spline\" => SPLINE,\n\t\t_ \"Bar\" => BAR\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t_ \"YYYY\" => YYYY,\n\t\t_ \"XYYY\" => XYXY,\n\t\t_ \"XYXY\" => XYXY\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n\tto_image dpi = extract_bands 0 3 \n\t\t(graph_export_image (to_real dpi) this);\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [$format => Plot_format.XYYY] value {\n}\n\n/* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate\n * empty slots, for example.\n */\nNULL = class \n\t_Object {\n\too_binary_table op x = [\n\t\t// the only operation we allow is equality .. use pointer equality,\n\t\t// this lets us test a == NULL and a != NULL\n\t\t[this === x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"equal\"],\n\t\t[this !== x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"not_equal\"]\n\t] ++ super.oo_binary_table op x;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.5/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t[_L, _a, _b] = default_value;\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n\n\tCCT_colour = class\n\t\tMenuaction (_ \"Colour from CCT\") (_ \"pick colour by CCT\") {\n\t\taction = widget 6500;\n\n\t\twidget x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tT = Scale \"CCT\" 1800 25000 x;\n\n\t\t\t_result = colour_from_temp (to_real T);\n\n\t\t\tColour_edit space value \n\t\t\t\t= widget (temp_from_colour (Colour space value));\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Convert to\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Tag as\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum (_ \"Old whitepoint\") Whitepoints \"D65\";\n\t\t\tnew_white = Option_enum (_ \"New whitepoint\") Whitepoints \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCCT_item = class\n\t\tMenuaction (_ \"Calculate temperature\")\n\t\t\t(_ \"estimate CCT using the McCamy approximation\") {\n\t\taction z = map_unary temp_from_colour z;\n\t}\n\n\tColour_item = Colour_new_item.CCT_colour;\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= print_profile, \n\t\t\thas_type image && \n\t\t\tget_type image == Image_type.CMYK &&\n\t\t\thas_bands image && \n\t\t\tget_bands image >= 4\n\t\t= monitor_profile;\n\trender_intents = Option_enum (_ \"Render intent\") Render_intent.names\n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_rad_item = class\n\tMenupullright (_ \"_Radiance\") (_ \"convert to and from Radiance packed format\") {\n\tUnpack_item = class\n\t\tMenuaction (_ \"Unpack\") \n\t\t\t(_ \"unpack Radiance format to float\") {\n\t\taction x = map_unary rad2float x;\n\t}\n\n\tPack_item = class\n\t\tMenuaction (_ \"Pack\") \n\t\t\t(_ \"pack 3-band float to Radiance format\") {\n\t\taction x = map_unary float2rad x;\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n        // get a representative image from an arg\n        get_image x\n            = get_image x.value?0, is_Group x\n            = x;\n\n        _im = get_image x; \n\t\tsample = measure_draw (to_real pacross) (to_real pdown) \n\t\t\t\t(to_real measure) _im;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure_sample (to_real pacross) (to_real pdown) \n\t\t\t\t\t(to_real measure) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.5/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 2;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 20;\n\t\t\tfs = Scale \"Sharpen flat areas by\" 0 5 0.5;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" 0 5 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tlayers = Scale \"Layers\" 1 100 10;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\", \"Approximate\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf, aconvsep layers]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\t\t\trotate = Option \"Rotate\" [\n\t\t\t\t\"Don't rotate\", \n\t\t\t\t\"4 x 45 degrees\", \n\t\t\t\t\"8 x 45 degrees\", \n\t\t\t\t\"2 x 90 degrees\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_lindetect, !separable && type == 0 && rotate == 1\n\t\t\t\t\t\t= im_compass, !separable && type == 0 && rotate == 2\n\t\t\t\t\t\t= im_gradient, !separable && type == 0 && rotate == 3\n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_conv_f, !separable && type == 1\n\t\t\t\t\t\t= im_convsep_f, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 4) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\t\t\tmax_slope = Scale \"Maxium slope\" 0 10 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width \n\t\t\t\t\t\t\twindow_height \n\t\t\t\t\t\t\tmax_slope in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\nFilter_hough_item = class\n\tMenupullright \"_Hough Transform\" \"transform to parameter space\" {\n\tLine_item = class\n\t\tMenuaction \"_Line\" \"find straight line Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpspace_width = Expression \"Parameter space width\" 64;\n\t\t\tpspace_height = Expression \"Parameter space height\" 64;\n\n\t\t\t_result \n\t\t\t\t= map_unary line a \n\t\t\t{\n\t\t\t\tline a \n\t\t\t\t\t= hough_line \n\t\t\t\t\t\t(to_real pspace_width) (to_real pspace_height) a;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class\n\t\tMenuaction \"_Circle\" \"find circle Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Expression \"Scale down parameter space by\" 10;\n\t\t\tmin_radius = Expression \"Minimum radius\" 10;\n\t\t\tmax_radius = Expression \"Maximum radius\" 30;\n\n\t\t\t_result \n\t\t\t\t= map_unary circle a \n\t\t\t{\n\t\t\t\tcircle a \n\t\t\t\t\t= hough_circle (to_real scale) (to_real min_radius)\n\t\t\t\t\t\t(to_real max_radius) a;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_coordinate_item = class\n\tMenupullright \"_Coordinate Transform\" \"various coordinate transforms\" {\n\t// run a function which wants a complex arg on a non-complex two-band\n\t// image\n\trun_cmplx fn x\n\t\t= re x' ++ im x'\n\t{\n\t\tx' = fn (x?0, x?1);\n\t}\n\n\tPolar_item = class\n\t\tMenuaction \"_Polar\" \"transform to polar coordinates\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result \n\t\t\t\t= map_unary to_polar a \n\t\t\t{\n\t\t\t\tto_polar im \n\t\t\t\t\t= mapim interp.value map' im\n\t\t\t\t{\n\t\t\t\t\t// xy image, origin in the centre, scaled to fit image to\n\t\t\t\t\t// a circle\n\t\t\t\t\txy = make_xy im.width im.height;\n\t\t\t\t\txy' = xy - Vector [im.width / 2, im.height / 2];\n\t\t\t\t\tscale = min [im.width, im.height] / im.width;\n\t\t\t\t\txy'' = 2 * xy' / scale;\n\n\t\t\t\t\t// to polar, scale vertical axis to 360 degrees\n\t\t\t\t\tmap = run_cmplx polar xy'';\n\t\t\t\t\tmap' = map * Vector [1, im.height / 360];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tRectangular_item = class\n\t\tMenuaction \"_Rectangular\" \"transform to rectangular coordinates\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result \n\t\t\t\t= map_unary to_rect a \n\t\t\t{\n\t\t\t\tto_rect im \n\t\t\t\t\t= mapim interp.value map'' im\n\t\t\t\t{\n\t\t\t\t\t// xy image, vertical scaled to 360 degrees\n\t\t\t\t\txy = make_xy im.width im.height;\n\t\t\t\t\txy' = xy * Vector [1, 360 / im.height];\n\n\t\t\t\t\t// to rect, scale to image rect\n\t\t\t\t\tmap = run_cmplx rectangular xy';\n\t\t\t\t\tscale = min [im.width, im.height] / im.width;\n\t\t\t\t\tmap' = map * scale / 2;\n\n\t\t\t\t\tmap'' = map' + Vector [im.width / 2, im.height / 2];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image\" \"use an image to blend two objects\" {\n\t\taction a b c = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ti = Toggle \"Invert mask\" false;\n\n\t\t\t_result \n\t\t\t\t= map_trinary process a b c\n\t\t\t{\n\t\t\t\tprocess a b c \n\t\t\t\t\t= blend condition in1 in2, !i\n\t\t\t\t\t= blend (invert condition) in1 in2\n\t\t\t\t{\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t\t= false,\n\t\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t\t= true;\n\t\t\t\t\t[condition, in1, in2] = sortc compare [a, b, c];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"Blend _Alpha\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t_ \"Normal\" => NORMAL,\n\t\t\t_ \"If Lighter\" => IFLIGHTER,\n\t\t\t_ \"If Darker\" => IFDARKER,\n\t\t\t_ \"Multiply\" => MULTIPLY,\n\t\t\t_ \"Add\" => ADD,\n\t\t\t_ \"Subtract\" => SUBTRACT,\n\t\t\t_ \"Screen\" => SCREEN,\n\t\t\t_ \"Burn\" => BURN,\n\t\t\t_ \"Soft Light\" => SOFTLIGHT,\n\t\t\t_ \"Hard Light\" => HARDLIGHT,\n\t\t\t_ \"Lighten\" => LIGHTEN,\n\t\t\t_ \"Darken\" => DARKEN,\n\t\t\t_ \"Dodge\" => DODGE,\n\t\t\t_ \"Reflect\" => REFLECT,\n\t\t\t_ \"Freeze\" => FREEZE,\n\t\t\t_ \"Bitwise OR\" => OR,\n\t\t\t_ \"Bitwise AND\" => AND\n\t\t];\n\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum \"Blend mode\" names \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\t[mono, colour] = \n\t\t\t\t\tsortc (const (is_colour_type @ get_type)) [a, b];\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t_ \"Grey\",\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t_ \"North-west\",\n\t\t\t\t_ \"North\",\n\t\t\t\t_ \"North-east\",\n\t\t\t\t_ \"West\",\n\t\t\t\t_ \"Centre\",\n\t\t\t\t_ \"East\",\n\t\t\t\t_ \"South-west\",\n\t\t\t\t_ \"South\",\n\t\t\t\t_ \"South-east\",\n\t\t\t\t_ \"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nAutotrace_item = class \n\tMenuaction \"_Trace\" \"convert a bitmap to an SVG file\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tdespeckle = Scale \"Despeckle level\" 1 20 1;\n\t\tline = Scale \"Line threshold\" 1 20 1;\n\t\tcenter = Toggle \"Trace centreline\" false;\n\t\tscale = Scale \"SVG scale\" 0.1 10 1;\n\n\t\tcommand \n\t\t\t= \"autotrace %s \" ++ join_sep \" \" \n\t\t\t\t[ofmt, ofile, desp, lint, cent]\n\t\t{\n\t\t\tprog = search_for_error \"autotrace\"; \n\t\t\tofmt = \"-output-format svg\";\n\t\t\tofile = \"-output-file %s\";\n\t\t\tdesp = \"-despeckle-level \" ++ print despeckle.value;\n\t\t\tlint = \"-line-threshold \" ++ print line.value;\n\t\t\tcent = if center then \"-centerline \" else \"\";\n\t\t}\n\n\t\t_result \n\t\t\t= Image output\n\t\t{\n\t\t\t[output] = vips_call \"system\" \n\t\t\t\t[command] \n\t\t\t\t[$in => [x.value],\n\t\t\t\t $in_format => \"%s.ppm\", \n\t\t\t\t $out => true,\n\t\t\t\t $out_format => \"%s.svg[scale=\" ++ print scale.value ++ \"]\"\n\t\t\t\t];\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.5/Histogram.def",
    "content": "Hist_new_item = class\n\tMenupullright \"_New\" \"new histogram\" {\n\tHist_item = class\n\t\tMenuaction \"_Identity\" \"make an identity histogram\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\t_result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d);\n\t\t}\n\t}\n\n\tHist_new_from_matrix = Matrix_buildlut_item; \n\n\tHist_from_image_item = class\n\t\tMenuaction \"Ta_g Image As Histogram\" \"set image Type to Histogram\" {\n\t\taction x = hist_tag x;\n\t}\n\n\tTone_item = class \n\t\tMenuaction \"_Tone Curve\" \"make a new tone mapping curve\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\t_result \n\t\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t\t{\n\t\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_convert_to_hist_item = class \n\tMenuaction \"Con_vert to Histogram\" \"convert anything to a histogram\" {\n\taction x = hist_tag (to_image x);\n}\n\nHist_find_item = class \n\tMenupullright \"_Find\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n\n\tIndexed_item = class\n\t\tMenuaction \"_Indexed\" \n\t\t\t\"use a 1-band index image to pick bins for an n-band image\" {\n\t\taction x y \n\t\t\t= map_binary map x y\n\t\t{\n\t\t\tmap a b\n\t\t\t\t= hist_find_indexed index im\n\t\t\t{\n\t\t\t\t[im, index] = sortc (const is_index) [a, b];\n\n\t\t\t\tis_index x\n\t\t\t\t\t= has_image x && b == 1 && \n\t\t\t\t\t\t(f == Image_format.UCHAR || f == Image_format.USHORT)\n\t\t\t\t{\n\t\t\t\t\tim = get_image x;\n\t\t\t\t\tb = get_bands x;\n\t\t\t\t\tf = get_format x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\t[im, hist] = sortc (const is_hist) [a, b];\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Integrate\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate\" \n\t\t\"find point-to-point differences (inverse of Integrate)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_inv_item = class \n\tMenuaction \"In_vert\" \"invert a histogram\" {\n\taction x = map_unary hist_inv x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\nHist_entropy_item = class Menuaction \"Entropy\" \"calculate histogram entropy\" {\n\taction x = hist_entropy x;\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\tarea = extract_arrow \n\t\t\t\t\tdisplace.value vdisplace.value width.value arrow;\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize Kernel_linear 1 (1 / width.value) area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary (extract_arrow \n\t\t\t\tdisplace.value vdisplace.value width.value) x;\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcaption = Expression \"Chart caption\" \"none\";\n\t\tformat = Option_enum \"Format\" Plot_format.names \"YYYY\";\n\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\t\txcaption = Expression \"X axis caption\" \"none\";\n\t\tycaption = Expression \"Y axis caption\" \"none\";\n\t\tseries_captions = Expression \"Series captions\" [\"Band 0\"];\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => style.value, $format => format.value] ++ \n\t\t\t\t\trange ++ captions;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\tcaptions \n\t\t\t\t= concat (map test caption_options) ++ \n\t\t\t\t  [$series_captions => series_captions.expr]\n\t\t\t{\n\t\t\t\tcaption_options = [\n\t\t\t\t\t$caption => caption.expr,\n\t\t\t\t\t$xcaption => xcaption.expr,\n\t\t\t\t\t$ycaption => ycaption.expr\n\t\t\t\t];\n\t\t\t\ttest x\n\t\t\t\t\t= [], value == \"none\"\n\t\t\t\t\t= [option_name => value]\n\t\t\t\t{\n\t\t\t\t\t[option_name, value] = x;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow 0 0 1 x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.5/Image.def",
    "content": "Image_new_item = class Menupullright \"_New\" \"make new things\" {\n\tImage_black_item = class Menuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \"Image type\"\n\t\t\t\tImage_type.type_names \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region on image using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\t[target, x] = sortc compare [a, b];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\nImage_number_format_item = class\n\tMenupullright \"_Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_header_item = class \n\tMenupullright \"_Header\" \"do stuff to the image header\" {\n\n\tImage_get_item = class\n\t\tMenupullright \"_Get\" \"get header fields\" {\n\n\t\t// the header fields we can get\n\t\tfields = class {\n\t\t\ttype = 0;\n\t\t\twidth = 1;\n\t\t\theight = 2;\n\t\t\tformat = 3;\n\t\t\tbands = 4;\n\t\t\txres = 5;\n\t\t\tyres = 6;\n\t\t\txoffset = 7;\n\t\t\tyoffset = 8;\n\t\t\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t$width => width,\n\t\t\t\t$height => height,\n\t\t\t\t$bands => bands,\n\t\t\t\t$format => format,\n\t\t\t\t$type => type,\n\t\t\t\t$xres => xres,\n\t\t\t\t$yres => yres,\n\t\t\t\t$xoffset => xoffset,\n\t\t\t\t$yoffset => yoffset,\n\t\t\t\t$coding => coding\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum (_ \"Field\") field_names name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tCustom_item = class\n\t\t\tMenuaction \"C_ustom\" \"get any header field\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tfield = String \"Field\" \"Xsize\";\n\t\t\t\tparse = Option \"Parse\" [\n\t\t\t\t\t\"No parsing\",\n\t\t\t\t\t\"Parse string as integer\",\n\t\t\t\t\t\"Parse string as real\",\n\t\t\t\t\t\"Parse string as hh:mm:ss\"\n\t\t\t\t] 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary (wrap @ process @ get_header field.value) x\n\t\t\t\t{\n\t\t\t\t\tparse_str parse str = parse (split is_space str)?0;\n\n\t\t\t\t\tparse_field name cast parse x\n\t\t\t\t\t\t= cast x, is_number x\n\t\t\t\t\t\t= parse_str parse x, is_string x\n\t\t\t\t\t\t= error (\"not \" ++ name);\n\n\t\t\t\t\tget_int = parse_field \"int\" \n\t\t\t\t\t\tcast_signed_int parse_int;\n\t\t\t\t\tget_float = parse_field \"float\" \n\t\t\t\t\t\tcast_float parse_float;\n\t\t\t\t\tget_time = parse_field \"hh:mm:ss\" \n\t\t\t\t\t\tcast_signed_int parse_time;\n\n\t\t\t\t\twrap x\n\t\t\t\t\t\t= Real x, is_real x\n\t\t\t\t\t\t= Vector x, is_real_list x\n\t\t\t\t\t\t= Image x, is_image x\n\t\t\t\t\t\t= Bool x, is_bool x\n\t\t\t\t\t\t= Matrix x, is_matrix x\n\t\t\t\t\t\t= String \"String\" x, is_string x\n\t\t\t\t\t\t= List x, is_list x\n\t\t\t\t\t\t= x;\n\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tget_int, \n\t\t\t\t\t\tget_float,\n\t\t\t\t\t\tget_time\n\t\t\t\t\t]?parse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum \"Image type\" Image_type.type_names \n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_cache_item = class\n\tMenuaction \"C_ache\" \"cache calculated image pixels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttile_width = Number \"Tile width\" 128;\n\t\ttile_height = Number \"Tile height\" 128;\n\t\tmax_tiles = Number \"Maximum number of tiles to cache\" (-1);\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= cache (to_real tile_width) (to_real tile_height) \n\t\t\t\t\t(to_real max_tiles) image;\n\t\t}\n\t}\n}\n\n#separator\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\t// we can't use id here since we want to \"declass\"\n\t\t\t\t\t\t// the members of x ... consider if x is a crop class,\n\t\t\t\t\t\t// for example, we don't want to inherit from crop, we\n\t\t\t\t\t\t// want to make a new image class\n\t\t\t\t\t\trot180 @ rot180,\n\t\t\t\t\t\trot90,\n\t\t\t\t\t\trot180,\n\t\t\t\t\t\trot270\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate interp angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary straighten x\n\t\t\t\t{\n\t\t\t\t\tstraighten arrow\n\t\t\t\t\t\t= rotate interp angle'' arrow.image\n\t\t\t\t\t{\n\t\t\t\t\t\tx = arrow.width;\n\t\t\t\t\t\ty = arrow.height;\n\t\t\n\t\t\t\t\t\tangle = im (polar (x, y));\n\t\t\n\t\t\t\t\t\tangle'\n\t\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t\t= angle;\n\t\t\n\t\t\t\t\t\tangle''\n\t\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize kernel xfactor yfactor image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\taspect = Toggle \"Break aspect ratio\" false;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize kernel h v image, aspect\n\t\t\t\t\t\t= resize kernel fac fac image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac > yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\tmin_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac < yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\t[h, v] = [\n\t\t\t\t\t\t\tmax_factor, \n\t\t\t\t\t\t\tmin_factor, \n\t\t\t\t\t\t\t[xfac, 1], \n\t\t\t\t\t\t\t[1, yfac]]?which;\n\n\t\t\t\t\t\tfac \n\t\t\t\t\t\t\t= h, v == 1\n\t\t\t\t\t\t\t= v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_within_item = class\n\t\t\tMenuaction \"Size _Within\" \"size to fit within a rectangle\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\t// the rects we size to fit within\n\t\t\t\t_rects = [\n\t\t\t\t\t[2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], \n\t\t\t\t\t[1280, 1024], [1024, 768], [800, 600], [640, 480] \n\t\t\t\t];\n\n\t\t\t\twithin = Option \"Fit within (pixels)\" (\n\t\t\t\t\t[print w ++ \" x \" ++ print h :: [w, h] <- _rects] ++\n\t\t\t\t\t[\"Custom\"]\n\t\t\t\t) 4;\n\t\t\t\tcustom_width = Expression \"Custom width\" 1000;\n\t\t\t\tcustom_height = Expression \"Custom height\" 1000;\n\t\t\t    size = Option \"Page size\" [\n\t\t\t\t\t\"Full page\", \"Half page\", \"Quarter page\" \n\t\t\t\t] 0;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t \t_result\n\t\t\t\t \t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\txdiv = [1, 2, 2]?size;\n\t\t\t\t\tydiv = [1, 1, 2]?size;\n\t\t\t\t\tallrect = _rects ++ [\n\t\t\t\t\t\t[custom_width.expr, custom_height.expr]\n\t\t\t\t\t];\n\t\t\t\t\t[width, height] = allrect?within;\n\n\t\t\t\t\tprocess x\n\t\t\t\t\t\t= resize kernel fac fac x, fac < 1\n\t\t\t\t\t\t= x\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = (width / xdiv) / x.width;\n\t\t\t\t\t\tyfac = (height / ydiv) / x.height;\n\t\t\t\t\t\tfac = min_pair xfac yfac;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_map_item = class\n\t\tMenuaction \"_Map\" \"map an image through a 2D transform image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result\n\t\t\t\t= map_binary trans a b\n\t\t\t{\n\t\t\t\ttrans a b\n\t\t\t\t\t= mapim interp.value in index\n\t\t\t\t{\n\t\t\t\t\t// get the index image first\n\t\t\t\t\t[index, in] = sortc (const is_twocomponent) [a, b];\n\n\t\t\t\t\t// is a two-component image, ie. one band complex, or\n\t\t\t\t\t// two-band non-complex\n\t\t\t\t\tis_twocomponent x\n\t\t\t\t\t\t= is_nonc x || is_c x;\n\t\t\t\t\tis_nonc x\n\t\t\t\t\t\t= has_bands x && get_bands x == 2 && \n\t\t\t\t\t\t\thas_format x && !is_complex_format (get_format x);\n\t\t\t\t\tis_c x\n\t\t\t\t\t\t= has_bands x && get_bands x == 1 && \n\t\t\t\t\t\t\thas_format x && is_complex_format (get_format x);\n\t\t\t\t\tis_complex_format f\n\t\t\t\t\t\t= f == Image_format.COMPLEX || \n\t\t\t\t\t\t\tf == Image_format.DPCOMPLEX;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\" [\"Nearest\", \"Bilinear\"] 1;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_trn {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t[sample', trn, err] = transform_search \n\t\t\t\t\tmax_err max_iter order interp wrap\n\t\t\t\t\tsample reference;\n\t\t\t\ttransformed_image = Image sample';\n\t\t\t\t_trn = Transform trn reference.width reference.height;\n\t\t\t\tfinal_error = err;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\t[i, t] = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tBandwise_item = Image_join_item.Bandwise_item;\n\n    sep1a = Menuseparator;\n\n\tBandand_item = class\n\t\tMenuaction \"Bitwise Band AND\" \"bitwise AND of image bands\" {\n\t\taction x = bandand x;\n\t}\n\n\tBandor_item = class\n\t\tMenuaction \"Bitwise Band OR\" \"bitwise OR of image bands\" {\n\t\taction x = bandor x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldl1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_alpha_item = class \n\tMenupullright \"_Alpha\" \"manipulate image alpha\" {\n\n\tAdd_item = class Menuaction \"_Add\" \"add alpha\" {\n\t\taction x = class\n\t\t\t_result { \n\t\t\t_vislevel = 3;\n\n\t\t\topacity = Expression \"Opacity (255 == solid)\" 255;\n\t\t\t\n\t\t\t_result = x ++ to_real opacity;\n\t\t}\n\t}\n\n\tFlatten_item = class Menuaction \"_Flatten\" \"flatten alpha out of image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbg = Expression \"Background\" 0;\n\n\t\t\t_result = map_unary (flattenimage bg) x;\n\t\t}\n\t}\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract alpha\" {\n\t\taction x \n\t\t\t= map_unary exb x\n\t\t{\n\t\t\texb x = extract_bands (x.bands - 1) 1 x;\n\t\t}\n\t}\n\n\tDrop_item = class Menuaction \"_Drop\" \"drop alpha\" {\n\t\taction x \n\t\t\t= map_unary exb x\n\t\t{\n\t\t\texb x = extract_bands 0 (x.bands - 1) x;\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tPremultiply_item = class Menuaction \"_Premultiply\" \"premultiply alpha\" {\n\t\taction x = premultiply x;\n\t}\n\n\tUnpremultiply_item = class \n\t\tMenuaction \"_Unpremultiply\" \"unpremultiply alpha\" {\n\t\taction x = unpremultiply x; \n\t}\n\n    sep2 = Menuseparator;\n\n\tBlend_alpha_item = Filter_blend_item.Blend_alpha_item;\n\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x \n\t\t= crop x [l, t, w, h]\n\t{\n\t\tfields = [\n\t\t\t[has_left, get_left, 0],\n\t\t\t[has_top, get_top, 0],\n\t\t\t[has_width, get_width, 100],\n\t\t\t[has_height, get_height, 100]\n\t\t];\n\n\t\t[l, t, w, h] \n\t\t\t= map get_default fields\n\t\t{\n\t\t\tget_default line\n\t\t\t\t= get x, has x\n\t\t\t\t= default\n\t\t\t{\n\t\t\t\t[has, get, default] = line;\n\t\t\t}\n\t\t}\n\t}\n\n\tcrop x geo = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tl = Expression \"Crop left\" ((int) (geo?0 + geo?2 / 4));\n\t\tt = Expression \"Crop top\" ((int) (geo?1 + geo?3 / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (geo?2 / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (geo?3 / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t[_a', _b'] = sortc _pred [a, b];\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_draw_item = class \n\tMenupullright \"_Draw\" \"draw lines, circles, rectangles, floods\" {\n\tLine_item = class Menuaction \"_Line\" \"draw line on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tx1 = Expression \"Start x\" 0;\n\t\t\ty1 = Expression \"Start y\" 0;\n\t\t\tx2 = Expression \"End x\" 100;\n\t\t\ty2 = Expression \"End y\" 100;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary line x\n\t\t\t{\n\t\t\t\tline im \n\t\t\t\t\t= draw_line x1 y1 x2 y2 i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tRect_item = class Menuaction \"_Rectangle\" \"draw rectangle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\trx = Expression \"Left\" 50;\n\t\t\try = Expression \"Top\" 50;\n\t\t\trw = Expression \"Width\" 100;\n\t\t\trh = Expression \"Height\" 100;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\tt = Scale \"Line thickness\" 1 50 3;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary rect x\n\t\t\t{\n\t\t\t\trect im \n\t\t\t\t\t= draw_rect_width rx ry rw rh f t i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class Menuaction \"_Circle\" \"draw circle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcx = Expression \"Centre x\" 100;\n\t\t\tcy = Expression \"Centre y\" 100;\n\t\t\tr = Expression \"Radius\" 50;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary circle x\n\t\t\t{\n\t\t\t\tcircle im \n\t\t\t\t\t= draw_circle cx cy r f i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tFlood_item = class Menuaction \"_Flood\" \"flood bounded area of image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsx = Expression \"Start x\" 0;\n\t\t\tsy = Expression \"Start y\" 0;\n\n\t\t\te = Option \"Flood while\" [\n\t\t\t\t\"Not equal to ink\",\n\t\t\t\t\"Equal to start point\"\n\t\t\t] 0;\n\n\t\t\t// pick a default ink that won't flood, if we can\n\t\t\ti \n\t\t\t\t= Expression \"Ink\" default_ink\n\t\t\t{\n\t\t\t\tdefault_ink\n\t\t\t\t\t= [0], ! has_image x\n\t\t\t\t\t= pixel;\n\t\t\t\tpixel = map mean (bandsplit (extract_area sx sy 1 1 im));\n\t\t\t\tim = get_image x;\n\t\t\t}\n\n\t\t\t_result \n\t\t\t\t= map_unary flood x\n\t\t\t{\n\t\t\t\tflood im \n\t\t\t\t\t= draw_flood sx sy i.expr im, e == 0\n\t\t\t\t\t= draw_flood_blob sx sy i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tDraw_scalebar_item = class Menuaction \"_Scale\" \"draw scale bar\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpx = Expression \"Left\" 50;\n\t\t\tpy = Expression \"Top\" 50;\n\t\t\twid = Expression \"Width\" 100;\n\t\t\tthick = Scale \"Line thickness\" 1 50 3;\n\t\t\ttext = String \"Dimension text\" \"50μm\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\tpos = Option \"Position Text\" [\"Above\", \"Below\"] 1;\n\t\t\tvp = Option \"Dimension by\" [\n\t\t\t\t\"Inner Vertical Edge\", \n\t\t\t\t\"Centre of Vertical\", \n\t\t\t\t\"Outer Vertical Edge\"\n\t\t\t] 1;\n            dpi = Expression \"DPI\" 100;\n            ink = Colour \"Lab\" [50,0,0];\n      \n            _result\n                = map_unary process x\n            {\n                process im\n                    = blend (Image scale) ink' im\n                {\n                    // make an ink compatible with the image\n                    ink' = colour_transform_to (get_type im) ink;\n\n                    x = to_real px;\n                    y = to_real py;\n                    w = to_real wid;\n                    d = to_real dpi;\n\n                    t = floor thick;\n\n                    bg = image_new (get_width im) (get_height im) (get_bands im)\n                        (get_format im) (get_coding im) (get_type im) 0 0 0;\n                    draw_block x y w t im =\n                        draw_rect_width x y w t true 1 [255] im;\n                    label = im_text text.value font.value w 1 d;\n                    lw = get_width label;\n                    lh = get_height label;\n                    ly = [y - lh - t, y + 2 * t]?pos;\n                    vx = [\n\t\t\t\t\t\t[x - t, x + w],\n\t\t\t\t\t\t[x - t / 2, x + w - t / 2],\n\t\t\t\t\t\t[x, x + w - t]\n\t\t\t\t\t]?vp;\n\n\t\t\t\t\tscale = (draw_block x y w t @\n\t\t\t\t\t\tdraw_block vx?0 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tdraw_block vx?1 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tinsert_noexpand (x + w / 2 - lw / 2) ly label)\n\t\t\t\t\t\tbg;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise Join\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t// we can't use map_unary since chop-into-tiles returns a group of\n\t\t\t// groups and we want to be able to reassemble that\n\t\t\t// TODO: chop-into-tiles should return an array class which\n\t\t\t// displays as group but does not have the looping behaviour?\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n\n\tArrayFL_item = class\n\t\tMenuaction \"_Array from List\"\n\t\t\t\"join a list of images into a single image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tncol = Number \"Max. Number of Columns\" 1;\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\t\t\tsnake = Toggle \"Reverse the order of every other row\" false; \n\n\t\t\t_l \n\t\t\t\t= split_lines ncol.value x.value, is_Group x\n\t\t\t\t= split_lines ncol.value x;\n\n\t\t\t_l'\n\t\t\t\t= map2 reverse_if_odd [0..] _l, snake\n\t\t\t\t= _l\n\t\t\t{\n\t\t\t\treverse_if_odd n x\n\t\t\t\t\t= reverse x, n % 2 == 1\n\t\t\t\t\t= x;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= (image_set_origin 0 0 @\n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value\n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list _l'));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tNoise_item = class\n\t\tMenupullright \"_Noise\" \"various noise generators\" {\n\t\tGaussian_item = class \n\t\t\tMenuaction \"_Gaussian\" \"make an image of gaussian noise\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t\t_result = Image (gaussnoise nwidth nheight \n\t\t\t\t\tmean.value deviation.value);\n\t\t\t}\n\t\t}\n\n\t\tFractal_item = class \n\t\t\tMenuaction \"_Fractal\" \"make a fractal noise image\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t\t}\n\t\t}\n\n\t\tPerlin_item = class \n\t\t\tMenuaction \"_Perlin\" \"Perlin noise image\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\t\tcell_size = Expression \"Cell size (pixels)\" 8;\n\t\t\t\teight = Toggle \"Eight bit output\" true;\n\n\t\t\t\t_result \n\t\t\t\t\t= 128 * im + 128, eight\n\t\t\t\t\t= im\n\t\t\t\t{\n\t\t\t\t\tim = perlin cell_size nwidth nheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tWorley_item = class \n\t\t\tMenuaction \"_Worley\" \"Worley noise image\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnwidth = Expression \"Image width (pixels)\" 512;\n\t\t\t\tnheight = Expression \"Image height (pixels)\" 512;\n\t\t\t\tcell_size = Expression \"Cell size (pixels)\" 256;\n\n\t\t\t\t_result \n\t\t\t\t\t= worley cell_size nwidth nheight;\n\t\t\t}\n\t\t}\n\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n\tColour_atlas_item = class\n\tMenuaction \"_Colour Atlas\"\n\t\t\"make a grid of patches grouped around a colour\" {\n\t\taction = class \n\t\t\t_result {   \n\t\t\t_vislevel = 3;\n       \n\t\t\tstart = Colour_picker \"Lab\" [50,0,0];\n\t\t\tnstep = Expression \"Number of steps\" 9;\n\t\t\tssize = Expression \"Step size\" 10; \n\t\t\tpsize = Expression \"Patch size\" 32;\n\t\t\tsepsize = Expression \"Separator size\" 4;\n\t\n\t\t\t_result\n\t\t\t\t= colour_transform_to (get_type start) blocks'''\n\t\t\t{\n\t\t\t\tsize = (to_real nstep * 2 + 1) * to_real psize - \n\t\t\t\t\tto_real sepsize;\n\t\t\t\txy = make_xy size size; \n\n\t\t\t\txy_grid = (xy % to_real psize) < \n\t\t\t\t\t(to_real psize - to_real sepsize);\n\t\t\t\tgrid = xy_grid?0 & xy_grid?1;\n\n\t\t\t\tblocks = (int) (to_real ssize * ((int) (xy / to_real psize)));\n\t\t\t\tlab_start = colour_transform_to Image_type.LAB start;\n\t\t\t\tblocks' = blocks - to_real nstep * to_real ssize + \n\t\t\t\t\tVector (tl lab_start.value);\n\t\t\t\tblocks'' = hd lab_start.value ++ Image blocks';\n\t\t\t\tblocks''' \n\t\t\t\t\t= image_set_type Image_type.LAB blocks'', Image grid\n\t\t\t\t\t= 0;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.5/Magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate Magick.def\n   13-Apr-2014 snibgo\n     Put \"new image\" items into sub-menu.\n     New class VirtualPixlBack.\n   17-Apr-2014 snibgo\n     Many small changes.\n     A few new menu options.\n     Created sub-menu for multi-input operations.\n   3-May-2014 jcupitt\n     Put quotes around ( in shadow to help unix\n\n   Last update: 17-Apr-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n*/\n\n// We don't need Noop.\n/*===\nMagick_noop_item = class\n\tMenuaction \"_Noop\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_testPar_item = class\n\tMenuaction \"_TestPar\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"( +clone ) +append \",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/* Removed Read_item and Write_item, much better to use nip2 load/save image.\n * Plus they can load all libMagick formats anyway.\n */\n\n\n// Put \"new image\" items into sub-menu\nMagick_NewImageMenu_item = class\n\tMenupullright \"_New image\" \"make a new image\" {\n\n\tMagick_newcanvas_item = class\n\t\tMenuaction \"_Solid colour\" \"make image of solid colour\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tcolour = Magick.generalcol_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"\\\"canvas:\" ++ colour._flag ++ \"\\\"\", \n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_builtin_item = class\n\t\tMenuaction \"_Built-in image\" \"create a built-in image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbuiltin = Magick.builtin_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tbuiltin._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_gradient_item = class\n\t\tMenuaction \"_Gradient\" \"make a linear gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\ttopColour = Magick.generalcol_widget;\n\t\t\tbottomColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"gradient:\", \n\t\t\t\t\ttopColour._flag, \"-\", bottomColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_hald_item = class\n\t\tMenuaction \"_Hald-clut image\" \"create an identity hald-clut image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torder = Expression \"order\" 8;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"hald:\" ++ print order.expr,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_pattern_item = class\n\t\tMenuaction \"_Pattern\" \"create pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tpattern = Magick.pattern_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tpattern._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_plasma_item = class\n\t\tMenuaction \"_Plasma image\" \"create plasma image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\t// FIXME? ColourA-ColourB.\n\t\t\t// FIXME? Allow plasma:fractal?\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"plasma:\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_radialgradient_item = class\n\t\tMenuaction \"_Radial gradient\" \n\t\t\t\"make a radial gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tinnerColour = Magick.generalcol_widget;\n\t\t\touterColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"radial-gradient:\", \n\t\t\t\t\tinnerColour._flag, \"-\", outerColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n}  // end Magick_NewImageMenu_item\n\n\nMagick_MultiMenu_item = class\n\tMenupullright \"_Multiple inputs\" \"make an image from multiple images\" {\n\n\tMagick_composite_item = class\n\t\tMenuaction \"_Composite\" \"composite two images (without mask)\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag,\n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_compositeMask_item = class\n\t\tMenuaction \"_Composite masked\" \"composite two images (with mask)\" {\n\t\taction x y z = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag, \n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system3 command x y z; \n\t\t}\n\t}\n\n\t// FIXME: other operations like remap that take another image as arguments are:\n\t// mask (pointless?), texture, tile (pointless?)\n\n\t// FIXME: operations that take a filename that isn't an image:\n\t// cdl, profile\n\n\tMagick_clut_item = class\n\t\tMenuaction \"_Clut\" \"replace values using second image as colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// FIXME: uses -intensity \"when mapping greyscale CLUT image to alpha channel if set by -channels\"\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_haldclut_item = class\n\t\tMenuaction \"_Hald clut\" \"replace values using second image as Hald colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-hald-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\n\t// Encipher and decipher: key files can be text or image files.\n\n\tMagick_encipher_item = class\n\t\tMenuaction \"_Encipher/Decipher\" \"encipher or decipher an image image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname = Pathname \"Read key file\" \"\";\n\t\t\tisDecipher = Toggle \"Decipher\" false;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname.value == \"\" then \"\" else (\n\t\t\t\t\t( if isDecipher then \"-decipher \" else \"-encipher \") ++\n\t\t\t\t\t( \"\\\"\" ++ pathname.value ++ \"\\\"\" )\n\t\t\t\t),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_profile_item = class\n\t\tMenuaction \"_Profile\" \"assigns/applies an ICC profile\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname1 = Pathname \"Read profile file\" \"\";\n\t\t\tpathname2 = Pathname \"Read profile file\" \"\";\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname1.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname1.value ++ \"\\\"\"),\n\t\t\t\tif pathname2.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname2.value ++ \"\\\"\"),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_remap_item = class\n\t\tMenuaction \"_Remap\" \"reduce colours to those in another image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-remap\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n}  // end Magick_MultiMenu_item\n\n\nMagick_image_type_item = class\n\tMenuaction \"_Image Type\" \"change image type\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\timagetype = Magick.imagetype_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\timagetype._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nsep2 = Menuseparator;\n\nMagick_alpha_item = class\n\tMenuaction \"_Alpha\" \"add/remove alpha channel\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\talpha = Magick.alpha_widget; \n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\talpha._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_annotate_item = class\n\tMenuaction \"_Annotate\" \"add text annotation\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttext = Magick.text_widget;\n\t\tfont = Magick.Font_widget;\n\t\tgeometry = Magick.AnnotGeometry_widget; \n\t\tgravity = Magick.gravity_widget; \n\t\tforeground = Magick.foreground_widget;\n\t\tundercol = Magick.undercol_widget;\n\t\tantialias = Magick.antialias_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfont._flag,\n\t\t\tantialias._flag,\n\t\t\tgravity._flag,\n\t\t\tforeground._flag,\n\t\t\tundercol._flag,\n\t\t\t\"-annotate\", \n\t\t\tgeometry._flag, \n\t\t\t\"\\\"\" ++ text.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoGamma_item = class\n\tMenuaction \"_AutoGamma\" \"automatic gamma\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-gamma\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoLevel_item = class\n\tMenuaction \"_AutoLevel\" \"automatic level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-level\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_blurSharpMenu_item = class\n\tMenupullright \"_Blur/Sharpen\" \"blur and sharpen\" {\n\n\tMagick_adaptive_blur_item = class\n\t\tMenuaction \"_Adaptive Blur\" \"blur less near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\t// note: adaptive-blur doesn't regard VP.\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-adaptive-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blur_item = class\n\t\tMenuaction \"_Blur\" \"blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_gaussianBlur_item = class\n\t\tMenuaction \"_Gaussian Blur\" \"blur with a Gaussian operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-gaussian-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_motionBlur_item = class\n\t\tMenuaction \"_Motion Blur\" \"simulate motion blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tangle = Scale \"angle\" (-360) 360 0;\n\t\t\tchannels = Magick.ch_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-motion-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_rotationalBlur_item = class\n\t\tMenuaction \"_RotationalBlur\" \"blur around the centre\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-radial-blur\", \n\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_selectiveBlur_item = class\n\t\tMenuaction \"_Selective Blur\" \"blur where contrast is less than or equal to threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-selective-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++  \"+\" ++\n\t\t\t\t\tprint threshold.value ++ \"%%\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMagick_adaptive_sharpen_item = class\n\t\tMenuaction \"_Adaptive Sharpen\" \"sharpen more near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\t\"-adaptive-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_sharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"sharpen\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_unsharpen_item = class\n\t\tMenuaction \"_Unsharp\" \"sharpen with unsharp mask\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tgain = Scale \"Gain\" (-10) 10 1;\n\t\t\tthreshold = Scale \"Threshold\" 0 1 0.05;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-unsharp\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint gain.value ++ \"+\" ++\n\t\t\t\t\tprint threshold.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end BlurSharpMenu_item\n\n\nMagick_border_item = class\n\tMenuaction \"_Border\" \"add border of given colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcompose = Magick.compose_widget;\n\t\twidth = Expression \"Width\" 3;\n\t\tbordercol = Magick.bordercol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag,\n\t\t\tbordercol._flag,\n\t\t\t\"-border\", \n\t\t\tprint width.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_brightCont_item = class\n\tMenuaction \"_Brightness-contrast\" \"adjust the brightness and/or contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbri = Scale \"brightness\" (-100) 100 0;\n\t\tcon = Scale \"contrast\" (-100) 100 0;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-brightness-contrast\", \n\t\t\tprint bri.value ++ \"x\" ++ print con.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// Note: canny requires ImageMagick 6.8.9-0 or later.\n\nMagick_canny_item = class\n\tMenuaction \"_Canny\" \"detect a wide range of edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tlowPc = Scale \"lower percent\" 0 100 10;\n\t\thighPc = Scale \"lower percent\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-canny\", \n\t\t\tconcat [\"\\\"\",\n\t\t\t\tprint radius.value ++ \"x\" ++ \n\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\tprint lowPc.value ++ \"%%+\" ++\n\t\t\t\tprint highPc.value ++ \"%%\" ++ \"\\\"\"\n\t\t\t],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_charcoal_item = class\n\tMenuaction \"_Charcoal\" \"simulate a charcoal drawing\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tfactor = Scale \"factor\" 0 50 1;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-charcoal\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_chop_item = class\n\tMenuaction \"_Chop\" \"remove pixels from the interior\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-chop\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorize_item = class\n\tMenuaction \"_Colorize\" \"colorize by given amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tval = Scale \"value\" 0 100 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-colorize\", \n\t\t\tprint val.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colors_item = class\n\tMenuaction \"_Colors\" \"reduce number of colors\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\t\tquantize = Magick.colorspace_widget;\n\t\tcolors = Expression \"Colours\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-quantize\", quantize._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\tdither._flag,\n\t\t\t\"-colors\", \n\t\t\tprint colors.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: color-matrix?\n\nMagick_colorspace_item = class\n\tMenuaction \"_Colourspace\" \"convert to arbitrary colourspace\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolsp = Magick.colorspace_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-colorspace\",\n\t\t\tcolsp._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorspaceGray_item = class\n\tMenuaction \"_Colourspace gray\" \"convert to gray using given intensity method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-colorspace gray\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrast_item = class\n\tMenuaction \"_Contrast\" \"increase or reduce the contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tisReduce = Toggle \"reduce contrast\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t(if isReduce then \"+\" else \"-\") ++ \"contrast\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrastStretch_item = class\n\tMenuaction \"_Contrast stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-contrast-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: convolve (bias, kernel)\n\nMagick_crop_item = class\n\tMenuaction \"_Crop\" \"cut out a rectangular region\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-crop\",\n\t\t\tgeometry._flag,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_deskew_item = class\n\tMenuaction \"_Deskew\" \"straighten the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\t// FIXME: toggle auto-crop?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-deskew\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_despeckle_item = class\n\tMenuaction \"_Despeckle\" \"reduce the speckles\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-despeckle\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_distort_item = class\n\tMenuaction \"_Distort\" \"distort using a method and arguments\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tdistort = Magick.distort_widget;\n\t\targs = String \"Arguments\" \"1,0\";\n\t\tisPlus = Toggle \"Extend to show entire image\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t(if isPlus then \"+\" else \"-\") ++ \"distort\",\n\t\t\tdistort._flag,\n\t\t\targs.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_draw_item = class\n\tMenuaction \"_Draw\" \"annotate with one or more graphic primitives\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\targs = String \"Arguments\" \"line 0,0 9,9 rectangle 10,10 20,20\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-draw\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_edge_item = class\n\tMenuaction \"_Edge\" \"detect edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-edge\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_emboss_item = class\n\tMenuaction \"_Emboss\" \"emboss\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-emboss\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_enhance_item = class\n\tMenuaction \"_Enhance\" \"enhance a noisy image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-enhance\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_equalize_item = class\n\tMenuaction \"_Equalize\" \"equalize the histogram\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-equalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_evaluate_item = class\n\tMenuaction \"_Evaluate\" \"evaluate an expression on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\toperation = Magick.evaluate_widget;\n\t\tval = Expression \"value\" 5;\n\t\tisPc = Toggle \"Value is percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag, \n\t\t\toperation._flag, \n\t\t\tprint val.expr ++ if isPc then \"%%\" else \"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_extent_item = class\n\tMenuaction \"_Extent\" \"set the image size and offset\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-extent\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_FlipFlopMenu_item = class\n\tMenupullright \"_Flip/flop\" \"flip/flop/transverse/transpose\" {\n\n\tMagick_flip_item = class\n\t\tMenuaction \"_Flip vertically\" \"mirror upside-down\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flip\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_flop_item = class\n\t\tMenuaction \"_Flop horizontally\" \"mirror left-right\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flop\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transpose_item = class\n\t\tMenuaction \"_Transpose\" \"mirror along the top-left to bottom-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transpose +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transverse_item = class\n\t\tMenuaction \"_Transverse\" \"mirror along the bottom-left to top-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transverse +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end Magick_FlipFlopMenu_item\n\n\nMagick_floodfill_item = class\n\tMenuaction \"_Floodfill\" \"recolour neighbours that match\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tfuzz = Magick.fuzz_widget;\n\t\tcoordinate = Magick.coordinate_widget;\n\n\t\t// -draw \"color x,y floodfill\"\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-draw \\\" color\",\n\t\t\tcoordinate._flag,\n\t\t\t\"floodfill \\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_frame_item = class\n\tMenuaction \"_Frame\" \"surround with border or beveled frame\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tborder = Magick.bordercol_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tmatte = Magick.mattecol_widget;\n\t\tgeometry = Magick.FrameGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tborder._flag, \n\t\t\tmatte._flag, \n\t\t\t\"-frame\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_function_item = class\n\tMenuaction \"_Function\" \"evaluate a function on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfunction = Magick.function_widget;\n\t\t// FIXME: explain values; use sensible defaults.\n\t\tvalues = String \"values\" \"0,0,0,0\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-function\", \n\t\t\tfunction._flag, \n\t\t\tvalues.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_fx_item = class\n\tMenuaction \"_Fx\" \"apply a mathematical expression\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\targs = String \"Expression\" \"u*1/2\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\tinterpolate._flag,\n\t\t\tvirtpixback._flag,\n\t\t\t\"-fx\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gamma_item = class\n\tMenuaction \"_Gamma\" \"apply a gamma correction\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tgamma = Magick.gamma_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-gamma\",\n\t\t\tprint gamma.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradient_item = class\n\tMenuaction \"_Gradient\" \"apply a linear gradient\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolourA = Magick.generalcol_widget;\n\t\tcolourB = Magick.generalcol_widget;\n\n\t\tposition = Option \"colourA is at\" [\n\t\t\t\t\"top\", \"bottom\", \n\t\t\t\t\"left\", \"right\", \n\t\t\t\t\"top-left\", \"top-right\", \n\t\t\t\t\"bottom-left\", \"bottom-right\"] 0;\n\t\t_baryArg\n\t\t\t= concat [\"0,0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 0\n\t\t\t= concat [\"0,0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 1\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],0,\", colourB._flag], position.value == 2\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],0,\", colourA._flag], position.value == 3\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourB._flag], position.value == 4\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 5\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 6\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourA._flag], position.value == 7\n\t\t\t= \"dunno\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color barycentric \\\"\" ++ _baryArg ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradientCorn_item = class\n\tMenuaction \"_Gradient corners\" \n\t\t\"apply a bilinear gradient between the corners\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour_top_left = Magick.generalcol_widget;\n\t\tcolour_top_right = Magick.generalcol_widget;\n\t\tcolour_bottom_left = Magick.generalcol_widget;\n\t\tcolour_bottom_right = Magick.generalcol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color bilinear \\\"\" ++\n\t\t\t\t\"0,0,\" ++ colour_top_left._flag ++\n\t\t\t\t\",%%[fx:w-1],0\" ++ colour_top_right._flag ++\n\t\t\t\t\",0,%%[fx:h-1]\" ++ colour_bottom_left._flag ++\n\t\t\t\t\",%%[fx:w-1],%%[fx:h-1]\" ++ colour_bottom_right._flag ++ \"\\\"\",\n\t\t\t\"+depth\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_histogram_item = class\n\tMenuaction \"_Histogram\" \"make a histogram image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-define histogram:unique-colors=false histogram:\" ++\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_implode_item = class\n\tMenuaction \"_Implode\" \"implode pixels about the center\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfactor = Scale \"factor\" 0 20 1;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\t// FIXME: virtual-pixel?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tinterpolate._flag,\n\t\t\t\"-implode\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_level_item = class\n\tMenuaction \"_Level\" \"adjust the level of channels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"black point\" (-100) 200 0;\n\t\twht = Scale \"white point\" (-100) 200 100;\n\t\tgam = Scale \"gamma\" 0 30 1;\n\t\tisPc = Toggle \"Levels are percent\" true;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \",\" ++ \n\t\t\t\tprint wht.value ++ (if isPc then \"%%\" else \"\") ++ \",\" ++ \n\t\t\t\tprint gam.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_levelCols_item = class\n\tMenuaction \"_Level colors\" \"adjust levels to given colours\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcolour_black = Magick.generalcol_widget;\n\t\tcolour_white = Magick.generalcol_widget;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level-colors\",\n\t\t\t\"\\\"\" ++ colour_black._flag ++ \",\" ++ colour_white._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_linearStretch_item = class\n\tMenuaction \"_Linear stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-linear-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_magnify_item = class\n\tMenuaction \"_Magnify\" \"double the size of the image with pixel art scaling\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-magnify\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_modulate_item = class\n\tMenuaction \"_Modulate\" \"modulate brightness, saturation and hue\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmodcolsp = Magick.ModColSp_widget;\n\t\tbright = Scale \"brightness\" 0 200 100;\n\t\tsat = Scale \"saturation\" 0 200 100;\n\t\thue = Scale \"hue\" 0 200 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tmodcolsp._flag,\n\t\t\t\"-modulate\",\n\t\t\tprint bright.value ++ \",\" ++ print sat.value ++ \",\" ++ \n\t\t\t\tprint hue.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_monochrome_item = class\n\tMenuaction \"_Monochrome\" \"transform to black and white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// FIXME: also intensity?\n\n\t\tintensity = Magick.intensity_widget;\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tdither._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\t\"-monochrome\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_morphology_item = class\n\t// See http://www.imagemagick.org/Usage/morphology/\n\tMenuaction \"_Morphology\" \"apply a morphological method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmethod = Magick.morphmeth_widget;\n\t\titer = Expression \"Iterations (-1=repeat until done)\" 1;\n\n\t\tkernel = Magick.kernel_widget;\n\t\t// FIXME: custom kernel eg \"3x1+2+0:1,0,0\"\n\t\t//   width x height + offsx + offsy : {w*h values}\n\t\t//   each value is 0.0 to 1.0 or \"NaN\" or \"-\"\n\n\t\t// kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0\n\t\t// but\n\t\t//   ring takes: radius1, radius2, scale\n\t\t//   rectangle and comet take: width x height + offsx + offsy\n\t\t//   blur takes: radius x sigma\n\t\t// FIXME: for now, simply allow any string input.\n\t\tkernel_arg = String \"Kernel arguments\" \"\";\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-morphology\",\n\t\t\tmethod._flag ++ \":\" ++ print iter.expr, \n\t\t\tkernel._flag ++\n\t\t\t(if kernel_arg.value == \"\" then \"\" else \":\") ++ kernel_arg.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_negate_item = class\n\tMenuaction \"_Negate\" \"negate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-negate\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_addNoise_item = class\n\tMenuaction \"_add Noise\" \"add noise\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tattenuate = Scale \"attenuate\" 0 1.0 1.0;\n\t\tnoise = Magick.noise_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-attenuate\", \n\t\t\tprint attenuate.value,\n\t\t\tnoise._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_normalize_item = class\n\tMenuaction \"_Normalize\" \"normalize\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-normalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_opaque_item = class\n\tMenuaction \"_Opaque\" \"change this colour to the fill colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfill = Magick.foreground_widget;\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfill._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"opaque\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_paint_item = class\n\tMenuaction \"_Paint\" \"simulate an oil painting\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"radius\" 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-paint\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/*=== FIXME Bug; remove for now.\nPolaroid_item = class\n\tMenuaction \"_Polaroid\" \"simulate a polaroid picture\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle\" (-90) 90 20;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-polaroid\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_posterize_item = class\n\tMenuaction \"_Posterize\" \"reduce to (n) levels per channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tlevels = Expression \"levels\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-posterize\",\n\t\t\tprint levels.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_raise_item = class\n\tMenuaction \"_Raise\" \"lighten or darken image edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthk = Expression \"Thickness\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-raise\",\n\t\t\tprint thk.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_resize_item = class\n\tMenuaction \"_Resize\" \"resize to given width and height\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfilter = Magick.filter_widget;\n\t\ttype = Magick.ResizeType_widget;\n\t\twidth = Scale \"Width\" 1 100 10;\n\t\theight = Scale \"Height\" 1 100 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfilter._flag,\n\t\t\t\"-\" ++ type._flag,\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"!\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_roll_item = class\n\tMenuaction \"_Roll\" \"roll an image horizontally or vertically\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trollx = Expression \"X\" 3;\n\t\trolly = Expression \"Y\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-roll\",\n\t\t\t(if rollx.expr >= 0 then \"+\" else \"\") ++ print rollx.expr ++\n\t\t\t(if rolly.expr >= 0 then \"+\" else \"\") ++ print rolly.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_rotate_item = class\n\tMenuaction \"_Rotate\" \"rotate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"+distort\",\n\t\t\t\"SRT\",\n\t\t\tprint angle.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -segment, but cluster-threshold should be percentage of image area.\n\nMagick_sepia_item = class\n\tMenuaction \"_Sepia tone\" \"simulate a sepia-toned photo\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sepia-tone\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shade_item = class\n\tMenuaction \"_Shade\" \"shade with a distant light source\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tazimuth = Scale \"Azimuth (degrees)\" (-360) 360 0;\n\t\televation = Scale \"Elevation (degrees)\" 0 90 45;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shade\",\n\t\t\tprint azimuth.value ++ \"x\" ++ print elevation.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shadow_item = class\n\tMenuaction \"_Shadow\" \"simulate a shadow\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshadowCol = Magick.generalcol_widget;\n\t\topacity = Scale \"Opacity (percent)\" 0 100 75;\n\t\tsigma = Scale \"Sigma\" 0 30 2;\n\t\t// FIXME: make offsets a single widget?\n\t\toffsx = Scale \"X-offset\" (-20) 20 4;\n\t\toffsy = Scale \"Y-offset\" (-20) 20 4;\n\t\tarePc = Toggle \"offsets are percentages\" false;\n\n\t\t// FIXME: raw operation creates page offset, which vips dislikes.\n\t\t// So we take this futher, compositing with source.\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"(\\\" +clone\",\n\t\t\t\"-background\", \"\\\"\" ++ shadowCol._flag ++ \"\\\"\",\n\t\t\t\"-shadow\",\n\t\t\tconcat [\n\t\t\t\t\"\\\"\",\n\t\t\t\tprint opacity.value, \"x\", print sigma.value,\n\t\t\t\t(if offsx.value >= 0 then \"+\" else \"\"), print offsx.value,\n\t\t\t\t(if offsy.value >= 0 then \"+\" else \"\"), print offsy.value,\n\t\t\t\t(if arePc then \"%%\" else \"\"),\n\t\t\t\t\"\\\"\"\n\t\t\t],\n\t\t\t\"\\\")\\\" +swap -background None -layers merge\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shave_item = class\n\tMenuaction \"_Shave\" \"shave pixels from the edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 0 50 10;\n\t\theight = Scale \"Height\" 0 50 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shave\",\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shear_item = class\n\tMenuaction \"_Shear\" \"shear along the x-axis and/or y-axis\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-shear\",\n\t\t\tprint shearX.expr ++ \"x\" ++ print shearY.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sigmoid_item = class\n\tMenuaction \"_Sigmoid\" \"increase or decrease mid-tone contrast sigmoidally\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcontrast = Scale \"contrast\" 0 30 3;\n\t\tmidpoint = Scale \"mid-point (percent)\" 0 100 50;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"sigmoidal-contrast\",\n\t\t\t\"\\\"\" ++ print contrast.value ++ \"x\" ++ \n\t\t\t\tprint midpoint.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sketch_item = class\n\tMenuaction \"_Sketch\" \"simulate a pencil sketch\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tangle = Scale \"angle\" (-360) 360 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sketch\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if angle >= 0 then (\"+\" ++ print angle.value) else \"\"),\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_solarize_item = class\n\tMenuaction \"_Solarize\" \"negate all pixels above a threshold level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-solarize\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -sparse-color needs abitrary list of {x,y,colour}.\n\nMagick_splice_item = class\n\tMenuaction \"_Splice\" \"splice a colour into the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-splice\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_spread_item = class\n\tMenuaction \"_Spread\" \"displace pixels by random amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tamount = Expression \"Amount (pixels)\" 5;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"-spread\",\n\t\t\tprint amount.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_statistic_item = class\n\tMenuaction \"_Statistic\" \"replace each pixel with statistic from neighbourhood\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width\" 5;\n\t\theight = Expression \"Height\" 5;\n\t\tstatisticType = Magick.StatType_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-statistic\", \n\t\t\tstatisticType._flag, \n\t\t\tprint width.expr ++ \"x\" ++ print height.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_swirl_item = class\n\tMenuaction \"_Swirl\" \"swirl around the centre\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Magick.angle_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-swirl\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_thresholdMenu_item = class\n\tMenupullright \"_Threshold\" \"make black or white\" {\n\n\tMagick_threshold_item = class\n\t\tMenuaction \"_Threshold\" \"apply black/white threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-threshold\", \n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blackThreshold_item = class\n\t\tMenuaction \"_Black threshold\" \"where below threshold set to black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-black-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_whiteThreshold_item = class\n\t\tMenuaction \"_White threshold\" \"where above threshold set to white\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-white-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_latThreshold_item = class\n\t\tMenuaction \"_Local Adaptive Threshold\" \"where above average plus offset set to white, otherwise black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twidth = Expression \"Width\" 10;\n\t\t\theight = Expression \"Height\" 10;\n\t\t\toffset = Scale \"Offset (percent)\" (-100) 100 0;\n\t\t\t// note: \"-lat\" doesn't respond to channels\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-lat\",\n\t\t\t\tconcat [\"\\\"\", print width.expr, \"x\", print height.expr, \n\t\t\t\t\t(if offset.value >= 0 then \"+\" else \"\"), print offset.value,\n\t\t\t\t\t\"%%\\\"\"\n\t\t\t\t],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_randThreshold_item = class\n\t\tMenuaction \"_Random Threshold\" \"between specified limits, apply random threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tlow = Scale \"Low threshold\" 0 100 10;\n\t\t\thigh = Scale \"High threshold\" 0 100 90;\n\t\t\tisPc = Toggle \"Thresholds are percent\" true;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-random-threshold\", \n\t\t\t\t\"\\\"\" ++ print low.value ++ \"x\" ++ print high.value ++\n\t\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end ThresholdMenu_item\n\n\n// Note: alternatives include:\n// convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif\n\nMagick_tile_item = class\n\tMenuaction \"_Tile\" \"fill given size with tiled image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tsize = Magick.Size_widget;\n\n\t\tcommand = Magick.command [\n\t\t\tsize._flag,\n\t\t\t\"tile:\" ++ \"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_tint_item = class\n\tMenuaction \"_Tint\" \"apply a tint\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tamount = Scale \"amount (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-tint\",\n\t\t\t// snibgo note: although the amount is a percentage, it doesn't need \"%\" character.\n\t\t\tprint amount.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_transparent_item = class\n\tMenuaction \"_Transparent\" \"make this colour transparent\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"transparent\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_trim_item = class\n\tMenuaction \"_Trim\" \"trims away border\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfuzz = Magick.fuzz_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-trim +repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_uniqueCols_item = class\n\tMenuaction \"_Unique colours\" \"discard all but one of any pixel color\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-unique-colors\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_vignette_item = class\n\tMenuaction \"_Vignette\" \"soften the edges in vignette style\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\trx = Scale \"Rolloff x (percent)\" 0 100 10;\n\t\try = Scale \"Rolloff y (percent)\" 0 100 10;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-vignette\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if rx.value >= 0 then \"+\" else \"\") ++ print rx.value ++\n\t\t\t\t(if ry.value >= 0 then \"+\" else \"\") ++ print ry.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_wave_item = class\n\tMenuaction \"_Wave\" \"shear the columns into a sine wave\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tamplitude = Scale \"Amplitude (pixels)\" 0 100 10;\n\t\twavelength = Scale \"Wavelength (pixels)\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-wave\",\n\t\t\tprint amplitude.value ++ \"x\" ++ print wavelength.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\n"
  },
  {
    "path": "share/nip2/compat/8.5/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/8.5\n\nstart_DATA = \\\n\tMath.def \\\n\tImage.def \\\n\tMagick.def \\\n\tColour.def \\\n\tTasks.def \\\n\tObject.def \\\n\tFilter.def \\\n\tMatrix.def \\\n\tWidgets.def \\\n\tHistogram.def \\\n\tPreferences.ws \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_convert.def \\\n\t_generate.def \\\n\t_list.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\t_Object.def \\\n\t_magick.def \\\n\t_types.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/8.5/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_AND\" \"bitwise AND of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_OR\" \"bitwise OR of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"_XOR\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_NOT\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBandand_item = Image_band_item.Bandand_item; \n\n\tBandor_item = Image_band_item.Bandor_item; \n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tDifference_item = class \n\t\tMenuaction \"_Difference\" \"difference of two lists\" {\n\t\taction a b = map_binary difference a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tValue_item = class \n\t\tMenuaction \"_Value\" \"value of point in object\" {\n\t\taction a = class _result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tposition = Expression \"Coordinate\" (0, 0);\n\t\n\t\t\t_result = map_binary point position.expr a;\n\t\t}\n\t}\n\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tSkew_item = class \n\t\tMenuaction \"S_kew\" \"skew of image or list or vector\" {\n\t\taction a = map_unary skew a;\n\t}\n\n\tKurtosis_item = class \n\t\tMenuaction \"Kurtosis\" \"kurtosis of image or list or vector\" {\n\t\taction a = map_unary kurtosis a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \n\t\t\t\"position of centre of gravity of histogram\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = linreg xes yes;\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = linregw xes yes devs;\n\t}\n\n\tCluster_item = class \n\t\tMenuaction \"_Cluster\" \"cluster a list of numbers\" {\n\t\taction l = class {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tthresh = Expression \"Threshold\" 10;\n\t\n\t\t\t[_r, _w] = cluster thresh.expr l;\n\t\n\t\t\tresult = _r;\n\t\t\tweights = _w;\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.5/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_identity_item = class \n\t\tMenuaction \"_Identity\" \"make an identity matrix\" {\n\t\taction = identity (identity_matrix 5);\n\t\t\n\t\tidentity v = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix (identity_matrix (to_real s)), to_real s != len v;\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = identity value;\n\t\t}\n\t}\n\n\tMatrix_series_item = class \n\t\tMenuaction \"_Series\" \"make a series\" {\n\t\taction = series (mkseries 0 1 5);\n\n\t\tmkseries s t e \n\t\t\t= transpose [[to_real s, to_real s + to_real t .. to_real e]];\n\n\t\tseries v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t_s = v?0?0;\n\t\t\t_t = v?1?0 - v?0?0;\n\t\t\t_e = (last v)?0;\n\n\t\t\ts = Expression \"Start value\" _s;\n\t\t\tt = Expression \"Step by\" _t;\n\t\t\te = Expression \"End value\" _e;\n\n\t\t\t_result \n\t\t\t\t= Matrix (mkseries s t e), \n\t\t\t\t\t\tto_real s != _s || to_real t != _t || to_real e != _e\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = series value;\n\t\t}\n\t}\n\n\tMatrix_square_item = class \n\t\tMenuaction \"_Square\" \"make a square matrix\" {\n\t\taction = square (mksquare 5);\n\n\t\tmksquare s = replicate s (take s [1, 1 ..]);\n\n\t\tsquare v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == to_real s\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mksquare (to_real s); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = square value;\n\t\t}\n\t}\n\n\tMatrix_circular_item = class \n\t\tMenuaction \"_Circular\" \"make a circular matrix\" {\n\t\taction = circle (mkcircle 3);\n\n\t\tmkcircle r\n\t\t\t\t= map2 (map2 pyth) xes yes\n\t\t{\n\t\t\tline = [-r .. r];\n\t\t\txes = replicate (2 * r + 1) line;\n\t\t\tyes = transpose xes;\n\t\t\tpyth a b \n\t\t\t\t\t= 1, (a**2 + b**2) ** 0.5 <= r\n\t\t\t\t\t= 0;\n\t\t}\n\n\t\tcircle v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tr = Expression \"Radius\" ((len v - 1) / 2);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mkcircle (to_real r); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = circle value;\n\t\t}\n\t}\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\nMatrix_sort_item = class \n\tMenuaction \"_Sort\" \"sort by column or row\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\to = Option (_ \"Orientation\") [\n\t\t\t_ \"Sort by column\",\n\t\t\t_ \"Sort by row\"\n\t\t] 0;\n\t\ti = Expression (_ \"Sort on index\") 0;\n\t\td = Option (_ \"Direction\") [\n\t\t\t_ \"Ascending\",\n\t\t\t_ \"Descending\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary sort x\n\t\t{\n\t\t\tidx = to_real i;\n\t\t\tpred a b \n\t\t\t\t= a?idx <= b?idx, d == 0\n\t\t\t\t= a?idx >= b?idx;\n\t\t\tsort x\n\t\t\t\t= (x.Matrix_base @ sortc pred) x.value,\n\t\t\t\t\to == 0\n\t\t\t\t= (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value;\n\t\t}\n\t}\n}\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ \n\t\t\t\t\trange;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.5/Object.def",
    "content": "Object_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nObject_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nObject_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nObject_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nObject_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.5/Preferences.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"680\" window_height=\"800\" filename=\"$VIPSHOME/share/$PACKAGE/start/Preferences.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"100\" lpane_open=\"false\" rpane_position=\"400\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"Preferences\">\n    <Column x=\"0\" y=\"3067\" open=\"false\" selected=\"false\" sform=\"false\" next=\"99\" name=\"B\" caption=\"Interface column -- don't touch this!\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"CSV_SEPARATOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"O1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PRINT_CARTIESIAN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F10.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"USE_GRAPHICSMAGICK\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D45.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_PANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"237\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"788\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"700\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"100\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RELOAD\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D42.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_STATUSBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR_STYLE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MATRIX_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_RECOMP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"N2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_MAX_UNDO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[-1,0,1,5,10]?N1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_FONT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"N4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_INTERLACE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_LINELENGTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D41.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A6.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE_FILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PPM_MODE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"G1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_LAYOUT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C16.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C18.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_MULTI_RES\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_FORMAT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_PREDICTOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_BIGTIFF\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_START\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D25.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_SEARCH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D2.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_TMP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_SLIDER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D28.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_REGION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D29.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_AUTO_WS_SAVE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D30.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_DISPLAY_LED\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLKITBROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_MAX_HEAP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D38.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PIN_FILESEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_STATUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CONVERSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_RULERS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CROSSHAIR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL_HQ\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E21.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_TRACE_FUNCTIONS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"H1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_DEVICE\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CHANNEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_BRIGHTNESS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_COLOUR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CONTRAST\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_HUE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_FRAMES\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J13.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_MONO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J14.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_LEFT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_TOP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_ASPECT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_MAX_BLEND_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_REFINE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_WINDOW_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_OBJECT_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_BALANCE_GAMMA\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"680\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER_REMOTE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"POPUP_NEW_ROWS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_HISTORY_MAX\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D43.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_CPUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D44.value\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2831\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"I\" caption=\"Mosaic defaults\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Maximum blend width&quot; 0 100 10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Refine tie-points&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search windows this size&quot; 30\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search for objects this size&quot; 10\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Image gamma for mosaic balance&quot; 1 3 1.6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2495\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"J\" caption=\"Video for linux\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"J2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;Device&quot; &quot;/dev/video&quot;\"/>\n            <Pathname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Channel&quot; [&quot;TV&quot;, &quot;Composite 1&quot;, &quot;Composite 2&quot;, &quot;Composite 3&quot;] 1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Brightness&quot; 0 32767 23000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Colour&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Contrast&quot; 0 32767 27000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Hue&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Number of frames to average&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Grab monochrome&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2208\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"K\" caption=\"General video capture\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"K1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Crop video: \" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Crop video&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop left&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop top&quot; 6\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number  &quot;Crop width&quot; 747\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop height&quot; 570\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Aspect ratio (stretch vertically\\nby this much)&quot; 1.202\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2072\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"M\" caption=\"PNG save options\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"M1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Compression&quot; (map print [0..9]) 6\"/>\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Interlace&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1970\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"G\" caption=\"PPM/PGM/PBM save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"PPM mode\" labelsn=\"2\" labels0=\"Binary\" labels1=\"ASCII\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Mode&quot; [&quot;Binary&quot;, &quot;ASCII&quot;] 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1620\" open=\"true\" selected=\"true\" sform=\"false\" next=\"27\" name=\"C\" caption=\"TIFF save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Compression&quot; [&quot;None&quot;, &quot;LZW&quot;, &quot;Zip (deflate)&quot;, &quot;PACKBITS&quot;, &quot;JPEG&quot;, &quot;CCITTFAX4&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;JPEG quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Deflate/LZW predictor&quot; [&quot;None&quot;,&quot;Horizontal difference&quot;,&quot;Floating-point&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Layout\" labelsn=\"2\" labels0=\"Strip\" labels1=\"Tile\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Layout&quot; [&quot;Strip&quot;, &quot;Tile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile width&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile height&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Multi-res&quot; [&quot;Single image&quot;, &quot;Image pyramid&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Format&quot; [&quot;No truncation&quot;,&quot;Save 1 band 8 bit images as 1 bit&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Save as BigTIFF&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1518\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"O\" caption=\"CSV save\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"String &quot;Separator character&quot; &quot;\\t&quot;\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1348\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"A\" caption=\"JPEG save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;ICC profile&quot; [&quot;Use image profile, if any&quot;, &quot;Embed profile from file&quot;, &quot;Don't attach a profile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Pathname/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;ICC profile file&quot; &quot;$VIPSHOME/share/nip2/data/sRGB.icm&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1144\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"F\" caption=\"Widgets\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Pin up file requestors&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Main window toolbar&quot; [&quot;Default style&quot;, &quot;Icon only&quot;, &quot;Text only&quot;, &quot;Icon and text&quot;, &quot;Icon and text to right&quot;] 0\"/>\n            <Option caption=\"Main window toolbar\" labelsn=\"5\" labels0=\"Default style\" labels1=\"Icon only\" labels2=\"Text only\" labels3=\"Icon and text\" labels4=\"Icon and text to right\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display LEDs in workspace&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display complex numbers as coordinates&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1044\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"H\" caption=\"Debug options\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Disassemble functions\" value=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;untitled&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"906\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"L\" caption=\"Help browser\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"L2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Command to start browser&quot; &quot;firefox&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Go-to-page argument&quot; &quot;-remote 'openURL(%s)'&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"734\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"N\" caption=\"Paintbox \">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Max undo steps\" labelsn=\"5\" labels0=\"Unlimited\" labels1=\"None\" labels2=\"1\" labels3=\"5\" labels4=\"10\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Max undo steps&quot; [&quot;Unlimited&quot;, &quot;None&quot;, &quot;1&quot;, &quot;5&quot;, &quot;10&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Fontname &quot;Default paintbox font&quot; &quot;Sans 12&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Fontname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update during paint&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"458\" open=\"true\" selected=\"false\" sform=\"false\" next=\"27\" name=\"E\" caption=\"Image display\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"E20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use crosshair cursor in image windows&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Thumbnail size&quot; 64\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;High-quality thumbnails&quot; false\"/>\n            <Toggle/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window width&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window height&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto image window pop up&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"46\" name=\"D\" caption=\"Calculation\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Data path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;data&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;data&quot;], &quot;.&quot;]\"/>\n            <Expression caption=\"Data path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Temporary files&quot; (path_relative [&quot;$SAVEDIR&quot;, &quot;tmp&quot;])\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Start path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;start&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;start&quot;]]\"/>\n            <Expression caption=\"Start path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D28\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update sliders during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update sliders during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D29\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update regions during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update regions during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D30\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto workspace save&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D42\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto-reload on file change&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D41\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Text display length (characters)&quot; 80\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D38\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Heap size (per workspace)&quot; 600000\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D43\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of VIPS functions to memoise&quot; 20000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D44\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of CPUs to use (0 for autodetect)&quot; 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D45\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use GraphicsMagick for Magick menu&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/compat/8.5/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\n\tCsv_import_item = class\n\t\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tstart_line = Expression \"Start at line\" 1;\n\t\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_csv2vips filename)\n\t\t\t{\n\t\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\t\tescape x \n\t\t\t\t\t= foldr prefix [] x\n\t\t\t\t{\n\t\t\t\t\tprefix x l\n\t\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t\t= x : l;\n\t\t\t\t}\n\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tRaw_import_item = class\n\t\tMenuaction \"_Raw Import\" \"read a file of binary values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tacross = Expression \"Pixels across\" 100;\n\t\t\tdown = Expression \"Pixels down\" 100;\n\t\t\tbytes = Expression \"Bytes per pixel\" 3;\n\t\t\tskip = Expression \"Skip over initial bytes\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_binfile path.value \n\t\t\t\t\tacross.expr down.expr bytes.expr skip.expr)\n\t\t\t{\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// interpret Analyze header for layout and calibration\n\tAnalyze7_header_item = class\n\t\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\t\"examine the Analyze header and set layout and value\" {\n\t\taction x \n\t\t\t= x'''\n\t\t{\n\t\t\t// read bits of header\n\t\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\t\tdim0 = dim 0 x;\n\t\t\tdim1 = dim 1 x;\n\t\t\tdim2 = dim 2 x;\n\t\t\tdim3 = dim 3 x;\n\t\t\tdim4 = dim 4 x;\n\t\t\tdim5 = dim 5 x;\n\t\t\tdim6 = dim 6 x;\n\t\t\tdim7 = dim 7 x;\n\t\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\t\n\t\t\t// oops, now a nop\n\t\t\tx' = x;\n\t\n\t\t\t// lay out higher dimensions width-ways\n\t\t\tx'' \n\t\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\t\tdim0 == 7\n\t\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\t\n\t\t\t// multiply by scale factor to get kBeq\n\t\t\tx''' = x'' * (cal_max / glmax);\n\t\t}\n\t}\n\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\t[image, patch] = sortc larger [a, b];\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n\t\t\tsample = measure_draw 6 4 (to_real measure) image;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\tmode = Option \"Input LUT\" [\n\t\t\t\t\"Linearize from chart greyscale\",\n\t\t\t\t\"Fit intercept from chart greyscale\",\n\t\t\t\t\"Linear input, set brightness from chart\",\n\t\t\t\t\"Linear input\"\n\t\t\t] 0;\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = measure_sample 6 4 (to_real measure) image;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb \n\t\t\t\t= Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0\n\t\t\t\t= Matrix [0: intercepts, replicate (_camera.width + 1) 1], \n\t\t\t\t\tmode == 1\n\t\t\t\t= Matrix [[0, 0], [1, 1]]\n\t\t\t{\n\t\t\t\tintercepts = [(linreg _true_grey_Y' cam).intercept :: \n\t\t\t\t\tcam <- transpose _camera_grey'];\n\t\t\t}\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\t// plot from 0 explicitly so we see the effect of mode1 (intercept\n\t\t\t// from greyscale)\n\t\t\tlinearising_lut = Plot [$ymin => 0] _linear_lut;\n\n\t\t\t// map an image though the lineariser\n\t\t\tlinear x\n\t\t\t\t= hist_map linearising_lut.value x, mode == 0 || mode == 1\n\t\t\t\t= x;\n\n\t\t\t// map the chart measurements though the lineariser\n\t\t\t_camera' = (to_matrix @ linear @ to_image) _camera;\n\n\t\t\t// solve for RGB -> XYZ\n\t\t\t// normalise: the 2nd row is what makes Y, so divide by that to\n\t\t\t// get Y in 0-1.\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\t_full_M = transpose (_pinv * (transpose _camera' * _true_XYZ));\n\t\t\tM = _full_M / scale;\n\t\t\tscale = sum _full_M.value?1;\n\n\t\t\t// now turn the camera to LAB and calculate dE76\n\t\t\t_camera'' = (to_matrix @ \n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @ \n\t\t\t\trecomb M @ \n\t\t\t\tmultiply scale @\n\t\t\t\tto_image) _camera';\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tavg_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0 && i < len macbeth_names\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\n\t\t\t// normalise brightness ... in linear mode, we optionally don't\n\t\t\t// set the brightness from the Macbeth chart\n\t\t\tnorm x \n\t\t\t\t= x * scale, mode != 3\n\t\t\t\t= x;\n\n\t\t\t// convert RGB camera to Lab\n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tnorm @\n\t\t\t\trecomb M @\n\t\t\t\tcast_float @\n\t\t\t\tlinear) image.value;\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b = class\n\t\t\t(map_binary process a b) {\n\t\t\tprocess a b\n\t\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t\t{\n\t\t\t\t// the name of the calib object we need\n\t\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t\t// get the Calibrate_chart arg first\n\t\t\t\t[image, calib] = sortc (const (is_instanceof calib_name)) \n\t\t\t\t\t[a, b];\n\n\t\t\t\tresult = (Image @\n\t\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\t\tcalib.norm @\n\t\t\t\t\trecomb calib.M @\n\t\t\t\t\tcast_float @\n\t\t\t\t\tcalib.linear) image.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [$style => style.value] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\t!is_list_len 2 images\n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = all (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize Kernel_linear xfactor yfactor scale_im;\n\t\t\t_offset_im = resize Kernel_linear xfactor yfactor offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.5/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.5/_Object.def",
    "content": "/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0|1|2|3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \n\tjoin_sep \"|\" Image_type.colour_spaces.names];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide|VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad properties for \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"where\" ++ \"\\n\" ++ arg_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make arg type notes\n\targ_types = join_sep \"\\n\" (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"\\n\" ++ _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = join_sep \"\\n\" all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if those fail as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if that fails as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary'_function op a b\n\t= matches1?0, matches1 != []\n\t= matches2?0, op.symmetric && matches2 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0, matches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t// these should always be defined\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x = oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x = oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op = oo_unary_function (oo_unary_lookup op) this;\n\n\too_binary_table op x = [];\n\too_unary_table op = [];\n}\n"
  },
  {
    "path": "share/nip2/compat/8.5/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make a Vector ... works for Vector/Image/Real, plus image/real\n */\nto_vector x\n\t= to_vector x.expr, is_Expression x\n\t= x, is_Vector x\n\t= oo_unary_function to_vector_op x, is_class x\n\t= tov x\n{\n\tto_vector_op = Operator \"to_vector\" tov Operator_type.COMPOUND false;\n\n\ttov x\n\t\t= Vector (itov x), is_image x\n\t\t= Vector [x], is_real x\n\t\t= Vector x, is_real_list x\n\t\t= Vector x?0, is_matrix x && len x == 1\n\t\t= Vector (transpose x)?0, is_matrix x && len x?0 == 1\n\t\t= error (_ \"bad arguments to \" ++ \"to_vector\");\n\n\titov i\n\t\t= v, is_image i \n\t\t= error (_ \"not image\")\n\t{\n\t\tm = im_vips2mask ((double) i);\n\t\tv \n\t\t\t= m.value?0, m.height == 1\n\t\t\t= (transpose m.value)?0, m.width == 1\n\t\t\t= error (_ \"image is not 1xN or Nx1\");\n\t}\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= Image x.value, is_Plot x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n// like to_image, but we do 1x1 pixel + x, then embed it up\n// always make an unwrapped image for speed ... this gets used by ifthenelse\n// and stuff like that\n// format can be NULL, meaning set format from x\nto_image_size width height bands format x\n\t= x, is_image x\n\t= x.value, is_Image x\n\t= im''\n{\n\t// we want x to set the target format if we don't have one, so we\n\t// can't use image_new\n\tim = im_black 1 1 bands + x;\n\tim'\n\t\t= clip2fmt format im, format != NULL\n\t\t= im;\n\tim'' = embed 1 0 0 width height im';\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && is_list_len 3 x\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\nto_int x = (int) (to_real x);\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The outermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x \n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), !is_list_len 2 parts \n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, !is_list_len 4 parts \n\t= sign * (abs ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", \n\t\tmember \".0123456789\",\n\t\tmember \"eE\", \n\t\tmember \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tsign \n\t\t= 1, ipart >= 0\n\t\t= -1;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), !is_list_len 5 parts \n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t$D93 => D93_whitepoint,\n\t$D75 => D75_whitepoint,\n\t$D65 => D65_whitepoint,\n\t$D55 => D55_whitepoint,\n\t$D50 => D50_whitepoint,\n\t$A => A_whitepoint,\n\t$B => B_whitepoint,\n\t$C => C_whitepoint,\n\t$E => E_whitepoint,\n\t$D3250 => D3250_whitepoint\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, image_set_type GREY16 @ im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\t[RGB16, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l = join_sep path_separator l;\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 > 1 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n/* Return $PATH, reformatted as [[\"comp1\", \"comp2\"], [\"comp1\", \"comp2\"] ..]\n */\nsystem_search_path\n\t= [vipsbin] ++\n\t\tmap path_parse (split (equal path_sep) (expand \"$PATH\"))\n{\n\t/* On some platforms we ship vips with a few extra progs. Search\n \t * $VIPSHOME/bin first.\n\t */\n\tvipsbin = path_parse (expand \"$VIPSHOME\") ++ [\"bin\"];\n\n\tpath_sep\n\t\t= ':', expand \"$SEP\" == \"/\"\n\t\t= ';';\n}\n\n/* Search $PATH for the first occurence of name, or \"\". \n */\nsearch_for name\n\t= hits?0, hits != []\n\t= \"\"\n{\n\texe_name = name ++ expand \"$EXEEXT\";\n\tform_path p = path_absolute (p ++ [exe_name]);\n\tpaths = map form_path system_search_path;\n\thits = dropwhile (equal []) (map search paths);\n}\n\n/* Search $PATH for the first occurence of name, error on failure. \n */\nsearch_for_error name\n\t= path, path != \"\"\n\t= error (exe_name ++ \" not found on your search path. \" ++\n\t\t\"Check you have installed the program and it is on your PATH.\")\n{\n\texe_name = name ++ expand \"$EXEEXT\";\n\tpath = search_for name;\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.5/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= embed 1 0 0 w h im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black 1 1 (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\nmkim options x y b\n    = Image (image_new x y b\n        (opt $format) (opt $coding) (opt $type)\n        (opt $pixel)\n        (opt $xoffset) (opt $yoffset))\n{\n    opt = get_option options [\n        $format => Image_format.UCHAR,\n        $coding => Image_coding.NOCODING,\n        $type => Image_type.sRGB,\n        $pixel => 0,\n        $xoffset => 0,\n        $yoffset => 0\n    ];\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = im_gauss_imask_sep (radius / 3) 0.2;\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n/* Make a colour from a temperature.\n */\ncolour_from_temp T\n\t= error (_ \"T out of range\"), T < 1667 || T > 25000\n\t= Colour \"Yxy\" [50, x, y]\n{\n\t// Kim et all approximation\n\t// see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation\n\tx\n\t\t= -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 +\n\t\t\t0.8776956 * 10 ** 3 / T + 0.179910, T < 4000\n\t\t= -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 +\n\t\t\t0.2226347 * 10 ** 3 / T + 0.240390;\n\n\ty \n\t\t= -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + \n\t\t\t2.18555832 * x - 0.20219638, T < 2222\n\t\t= -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + \n\t\t\t2.09137015 * x - 0.16748867, T < 4000\n\t\t=  3.0817580 * x ** 3 - 5.87338670 * x ** 2 +\n\t\t\t3.75112997 * x - 0.37001483;\n}\n\ntemp_from_colour z\n\t= T\n{\n\tc = colour_transform_to Image_type.YXY (to_colour z);\n\tx = c.value?1;\n\ty = c.value?2;\n\n\t// McCamy's approximation, see eg. \n\t// http://en.wikipedia.org/wiki/Color_temperature#Approximation\n\n\txe = 0.332;\n\tye = 0.1858;\n\tn = (x - xe) / (y - ye);\n\tT = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33;\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.5/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 1;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" \n\t] 4;\n\n\tcontrol_selection mask im no\n\t\t= [\n\t\t\tif mask then im * 1.2 else im * 1,\n\t\t\tif mask then im * 0.8 else im * 1,\n\t\t\tif mask then 0 else im,\n\t\t\tif mask then 255 else im,\n\t\t\tif mask then im else 0,\n\t\t\tif mask then im else 255,\n\t\t\tmask\n\t\t]?no;\n\n\tRectangle = class\n        Menuaction \"_Rectangle\"\n            \"use an Arrow or Region x to define a rectangle\"\n        {\n        action x = class\n            _result {\n            _vislevel = 3;\n\n            control = _control;   \n\n            _result = control_selection mask im control\n                  {\n                \tim = x.image;\n                \tmask = Image m\n                    {\n\t\t\t\t\t\trx     \n\t\t\t\t\t\t\t= x.region_rect, is_Region x\n\t\t\t\t\t\t\t= x;\n\t\t\t\t\t\tb     = image_new im.width im.height 1 0 0 1 0 0 0;\n\t\t\t\t\t\tw     = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0;\n\t\t\t\t\t\tm     = insert_noexpand rx.nleft rx.ntop w b; \n                     }\n                   }\n            }\n        }\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = get_image a;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = get_image ((pt_list.value)?0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tSegment_item = class\n\t\tMenuaction \"_Segment\" \"break image into disjoint regions\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsegments\n\t\t\t\t= Expression \"Number of disjoint regions\" \n\t\t\t\t\t(map_unary (get_header \"n-segments\") _result);\n\n\t\t\t_result = map_unary segment x;\n\t\t}\n\t}\n\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize Kernel_linear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize Kernel_linear f1 1 b1\n\t\t\t\t\t{b1 = resize Kernel_linear 1 f2 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/8.5/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = Image (get_image line);\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = Image (get_image (pt_l?0));\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t};\n\nMount_options _ctype _ppcm = class \n  {\n  _vislevel = 3;\n  apply = Toggle \"Apply mount options\" false;\n  ls = Expression \"Lower mount section bigger by (cm)\" 0;\n  mount_colour = Colour _ctype [0, 0, 0];\n  _los = ls.expr * _ppcm;\n  };\n\nFrame_variables comp = class\n  {\n  _vislevel = 3;\n\n  scale_factor = Expression \"scale the size of the frame by\" 1;\n\n  /* These sliders define the fraction of the frames width or height is extracted\n   * to produce each of the particular regions.\n   */\n  corner_section = Scale \"Corner section\" 0.1 1 0.5;\n  edge_section = Scale \"Edge section\" 0.1 1 0.2, comp > 0\n\t\t\t\t  = \"Only required for complex frames\";\n  middle_section = Scale \"Middle section\" 0.1 1 0.2;\n  blend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n  option = Toggle \"Use mirror of left-side to make right\" true;\n  };\n\n"
  },
  {
    "path": "share/nip2/compat/8.5/_list.def",
    "content": "/* any l: or all the elements of list l together\n *\n * any (map (equal 0) list) == true, if any element of list is zero.\n * any :: [bool] -> bool\n */\nany = foldr logical_or false;\n\n/* all l: and all the elements of list l together\n *\n * all (map (==0) list) == true, if every element of list is zero.\n * all :: [bool] -> bool\n */\nall = foldr logical_and true;\n\n/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* delete eq x l: delete the first x from l\n *\n * delete equal 'b' \"abcdb\" == \"acdb\"\n * delete :: (* -> bool) -> * -> [*] -> [*]\n */\ndelete eq a l\n\t= [], l == []\n\t= y, eq a b\n\t= b : delete eq a y\n{\n\tb:y = l;\n}\n\n/* difference eq a b: delete b from a\n *\n * difference equal \"asdf\" \"ad\" == \"sf\"\n * difference :: (* -> bool) -> [*] -> [*] -> [*]\n */\ndifference = foldl @ converse @ delete;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn x, fn a\n\t= l\n{\n\ta:x = l;\n}\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* flatten x: flatten a list of lists of things into a simple list\n *\n * flatten :: [[*]] -> [*]\n */\nflatten x\n\t= foldr flat [] x, is_list x\n\t= x\n{\n\tflat x sofar\n\t\t= foldr flat sofar x, is_list x\n\t\t= x : sofar;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st x) xs\n{\n\tx:xs = l;\n}\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn x xs\n{\n\tx:xs = l;\n}\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn x (foldr fn st xs)\n{\n\tx:xs = l;\n}\n\n/* foldr1 fn l: like foldr, but use the last element as the start value\n *\n * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= x, xs == []\n\t= fn x (foldr1 fn xs)\n{\n\tx:xs = l;\n}\n\n/* Search a list for an element, returning its index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn x\n\t\t= search xs (n + 1)\n\t\t{\n\t\t\tx:xs = l;\n\t\t}\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= x : init xs\n{\n\tx:xs = l;\n}\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* join_sep sep l: join a list with a separator\n *\n * join_sep \", \" (map print [1 .. 4]) == \"1, 2, 3, 4\"\n * join_sep :: [*] -> [[*]] -> [*]\n */\njoin_sep sep l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ sep ++ b;\n}\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= x, xs == []\n\t= last xs\n{\n\tx:xs = l;\n}\n\n/* len l: length of list l\n * (see also is_list_len and friends in predicate.def)\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta:b:x = l;\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = any (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge p l r\n\t= [], p == [] || l == [] || r == []\n\t= a : merge z x y, c\n\t= b : merge z x y\n{\n\ta:x = l;\n\tb:y = r;\n\tc:z = p;\n}\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta:x = l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scanl fn st l: apply (foldl fn r) to every initial segment of a list\n *\n * scanl add 0 [1,2,3] == [1,3,6]\n * scanl :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscanl fn st l\n\t= st, l == []\n\t= st' : scanl fn st' xs\n{\n\tx:xs = l;\n\tst' = fn st x;\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta:x = l1;\n\t\tb:y = l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/8.5/_magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate _magick.def\n\t Add 0-ary and 2-ary system\n\t Put utility funcs into a Magick class\n   11-Apr-2014 snibgo\n     Added VirtualPixelBack for cases where background is only relevant when VP=Background\n   17-Apr-2014 snibgo\n     Many small changes.\n   2-May-2014 jcupitt\n     Added Magick.version\n   30-June-2014\n   \t Put single-quotes around command exe to help win\n   1-July-2014\n     Automatically fall back to gm if we can't find convert\n   17-July-2014\n     better GM support\n\n\n   Last update: 17-July-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n\n*/\n\n/* Put these in a class to avoid filling the main namespace with IM stuff.\n */\n\nMagick = class {\n\n\t// first gm on path, or \"\"\n\tgm_path = search_for \"gm\";\n\n\t// first convert on $PATH, or \"\"\n\t// we check for the convert we ship first\n\tconvert_path \n\t\t= vips_convert, vips_convert != \"\"\n\t\t= search_for \"convert\"\n\t{\n\t\t// the convert we ship with the vips binary on some platforms, or \"\"\n\t\tvips_convert \n\t\t\t= search (path_absolute convert)\n\t\t{\n\t\t\tvipshome = path_parse (expand \"$VIPSHOME\");\n\t\t\tconvert = vipshome ++ [\"bin\", \"convert\" ++ expand \"$EXEEXT\"];\n\t\t}\n\t}\n\n\tuse_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK;\n\n\t// Are we in GM or IM mode? \n\tuse_gm \n\t\t= true, use_gm_pref && gm_path != \"\"\n\t\t= false, !use_gm_pref && convert_path != \"\"\n\t\t= false, convert_path != \"\"\n\t\t= true, gm_path != \"\"\n\t\t= error \"neither IM nor GM executable found\";\n\n\tcommand_path\n\t\t= gm_path, use_gm\n\t\t= convert_path;\n\n\t// try to get the version as eg. [6, 7, 7, 10]\n\t// GM versions are smaller, typically [1, 3, 18]\n\tversion\n\t\t= map parse_int (split (member \".-\") version_string)\n\t{\n\t\t[output] = vips_call \"system\" \n\t\t\t[\"'\" ++ command_path ++ \"' -version\"] [$log=>true];\n\t\tversion_string \n\t\t\t= (split (equal ' ') output)?1, use_gm\n\t\t\t= (split (equal ' ') output)?2;\n\t}\n\n\t// make a command-line ... args is a [str] we join with spaces\n\tcommand args \n\t\t= \"'\" ++ command_path ++ \"' \" ++ join_sep \" \" args'\n\t{\n\t\targs'\n\t\t\t= [\"convert\"] ++ args, use_gm\n\t\t\t= args;\n\t}\n\n\t// capabilities ... different versions support different features, we \n\t// turn features on and off based on these\n\n\t// would probably be better to test for caps somehow\n\thas_intensity\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\thas_channel\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\n\tsystem0 cmd = system_image0 cmd;\n\tsystem cmd x = map_unary (system_image cmd) x;\n\tsystem2 cmd x y = map_binary (system_image2 cmd) x y;\n\tsystem3 cmd x y z = map_trinary (system_image3 cmd) x y z;\n\n\tradius_widget = Scale \"Radius\" 0 100 10;\n\tsigma_widget = Scale \"Sigma\" 0.1 10 1;\n\tangle_widget = Scale \"Angle (degrees)\" (-360) 360 0;\n\ttext_widget = String \"Text to draw\" \"AaBbCcDdEe\";\n\n\tgamma_widget = Scale \"Gamma\" 0 10 1;\n\tcolors_widget = Scale \"Colors\" 1 10 3;\n\tresize_widget = Scale \"Resize (percent)\" 0 500 100;\n\tfuzz_widget = Scale \"Fuzz (percent)\" 0 100 0;\n\tblur_rad_widget = Scale \"Radius (0=auto)\" 0 100 0;\n\n\t// a colour with no enclosing quotes ... use this if we know there are\n\t// some quotes at an outer level\n\tprint_colour_nq triple\n\t\t= concat [\"#\", concat (map fmt triple)]\n\t{\n\t\tfmt x = reverse (take 2 (reverse (print_base 16 (x + 256))));\n\t}\n\n\t// we need the quotes because # is the comment character in *nix\n\tprint_colour triple = \"\\\"\" ++ print_colour_nq triple ++ \"\\\"\";\n\n\tForeground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-fill \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Foreground triple;\n\t}\n\tforeground_widget = Foreground [0, 0, 0];\n\n\tGeneralCol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = print_colour_nq triple;\n\n\t\tColour_edit space triple = this.GeneralCol triple;\n\t}\n\tgeneralcol_widget = GeneralCol [0, 0, 0];\n\n\tBackground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" false;\n\n\t\t_flag = \"-background \" ++ if isNone then \"None\" else print_colour triple;\n\n\t\tColour_edit space triple = this.Background triple;\n\t}\n\tbackground_widget = Background [255, 255, 255];\n\n\tBordercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-bordercolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Bordercol triple;\n\t}\n\tbordercol_widget = Bordercol [0, 0, 0];\n\n\tMattecol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-mattecolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Mattecol triple;\n\t}\n\tmattecol_widget = Mattecol [189, 189, 189];\n\n\t// FIXME: Undercolour, like many others, can have alpha channel.\n\t// How does user input this? With a slider?\n\tUndercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" true;\n\n\t\t_flag = if isNone then \"\" else (\"-undercolor \" ++ print_colour triple);\n\n\t\tColour_edit space triple = this.Undercol triple;\n\t}\n\tundercol_widget = Undercol [0, 0, 0];\n\n\tchangeCol_widget = class {\n\t\t_vislevel = 3;\n\n\t\tcolour = GeneralCol [0, 0, 0];\n\t\tfuzz = fuzz_widget;\n\t\tnonMatch = Toggle \"change non-matching colours\" false;\n\t}\n\n\tAlpha alpha = class\n\t\tOption_string \"Alpha\" [\n\t\t\t\"On\", \n\t\t\t\"Off\", \n\t\t\t\"Set\", \n\t\t\t\"Opaque\", \n\t\t\t\"Transparent\", \n\t\t\t\"Extract\", \n\t\t\t\"Copy\", \n\t\t\t\"Shape\", \n\t\t\t\"Remove\", \n\t\t\t\"Background\"\n\t\t] alpha {\n\n\t\t_flag = \"-alpha \" ++ alpha;\n\n\t\tOption_edit caption labels value = this.Alpha labels?value;\n\t}\n\talpha_widget = Alpha \"On\";\n\n\tAntialias value = class\n\t\tToggle \"Antialias\" value {\n\n\t\t_flag\n\t\t\t= \"-antialias\", value\n\t\t\t= \"+antialias\";\n\n\t\tToggle_edit caption value = this.Antialias value;\n\t}\n\tantialias_widget = Antialias true;\n\n\tBuiltin builtin = class\n\t\tOption_string \"Builtin\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"rose:\",\n\t\t\t\"logo:\",\n\t\t\t\"wizard:\",\n\t\t\t\"granite:\",\n\t\t\t\"netscape:\"\n\t\t] builtin {\n\n\t\t_flag = builtin;\n\n\t\tOption_edit caption labels value = this.Builtin labels?value;\n\t}\n\tbuiltin_widget = Builtin \"rose:\";\n\n\n\tchannels_widget = class {\n\t\t// FIXME? Can we grey-out alpha when we have no alpha channel,\n\t\t//        show CMY(K) instead of RGB(K) etc?\n\t\t// Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA.\n\t\tChanR valueR = class\n\t\t\tToggle \"Red\" valueR {\n\n\t\t\t_flag\n\t\t\t\t= \"R\", valueR\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueR = this.ChanR valueR;\n\t\t}\n\t\tchannelR = ChanR true;\n\n\t\tChanG valueG = class\n\t\t\tToggle \"Green\" valueG {\n\n\t\t\t_flag\n\t\t\t\t= \"G\", valueG\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueG = this.ChanG valueG;\n\t\t}\n\t\tchannelG = ChanG true;\n\n\t\tChanB valueB = class\n\t\t\tToggle \"Blue\" valueB {\n\n\t\t\t_flag\n\t\t\t\t= \"B\", valueB\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueB = this.ChanB valueB;\n\t\t}\n\t\tchannelB = ChanB true;\n\n\t\tChanK valueK = class\n\t\t\tToggle \"Black\" valueK {\n\n\t\t\t_flag\n\t\t\t\t= \"K\", valueK\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueK = this.ChanK valueK;\n\t\t}\n\t\tchannelK = ChanK true;\n\n\t\tChanA valueA = class\n\t\t\tToggle \"Alpha\" valueA {\n\n\t\t\t_flag\n\t\t\t\t= \"A\", valueA\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueA = this.ChanA valueA;\n\t\t}\n\t\tchannelA = ChanA false;\n\n\t\tChanSy valueSy = class\n\t\t\tToggle \"Sync\" valueSy {\n\n\t\t\t_flag\n\t\t\t\t= \",sync\", valueSy\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueSy = this.ChanSy valueSy;\n\t\t}\n\t\tchannelSy = ChanSy true;\n\n\t\t_rgbka = concat [channelR._flag,\n\t\t\t\tchannelG._flag,\n\t\t\t\tchannelB._flag,\n\t\t\t\tchannelK._flag,\n\t\t\t\tchannelA._flag\n\t\t\t];\n\n\t\t_flag\n\t\t\t= \"\", _rgbka == \"\" || !has_channel\n\t\t\t= concat [ \"-channel \",\n\t\t\t\t_rgbka,\n\t\t\t\tchannelSy._flag \n\t\t\t\t];\n\t}\n\n\tch_widget = channels_widget;\n\n\tColorspace colsp = class\n\t\tOption_string \"Colorspace\" [\n\t\t\t\"CIELab\",\n\t\t\t\"CMY\",\n\t\t\t\"CMYK\",\n\t\t\t\"Gray\",\n\t\t\t\"HCL\",\n\t\t\t\"HCLp\",\n\t\t\t\"HSB\",\n\t\t\t\"HSI\",\n\t\t\t\"HSL\",\n\t\t\t\"HSV\",\n\t\t\t\"HWB\",\n\t\t\t\"Lab\",\n\t\t\t\"LCH\",\n\t\t\t\"LCHab\",\n\t\t\t\"LCHuv\",\n\t\t\t\"LMS\",\n\t\t\t\"Log\",\n\t\t\t\"Luv\",\n\t\t\t\"OHTA\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601YCbCr\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709YCbCr\",\n\t\t\t\"RGB\",\n\t\t\t\"scRGB\",\n\t\t\t\"sRGB\",\n\t\t\t\"Transparent\",\n\t\t\t\"XYZ\",\n\t\t\t\"YCbCr\",\n\t\t\t\"YDbDr\",\n\t\t\t\"YCC\",\n\t\t\t\"YIQ\",\n\t\t\t\"YPbPr\",\n\t\t\t\"YUV\"\n\t\t] colsp {\n\n\t\t_flag = colsp;\n\n\t\tOption_edit caption labels value = this.Colorspace labels?value;\n\t}\n\tcolorspace_widget = Colorspace \"sRGB\";\n\n\tCompose comp = class\n\t\tOption_string \"Compose method\" [\n\t\t\t\"Atop\", \n\t\t\t\"Blend\", \n\t\t\t\"Blur\", \n\t\t\t\"Bumpmap\", \n\t\t\t\"ChangeMask\", \n\t\t\t\"Clear\", \n\t\t\t\"ColorBurn\", \n\t\t\t\"ColorDodge\", \n\t\t\t\"Colorize\", \n\t\t\t\"CopyBlack\", \n\t\t\t\"CopyBlue\", \n\t\t\t\"CopyCyan\", \n\t\t\t\"CopyGreen\", \n\t\t\t\"Copy\", \n\t\t\t\"CopyMagenta\", \n\t\t\t\"CopyOpacity\", \n\t\t\t\"CopyRed\", \n\t\t\t\"CopyYellow\", \n\t\t\t\"Darken\", \n\t\t\t\"DarkenIntensity\", \n\t\t\t\"DivideDst\", \n\t\t\t\"DivideSrc\", \n\t\t\t\"Dst\", \n\t\t\t\"Difference\", \n\t\t\t\"Displace\", \n\t\t\t\"Dissolve\", \n\t\t\t\"Distort\", \n\t\t\t\"DstAtop\", \n\t\t\t\"DstIn\", \n\t\t\t\"DstOut\", \n\t\t\t\"DstOver\", \n\t\t\t\"Exclusion\", \n\t\t\t\"HardLight\", \n\t\t\t\"Hue\", \n\t\t\t\"In\", \n\t\t\t\"Lighten\", \n\t\t\t\"LightenIntensity\", \n\t\t\t\"LinearBurn\", \n\t\t\t\"LinearDodge\", \n\t\t\t\"LinearLight\", \n\t\t\t\"Luminize\", \n\t\t\t\"Mathematics\", \n\t\t\t\"MinusDst\", \n\t\t\t\"MinusSrc\", \n\t\t\t\"Modulate\", \n\t\t\t\"ModulusAdd\", \n\t\t\t\"ModulusSubtract\", \n\t\t\t\"Multiply\", \n\t\t\t\"None\", \n\t\t\t\"Out\", \n\t\t\t\"Overlay\", \n\t\t\t\"Over\", \n\t\t\t\"PegtopLight\", \n\t\t\t\"PinLight\", \n\t\t\t\"Plus\", \n\t\t\t\"Replace\", \n\t\t\t\"Saturate\", \n\t\t\t\"Screen\", \n\t\t\t\"SoftLight\", \n\t\t\t\"Src\", \n\t\t\t\"SrcAtop\", \n\t\t\t\"SrcIn\", \n\t\t\t\"SrcOut\", \n\t\t\t\"SrcOver\", \n\t\t\t\"VividLight\", \n\t\t\t\"Xor\"\n\t\t] comp {\n\n\t\t_flag = \"-compose \" ++ comp;\n\n\t\tOption_edit caption labels value = this.Compose labels?value;\n\t}\n\tcompose_widget = Compose \"Over\";\n\t// FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string.\n\n\t// FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack\n\n\tcoordinate_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\n\t\t_flag = concat [print x.expr, \",\", print y.expr];\n\t};\n\n\tDistort distort = class\n\t\tOption_string \"Distort\" [\n\t\t\t\"Affine\",\n\t\t\t\"AffineProjection\",\n\t\t\t\"ScaleRotateTranslate\",\n\t\t\t\"SRT\",\n\t\t\t\"Perspective\",\n\t\t\t\"PerspectiveProjection\",\n\t\t\t\"BilinearForward\",\n\t\t\t\"BilinearReverse\",\n\t\t\t\"Polynomial\",\n\t\t\t\"Arc\",\n\t\t\t\"Polar\",\n\t\t\t\"DePolar\",\n\t\t\t\"Barrel\",\n\t\t\t\"BarrelInverse\",\n\t\t\t\"Shepards\",\n\t\t\t\"Resize\"\n\t\t] distort {\n\n\t\t_flag = distort;\n\n\t\tOption_edit caption labels value = this.Distort labels?value;\n\t}\n\tdistort_widget = Distort \"SRT\";\n\n\tDither dither = class\n\t\tOption_string \"Dither\" [\n\t\t\t\"None\",\n\t\t\t\"FloydSteinberg\",\n\t\t\t\"Riemersma\"\n\t\t] dither {\n\n\t\t_flag = \"-dither \" ++ dither;\n\n\t\tOption_edit caption labels value = this.Dither labels?value;\n\t}\n\tdither_widget = Dither \"FloydSteinberg\";\n\n\tEvaluate eval = class\n\t\tOption_string \"Evaluate operation\" [\n\t\t\t\"Abs\",\n\t\t\t\"Add\",\n\t\t\t\"AddModulus\",\n\t\t\t\"And\",\n\t\t\t\"Cos\",\n\t\t\t\"Cosine\",\n\t\t\t\"Divide\",\n\t\t\t\"Exp\",\n\t\t\t\"Exponential\",\n\t\t\t\"GaussianNoise\",\n\t\t\t\"ImpulseNoise\",\n\t\t\t\"LaplacianNoise\",\n\t\t\t\"LeftShift\",\n\t\t\t\"Log\",\n\t\t\t\"Max\",\n\t\t\t\"Mean\",\n\t\t\t\"Median\",\n\t\t\t\"Min\",\n\t\t\t\"MultiplicativeNoise\",\n\t\t\t\"Multiply\",\n\t\t\t\"Or\",\n\t\t\t\"PoissonNoise\",\n\t\t\t\"Pow\",\n\t\t\t\"RightShift\",\n\t\t\t\"Set\",\n\t\t\t\"Sin\",\n\t\t\t\"Sine\",\n\t\t\t\"Subtract\",\n\t\t\t\"Sum\",\n\t\t\t\"Threshold\",\n\t\t\t\"ThresholdBlack\",\n\t\t\t\"ThresholdWhite\",\n\t\t\t\"UniformNoise\",\n\t\t\t\"Xor\"\n\t\t] eval {\n\n\t\t_flag = \"-evaluate \" ++ eval;\n\n\t\tOption_edit caption labels value = this.Evaluate labels?value;\n\t}\n\tevaluate_widget = Evaluate \"Add\";\n\n\tFilter filt = class\n\t\tOption_string \"Filter\" [\n\t\t\t\"default\",\n\t\t\t\"Bartlett\",\n\t\t\t\"Blackman\",\n\t\t\t\"Bohman\",\n\t\t\t\"Box\",\n\t\t\t\"Catrom\",\n\t\t\t\"Cosine\",\n\t\t\t\"Cubic\",\n\t\t\t\"Gaussian\",\n\t\t\t\"Hamming\",\n\t\t\t\"Hann\",\n\t\t\t\"Hermite\",\n\t\t\t\"Jinc\",\n\t\t\t\"Kaiser\",\n\t\t\t\"Lagrange\",\n\t\t\t\"Lanczos\",\n\t\t\t\"Lanczos2\",\n\t\t\t\"Lanczos2Sharp\",\n\t\t\t\"LanczosRadius\",\n\t\t\t\"LanczosSharp\",\n\t\t\t\"Mitchell\",\n\t\t\t\"Parzen\",\n\t\t\t\"Point\",\n\t\t\t\"Quadratic\",\n\t\t\t\"Robidoux\",\n\t\t\t\"RobidouxSharp\",\n\t\t\t\"Sinc\",\n\t\t\t\"SincFast\",\n\t\t\t\"Spline\",\n\t\t\t\"Triangle\",\n\t\t\t\"Welch\"\n\t\t] filt {\n\n\t\t_flag = if filt == \"default\" then \"\" else \"-filter \" ++ filt;\n\n\t\tOption_edit caption labels value = this.Filter labels?value;\n\t}\n\tfilter_widget = Filter \"default\";\n\n\tFunction func = class\n\t\tOption_string \"Function\" [\n\t\t\t\"Polynomial\",\n\t\t\t\"Sinusoid\",\n\t\t\t\"Arcsin\",\n\t\t\t\"Arctan\"\n\t\t] func {\n\n\t\t_flag = func;\n\n\t\tOption_edit caption labels value = this.Function labels?value;\n\t}\n\tfunction_widget = Function \"Polynomial\";\n\n//  \"Polynomial (a[n], a[n-1], ... a[1], a[0])\",\n//  \"Sinusoid (freq, phase, amp, bias)\",\n//  \"Arcsin (width, centre, range, bias)\",\n//  \"Arctan (slope, centre, range, bias)\"\n\n\tGravity gravity = class\n\t\tOption_string \"Gravity\" [\n\t\t\t\"None\",\n\t\t\t\"Center\",\n\t\t\t\"East\",\n\t\t\t\"Forget\",\n\t\t\t\"NorthEast\",\n\t\t\t\"North\",\n\t\t\t\"NorthWest\",\n\t\t\t\"SouthEast\",\n\t\t\t\"South\",\n\t\t\t\"SouthWest\",\n\t\t\t\"West\",\n\t\t\t\"Static\"\n\t\t] gravity {\n\n\t\t_flag = \"-gravity \" ++ gravity;\n\n\t\tOption_edit caption labels value = this.Gravity labels?value;\n\t}\n\tgravity_widget = Gravity \"Center\";\n\n\tImageType imagetype = class\n\t\tOption_string \"Image type\" [\n\t\t\t\"Bilevel\",\n\t\t\t\"ColorSeparation\",\n\t\t\t\"ColorSeparationAlpha\",\n\t\t\t\"ColorSeparationMatte\",\n\t\t\t\"Grayscale\",\n\t\t\t\"GrayscaleAlpha\",\n\t\t\t\"GrayscaleMatte\",\n\t\t\t\"Optimize\",\n\t\t\t\"Palette\",\n\t\t\t\"PaletteBilevelAlpha\",\n\t\t\t\"PaletteBilevelMatte\",\n\t\t\t\"PaletteAlpha\",\n\t\t\t\"PaletteMatte\",\n\t\t\t\"TrueColorAlpha\",\n\t\t\t\"TrueColorMatte\",\n\t\t\t\"TrueColor\"\n\t\t] imagetype {\n\n\t\t_flag = \"-type \" ++ imagetype;\n\n\t\tOption_edit caption labels value = this.ImageType labels?value;\n\t}\n\timagetype_widget = ImageType \"TrueColor\";\n\n\tIntensity intensity = class\n\t\tOption_string \"Intensity (gray conversion)\" [\n\t\t\t\"Average\",\n\t\t\t\"Brightness\",\n\t\t\t\"Lightness\",\n\t\t\t\"MS\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601Luminance\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709Luminance\",\n\t\t\t\"RMS\"\n\t\t] intensity {\n\n\t\t_flag \n\t\t\t= \"-intensity \" ++ intensity, has_intensity\n\t\t\t= \"\";\n\n\t\tOption_edit caption labels value = this.Intensity labels?value;\n\t}\n\tintensity_widget = Intensity \"Rec709Luminance\";\n\n\tInterpolate interp = class\n\t\tOption_string \"Interpolate\" [\n\t\t\t\"default\",\n\t\t\t\"Average\",\n\t\t\t\"Average4\",\n\t\t\t\"Average9\",\n\t\t\t\"Average16\",\n\t\t\t\"Background\",\n\t\t\t\"Bilinear\",\n\t\t\t\"Blend\",\n\t\t\t\"Integer\",\n\t\t\t\"Mesh\",\n\t\t\t\"Nearest\",\n\t\t\t\"NearestNeighbor\",\n\t\t\t\"Spline\"\n\t\t] interp {\n\n\t\t_flag = if interp == \"default\" then \"\" else \"-interpolate \" ++ interp;\n\n\t\tOption_edit caption labels value = this.Interpolate labels?value;\n\t}\n\tinterpolate_widget = Interpolate \"default\";\n\n\tKernel kernel = class\n\t\tOption_string \"Kernel\" [\n\t\t\t\"Unity\",\n\t\t\t\"Gaussian\",\n\t\t\t\"DoG\",\n\t\t\t\"LoG\",\n\t\t\t\"Blur\",\n\t\t\t\"Comet\",\n\t\t\t\"Binomial\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Sobel\",\n\t\t\t\"FreiChen\",\n\t\t\t\"Roberts\",\n\t\t\t\"Prewitt\",\n\t\t\t\"Compass\",\n\t\t\t\"Kirsch\",\n\t\t\t\"Diamond\",\n\t\t\t\"Square\",\n\t\t\t\"Rectangle\",\n\t\t\t\"Disk\",\n\t\t\t\"Octagon\",\n\t\t\t\"Plus\",\n\t\t\t\"Cross\",\n\t\t\t\"Ring\",\n\t\t\t\"Peaks\",\n\t\t\t\"Edges\",\n\t\t\t\"Corners\",\n\t\t\t\"Diagonals\",\n\t\t\t\"LineEnds\",\n\t\t\t\"LineJunctions\",\n\t\t\t\"Ridges\",\n\t\t\t\"ConvexHull\",\n\t\t\t\"ThinSe\",\n\t\t\t\"Skeleton\",\n\t\t\t\"Chebyshev\",\n\t\t\t\"Manhattan\",\n\t\t\t\"Octagonal\",\n\t\t\t\"Euclidean\"\n\t\t\t// FIXME: custom kernel\n\t\t] kernel {\n\n\t\t_flag = kernel;\n\n\t\tOption_edit caption labels value = this.Kernel labels?value;\n\t}\n\tkernel_widget = Kernel \"Unity\";\n\n\tModColSp msp = class\n\t\tOption_string \"modulate colorspace\" [\n\t\t\t\"HCL\", \n\t\t\t\"HCLp\", \n\t\t\t\"HSB\", \n\t\t\t\"HSI\", \n\t\t\t\"HSL\", \n\t\t\t\"HSV\", \n\t\t\t\"HWB\", \n\t\t\t\"LCH\"\n\t\t] msp {\n\n\t\t_flag = \"-set option:modulate:colorspace \" ++ msp;\n\n\t\tOption_edit caption labels value = this.ModColSp labels?value;\n\t}\n\tModColSp_widget = ModColSp \"HSL\";\n\n\tMorphMeth morph = class\n\t\tOption_string \"Method\" [\n\t\t\t\"Correlate\",\n\t\t\t\"Convolve\",\n\t\t\t\"Dilate\",\n\t\t\t\"Erode\",\n\t\t\t\"Close\",\n\t\t\t\"Open\",\n\t\t\t\"DilateIntensity\",\n\t\t\t\"ErodeIntensity\",\n\t\t\t\"CloseIntensity\",\n\t\t\t\"OpenIntensity\",\n\t\t\t\"Smooth\",\n\t\t\t\"EdgeOut\",\n\t\t\t\"EdgeIn\",\n\t\t\t\"Edge\",\n\t\t\t\"TopHat\",\n\t\t\t\"BottomHat\",\n\t\t\t\"HitAndMiss\",\n\t\t\t\"Thinning\",\n\t\t\t\"Thicken\",\n\t\t\t\"Distance\",\n\t\t\t\"IterativeDistance\"\n\t\t] morph {\n\n\t\t_flag = morph;\n\n\t\tOption_edit caption labels value = this.MorphMeth labels?value;\n\t}\n\tmorphmeth_widget = MorphMeth \"Dilate\";\n\n\tNoise noise = class\n\t\tOption_string \"Noise\" [\n\t\t\t\"Gaussian\",\n\t\t\t\"Impulse\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Multiplicative\",\n\t\t\t\"Poisson\",\n\t\t\t\"Random\",\n\t\t\t\"Uniform\"\n\t\t] noise {\n\n\t\t_flag = \"+noise \" ++ noise;\n\n\t\tOption_edit caption labels value = this.Noise labels?value;\n\t}\n\tnoise_widget = Noise \"Gaussian\";\n\n\tPattern pattern = class\n\t\tOption_string \"Noise\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"bricks\",\n\t\t\t\"checkerboard\",\n\t\t\t\"circles\",\n\t\t\t\"crosshatch\",\n\t\t\t\"crosshatch30\",\n\t\t\t\"crosshatch45\",\n\t\t\t\"gray0\",\n\t\t\t\"gray5\",\n\t\t\t\"gray10\",\n\t\t\t\"gray15\",\n\t\t\t\"gray20\",\n\t\t\t\"gray25\",\n\t\t\t\"gray30\",\n\t\t\t\"gray35\",\n\t\t\t\"gray40\",\n\t\t\t\"gray45\",\n\t\t\t\"gray50\",\n\t\t\t\"gray55\",\n\t\t\t\"gray60\",\n\t\t\t\"gray65\",\n\t\t\t\"gray70\",\n\t\t\t\"gray75\",\n\t\t\t\"gray80\",\n\t\t\t\"gray85\",\n\t\t\t\"gray90\",\n\t\t\t\"gray95\",\n\t\t\t\"gray100\",\n\t\t\t\"hexagons\",\n\t\t\t\"horizontal\",\n\t\t\t\"horizontal2\",\n\t\t\t\"horizontal3\",\n\t\t\t\"horizontalsaw\",\n\t\t\t\"hs_bdiagonal\",\n\t\t\t\"hs_cross\",\n\t\t\t\"hs_diagcross\",\n\t\t\t\"hs_fdiagonal\",\n\t\t\t\"hs_horizontal\",\n\t\t\t\"hs_vertical\",\n\t\t\t\"left30\",\n\t\t\t\"left45\",\n\t\t\t\"leftshingle\",\n\t\t\t\"octagons\",\n\t\t\t\"right30\",\n\t\t\t\"right45\",\n\t\t\t\"rightshingle\",\n\t\t\t\"smallfishscales\",\n\t\t\t\"vertical\",\n\t\t\t\"vertical2\",\n\t\t\t\"vertical3\",\n\t\t\t\"verticalbricks\",\n\t\t\t\"verticalleftshingle\",\n\t\t\t\"verticalrightshingle\",\n\t\t\t\"verticalsaw\"\n\t\t] pattern {\n\n\t\t_flag = \"pattern:\" ++ pattern;\n\n\t\tOption_edit caption labels value = this.Pattern labels?value;\n\t}\n\tpattern_widget = Pattern \"bricks\";\n\n\tResizeType resizet = class\n\t\tOption_string \"Resize type\" [\n\t\t\t\"resize\", \n\t\t\t\"scale\",\n\t\t\t\"sample\",\n\t\t\t\"adaptive-resize\"\n\t\t] resizet {\n\n\t\t_flag = resizet;\n\n\t\tOption_edit caption labels value = this.ResizeType labels?value;\n\t}\n\tResizeType_widget = ResizeType \"resize\";\n\n\tSize_widget = class {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width (pixels)\" 64;\n\t\theight = Expression \"Height (pixels)\" 64;\n\n\t\t_flag = \"-size \" ++\n\t\t\tprint width.expr ++ \"x\" ++ print height.expr;\n\n\t};\n\n\tStatType statt = class\n\t\tOption_string \"Statistic type\" [\n\t\t\t\"Gradient\", \n\t\t\t\"Maximum\", \n\t\t\t\"Mean\", \n\t\t\t\"Median\", \n\t\t\t\"Minimum\", \n\t\t\t\"Mode\", \n\t\t\t\"Nonpeak\", \n\t\t\t\"StandardDeviation\"\n\t\t] statt {\n\n\t\t_flag = statt;\n\n\t\tOption_edit caption labels value = this.StatType labels?value;\n\t}\n\tStatType_widget = StatType \"Mean\";\n\n\tVirtualPixel vp = class\n\t\tOption_string \"Virtual pixel\" [\n\t\t\t\"Background\", \n\t\t\t\"Black\", \n\t\t\t\"CheckerTile\", \n\t\t\t\"Dither\", \n\t\t\t\"Edge\", \n\t\t\t\"Gray\", \n\t\t\t\"HorizontalTile\", \n\t\t\t\"HorizontalTileEdge\", \n\t\t\t\"Mirror\", \n\t\t\t\"None\",\n\t\t\t\"Random\",\n\t\t\t\"Tile\",\n\t\t\t\"Transparent\",\n\t\t\t\"VerticalTile\",\n\t\t\t\"VerticalTileEdge\",\n\t\t\t\"White\"\n\t\t] vp {\n\n\t\t_flag = \"-virtual-pixel \" ++ vp;\n\n\t\t_isBackground = (vp == \"Background\");\n\n\t\tOption_edit caption labels value = this.VirtualPixel labels?value;\n\t}\n\tVirtualPixel_widget = VirtualPixel \"Edge\";\n\n\tVirtualPixelBack_widget = class {\n\t\tvirtpix = Magick.VirtualPixel_widget;\n\t\tbackground = Magick.background_widget;\n\t\t_flag = (if virtpix._isBackground then (background._flag ++ \" \") else \"\")\n\t\t\t++ virtpix._flag;\n\t}\n\n\tGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tAnnotGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print shearX.expr, \"x\", print shearY.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tOffsetGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag = concat [format hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tWhxyGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFrameGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\toutbev = Expression \"Outer bevel thickness\" 0;\n\t\tinbev = Expression \"Inner bevel thickness\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat outbev, format inbev]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFont_widget = class {\n\t\t_vislevel = 3;\n\n\t\tfamily = Option_string \"Family\" [\n\t\t\t\"Arial\",\n\t\t\t\"ArialBlack\",\n\t\t\t\"AvantGarde\",\n\t\t\t\"BitstreamCharter\",\n\t\t\t\"Bookman\",\n\t\t\t\"CenturySchoolbook\",\n\t\t\t\"ComicSansMS\",\n\t\t\t\"Courier\",\n\t\t\t\"CourierNew\",\n\t\t\t\"DejaVuSans\",\n\t\t\t\"DejaVuSansMono\",\n\t\t\t\"DejaVuSerif\",\n\t\t\t\"Dingbats\",\n\t\t\t\"FreeMono\",\n\t\t\t\"FreeSans\",\n\t\t\t\"FreeSerif\",\n\t\t\t\"Garuda\",\n\t\t\t\"Georgia\",\n\t\t\t\"Helvetica\",\n\t\t\t\"HelveticaNarrow\",\n\t\t\t\"Impact\",\n\t\t\t\"LiberationMono\",\n\t\t\t\"LiberationSans\",\n\t\t\t\"LiberationSerif\",\n\t\t\t\"NewCenturySchlbk\",\n\t\t\t\"Palatino\",\n\t\t\t\"Purisa\",\n\t\t\t\"Symbol\",\n\t\t\t\"Times\",\n\t\t\t\"TimesNewRoman\",\n\t\t\t\"Ubuntu\",\n\t\t\t\"Verdana\",\n\t\t\t\"Webdings\"\n\t\t] \"Arial\";\n\t\tstyle = Option_string \"Style\" [\n\t\t\t\"Any\", \"Italic\", \"Normal\", \"Oblique\"\n\t\t] \"Normal\";\n\t\tweight = Scale \"Weight\" 1 800 400;\n\t\tsize = Scale \"Point size\" 1 100 12;\n\t\tstretch = Option_string \"Stretch\" [\n\t\t\t\"Any\", \"Condensed\", \"Expanded\", \"ExtraCondensed\", \"ExtraExpanded\", \n\t\t\t\"Normal\", \"SemiCondensed\", \"SemiExpanded\", \"UltraCondensed\", \n\t\t\t\"UltraExpanded\"\n\t\t] \"Normal\";\n\n\t\t_flag = join_sep \" \" [\n\t\t\t\t\"-family\", family.item,\n\t\t\t\t\"-weight\", print weight.value,\n\t\t\t\t\"-pointsize\", print size.value,\n\t\t\t\t\"-style\", style.item,\n\t\t\t\t\"-stretch\", stretch.item];\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.5/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = any (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && all (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* Test list length ... quicker than len x == n for large lists.\n */\nis_list_len n x\n\t= true, x == [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len (n - 1) (tl x);\n\nis_list_len_more n x\n\t= true, x != [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len_more (n - 1) (tl x);\n\nis_list_len_more_equal n x\n\t= true, n == 0\n\t= false, x == [] \n\t= is_list_len_more_equal (n - 1) (tl x);\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, all (map is_obj l)\n\t= true, all (map is_list l) &&\n\t\tall (map (not @ is_obj) l) &&\n\t\tall (map is_rectangular l) &&\n\t\tis_list_len_more 0 l &&\n\t\tall (map (is_list_len (len (hd l))) (tl l))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && is_list_len (len (hd l)) l;\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_NULL x = is_instanceof \"NULL\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Plot x = is_instanceof \"Plot\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && all (map xy l)\n{\n\txy l = is_real_list l && is_list_len 2 l;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && any (map is_Group l)\n\t= any (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= oo_unary_function get_type_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_type\")\n{\n\tget_type_op = Operator \"get_type\" get_type \n\t\tOperator_type.COMPOUND false;\n\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\t// can have alpha, hence we let bands be one more than you might think\n\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.GREY16, type == Image_type.GREY16 && is_bands 1\n\t\t= Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && \n\t\t\t(width == 1 || height == 1)\n\t\t= Image_type.B_W, is_bands 1 \n\t\t= Image_type.CMYK, type == Image_type.CMYK && is_bands 4\n\t\t= type, is_colorimetric && is_bands 3\n\t\t= Image_type.sRGB, !is_colorimetric && is_bands 3\n\t\t= Image_type.MULTIBAND, !is_colorimetric && !is_bands 3\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\n\t\t// is bands n, with an optional alpha (ie. can be n + 1 too)\n\t\tis_bands n = bands == n || bands == n + 1;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= oo_unary_function get_format_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_format\")\n{\n\tget_format_op = Operator \"get_format\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= oo_unary_function get_bits_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bits\")\n{\n\tget_bits_op = Operator \"get_bits\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= oo_unary_function get_bands_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bands\")\n{\n\tget_bands_op = Operator \"get_bands\" get_bands \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= oo_unary_function get_coding_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_coding\")\n{\n\tget_coding_op = Operator \"get_coding\" get_coding \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= oo_unary_function get_xres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xres\")\n{\n\tget_xres_op = Operator \"get_xres\" get_xres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= oo_unary_function get_yres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yres\")\n{\n\tget_yres_op = Operator \"get_yres\" get_yres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= oo_unary_function get_xoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xoffset\")\n{\n\tget_xoffset_op = Operator \"get_xoffset\" get_xoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= oo_unary_function get_yoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yoffset\")\n{\n\tget_yoffset_op = Operator \"get_yoffset\" get_yoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= oo_unary_function get_image_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_image\")\n{\n\tget_image_op = Operator \"get_image\" get_image \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= oo_unary_function get_number_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_number\")\n{\n\tget_number_op = Operator \"get_number\" get_number \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= oo_unary_function get_real_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_real\")\n{\n\tget_real_op = Operator \"get_real\" get_real \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= oo_unary_function get_width_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_width\")\n{\n\tget_width_op = Operator \"get_width\" get_width \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= oo_unary_function get_height_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_height\")\n{\n\tget_height_op = Operator \"get_height\" get_height \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= oo_unary_function get_left_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_left\")\n{\n\tget_left_op = Operator \"get_left\" get_left \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= oo_unary_function get_top_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_top\")\n{\n\tget_top_op = Operator \"get_top\" get_top \n\t\tOperator_type.COMPOUND false;\n}\n\n// like has/get member, but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.5/_stdenv.def",
    "content": "/* optional args to functions\n */\n\nget_option options defaults f\n\t= error (_ \"unknown parameter \" ++ f), hits == []\n\t= hits?0\n{\n\thits = [v :: [n, v] <- options ++ defaults; n == f];\n}\n\n/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\nidivide a b = (int) ((int) a / (int) b);\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\n// 'difference' is defined in _list\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the function we call for \"a -> v\" expressions\nmksvpair s v\n\t= [s, v], is_string s\n\t= error \"not str on lhs of ->\";\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error (\"unimplemented vector operation: \" ++ op_name)\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n// make a name value pair\nmknvpair n v\n\t= [n, v], is_string n\n\t= error \"not [char] on LHS of =>\";\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined, has_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nbandand x\n\t= oo_unary_function bandand_op x, is_class x\n\t= foldr1 bitwise_and (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandand\")\n{\n\tbandand_op = Operator \"bandand\" bandand Operator_type.COMPOUND_REWRAP false;\n}\n\nbandor x\n\t= oo_unary_function bandor_op x, is_class x\n\t= foldr1 bitwise_or (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandor\")\n{\n\tbandor_op = Operator \"bandor\" bandor Operator_type.COMPOUND_REWRAP false;\n}\n\nsum x\n\t= oo_unary_function sum_op x, is_class x\n\t= im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x\n\t= sum_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"sum\")\n{\n\tsum_op = Operator \"sum\" sum Operator_type.COMPOUND false;\n\n\t// add elements in a nested-list thing\n\tsum_list l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nproduct x\n\t= oo_unary_function product_op x, is_class x\n\t= product_list x, is_list x \n\t// (product image) doesn't make much sense :(\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"product\")\n{\n\tproduct_op = Operator \"product\" product Operator_type.COMPOUND false;\n\n\tproduct_list l\n\t\t= foldr prod 1 l\n\t{\n\t\tprod x total\n\t\t\t= total * product x, is_list x\n\t\t\t= total * x;\n\t}\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\nskew x\n\t= oo_unary_function skew_op x, is_class x\n\t= sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x \n\t= sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"skew\")\n{\n\tskew_op = Operator \"skew\" skew Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN \n\t\t= w * h * b, is_image x'\n\t\t= len x';\n}\n\nkurtosis x\n\t= oo_unary_function kurtosis_op x, is_class x\n\t= sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x \n\t= sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"kurtosis\")\n{\n\tkurtosis_op = Operator \"kurtosis\" kurtosis Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN\n\t\t= len x', is_list x';\n\t\t= w * h * b;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image_hist x, is_image x && \n\t\t(fmt == Image_format.UCHAR || fmt == Image_format.USHORT)\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tfmt = get_format x;\n\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean, for any image type\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n\n\t// image mean for 8 and 16-bit unsigned images\n\t// we can use a histogram, yay, and save a pass through the image\n\tmeanze_image_hist i\n\t\t= sum / N\n\t{\n\t\t// histogram, knock out zeros\n\t\thist = hist_find i;\n\t\tblack = image_new 1 1 (get_bands hist) \n\t\t\t(get_format hist) (get_coding hist) (get_type hist) 0 0 0;\n\t\thistze = insert 0 0 black hist;\n\n\t\t// matching identity\n\t\tiden\n\t\t\t= im_identity_ushort (get_bands hist) (get_width hist),\n\t\t\t\t(get_width hist) > 256\n\t\t\t= im_identity (get_bands hist);\n\n\t\t// number of non-zero pixels\n\t\tN = mean histze * 256;\n\n\t\t// sum of pixels\n\t\tsum = mean (hist * iden) * 256;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_tile_cache_random x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (\\row [row?x']) obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\" ++ \": \" ++\n\t\tjoin_sep \", \" (map print [cond, in1, in2]))\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x \n\t\t\t= to_image_size target_width target_height \n\t\t\t\ttarget_bands target_format x;\n\n\t\t[then_image, else_image] = map to_image [then_part, else_part];\n\n\t\tblend_result_image = image_set_type target_type \n\t\t\t(im_blend cond then_image else_image);\n\t}\n}\n\n// do big first: we want to keep big's class, if possible\n// eg. big is a Plot, small is a 1x1 Image\ninsert x y small big\n\t= oo_binary'_function insert_op small big, is_class big\n\t= oo_binary_function insert_op small big, is_class small\n\t= im_insert big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ndecode im\n\t= oo_unary_function decode_op im, is_class im\n\t= decode_im im, is_image im\n\t= error (_ \"bad arguments to \" ++ \"decode\")\n{\n\tdecode_op = Operator \"decode\" \n\t\tdecode Operator_type.COMPOUND_REWRAP false;\n\n\tdecode_im im\n\t\t= im_LabQ2Lab im, get_coding im == Image_coding.LABPACK\n\t\t= im_rad2float im, get_coding im == Image_coding.RAD\n\t\t= im;\n}\n\nmeasure_draw across down measure image\n    = mark\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n\n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::  \n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n    x = map (extract 0) cods;\n    y = map (extract 1) cods;\n\n    outer = mkim [$pixel => 255] sample_width sample_height 1;\n    inner = mkim [] (sample_width - 4) (sample_height - 4) 1;\n    patch = insert 2 2 inner outer;\n\n    bg = mkim [] image.width image.height 1;\n\n    mask = Image (im_insertset bg.value patch.value x y);\n\n    image' = colour_transform_to Image_type.sRGB image;\n\n    mark = if mask then Vector [0, 255, 0] else image';\n}\n\nmeasure_sample across down measure image\n    = measures\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n                \n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::\n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n\n\timage' = decode image;\n    patches = map (\\p extract_area p?0 p?1 sample_width sample_height image') \n\t\tcods;\n    measures = Matrix (map (map mean) (map bandsplit patches));\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ninvert x\n\t= oo_unary_function invert_op x, is_class x\n\t= im_invert x, is_image x\n\t= 255 - x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"invert\")\n{\n\tinvert_op = Operator \"invert\" invert Operator_type.COMPOUND false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate interp angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_affinei_all image interp.value a (-b) b a 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\t(rotate interp) Operator_type.COMPOUND_REWRAP false;\n\ta = cos angle;\n\tb = sin angle;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_lr\")\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin_lr Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert (get_width a) 0 b a;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_tb\")\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin_tb Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert 0 (get_height a) b a;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\t// The [[real]] can contain 128 values ... squeeze them out!\n\timage = im_mask2vips (Matrix m2) == 255;\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\" ++ \": \" ++ \n\t\t\"conv (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvf mask image\n\t= oo_unary_function convf_op image, is_class image\n\t= im_conv_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convf\" ++ \": \" ++ \n\t\t\"convf (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconvf_op = Operator \"convf\" \n\t\t(convf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\naconvsep layers mask image \n\t= oo_unary_function aconvsep_op image, is_class image\n\t= im_aconvsep image (to_matrix mask) (to_real layers), is_image image\n\t= error (_ \"bad arguments to \" ++ \"aconvsep\")\n{\n\taconvsep_op = Operator \"aconvsep\" \n\t\t(aconvsep layers mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsep_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_indexed index value\n\t= oo_binary_function hist_find_indexed_op index value, is_class index\n\t= oo_binary'_function hist_find_indexed_op index value, is_class value\n\t= im_hist_indexed index value, is_image index && is_image value\n\t= error (_ \"bad arguments to \" ++ \"hist_find_indexed\")\n{\n\thist_find_indexed_op = Operator \"hist_find_indexed\" \n\t\t(compose (compose Plot_histogram) hist_find_indexed) \n\t\t\tOperator_type.COMPOUND false;\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h \n\t\t= (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h\n\t{\n\t\t// up the format so it can represent the whole range of\n\t\t// possible values from this mask\n\t\tfmt x\n\t\t\t= Image_format.SHORT, \n\t\t\t\tx == Image_format.UCHAR || x == Image_format.CHAR\n\t\t\t= Image_format.INT, \n\t\t\t\tx == Image_format.USHORT || x == Image_format.SHORT ||\n\t\t\t\tx == Image_format.UINT \n\t\t\t= x;\n\t}\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_inv hist \n\t= oo_unary_function hist_inv_op hist, is_class hist\n\t= inv hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_inv\")\n{\n\thist_inv_op = Operator \"hist_inv\" \n\t\thist_inv Operator_type.COMPOUND_REWRAP false;\n\n\tinv im\n\t\t= im_invertlut (to_matrix im''') len\n\t{\n\t\t// need a vertical doublemask\n\t\tim' \n\t\t\t= rot90 im, get_width im > 1 && get_height im == 1 \n\t\t\t= im, get_width im == 1 && get_height im > 1\n\t\t\t= error (_ \"not a hist\");\n\t\tlen = get_height im';\n\n\t\t// values must be scaled to 0 - 1\n\t\tim'' = im' / (max im');\n\t\t\n\t\t// add an index column on the left\n\t\t// again, must be in 0-1\n\t\ty = ((make_xy 1 len)?1) / len;\n\t\tim''' = y ++ im'';\n\t}\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h l image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= out, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h l) Operator_type.COMPOUND_REWRAP false;\n\n\t[out] = vips_call \"hist_local\" \n\t\t[image, to_real w, to_real h] [$max_slope => to_real l];\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nreduce kernel xshr yshr image\n\t= oo_unary_function reduce_op image, is_class image\n\t= reduce_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"reduce\")\n{\n\treduce_op = Operator \"reduce\" \n\t\treduce_im Operator_type.COMPOUND_REWRAP false;\n\n\treduce_im im \n\t\t= out\n\t{\n\t\t[out] = vips_call \"reduce\" [im, xshr, yshr] [$kernel => kernel.value];\n\t}\n}\n\nsimilarity interpolate scale angle image\n\t= oo_unary_function similarity_op image, is_class image\n\t= similarity_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"similarity\")\n{\n\tsimilarity_op = Operator \"similarity\" \n\t\tsimilarity_im Operator_type.COMPOUND_REWRAP false;\n\n\tsimilarity_im im \n\t\t= out\n\t{\n\t\t[out] = vips_call \"similarity\" [im] [\n\t\t\t$interpolate => interpolate.value,\n\t\t\t$scale => scale,\n\t\t\t$angle => angle\n\t\t];\n\t}\n}\n\nresize kernel xfac yfac image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\tis_nn = kernel.type == Kernel_type.NEAREST_NEIGHBOUR;\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn \n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn \n\n\t\t// everything else ... we just pass on to vips_resize()\n\t\t= vips_resize kernel xfac' yfac' im\n\t{\n\t\tvips_resize kernel hscale vscale im \n\t\t\t= out\n\t\t{\n\t\t\t[out] = vips_call \"resize\" [im, hscale] \n\t\t\t\t[$vscale => vscale, $kernel => kernel.value];\n\t\t}\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\n\n// Given a xywh rect, flip it around so wh are always positive\nrect_normalise x y w h \n\t= [x', y', w', h']\n{\n\tx'\n\t\t= x + w, w < 0\n\t\t= x;\n\ty'\n\t\t= y + h, h < 0\n\t\t= y;\n\tw' = abs w;\n\th' = abs h;\n}\n\ndraw_flood_blob x y ink image\n\t= oo_unary_function draw_flood_blob_op image, is_class image\n\t= im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood_blob\")\n{\n\tdraw_flood_blob_op = Operator \"draw_flood_blob\" \n\t\t(draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_flood x y ink image\n\t= oo_unary_function draw_flood_op image, is_class image\n\t= im_draw_flood image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood\")\n{\n\tdraw_flood_op = Operator \"draw_flood\" \n\t\t(draw_flood x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* This version of draw_rect uses insert_noexpand and will be fast, even for\n * huge images.\n */\ndraw_rect_width x y w h f t ink image\n\t= oo_unary_function draw_rect_width_op image, is_class image\n\t= my_draw_rect_width image (to_int x) (to_int y) \n\t\t(to_int w) (to_int h) (to_int f) (to_int t) ink, \n\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_width\")\n{\n\tdraw_rect_width_op = Operator \"draw_rect_width\" \n\t\t(draw_rect_width x y w h f t ink) \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\tmy_draw_rect_width image x y w h f t ink\n\t\t= insert x' y' (block w' h') image, f == 1\n\t\t= (insert x' y' (block w' t) @ \n\t\t\tinsert (x' + w' - t) y' (block t h') @ \n\t\t\tinsert x' (y' + h' - t) (block w' t) @ \n\t\t\tinsert x' y' (block t h')) image\n\t{\n\t\tinsert = insert_noexpand;\n\t\tblock w h = image_new w h (get_bands image) (get_format image)\n\t\t\t(get_coding image) (get_type image) ink' 0 0;\n\t\tink' \n\t\t\t= Vector ink, is_list ink\n\t\t\t= ink;\n\t\t[x', y', w', h'] = rect_normalise x y w h;\n\t}\n}\n\n/* Default to 1 pixel wide edges.\n */\ndraw_rect x y w h f ink image\n\t= draw_rect_width x y w h f 1 ink image;\n\n/* This version of draw_rect uses the paintbox rect draw operation. It is an\n * inplace operation and will use bucketloads of memory.\n */\ndraw_rect_paintbox x y w h f ink image\n\t= oo_unary_function draw_rect_op image, is_class image\n\t= im_draw_rect image (to_real x) (to_real y) \n\t\t(to_real w) (to_real h) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_paintbox\")\n{\n\tdraw_rect_op = Operator \"draw_rect\" \n\t\t(draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_circle x y r f ink image\n\t= oo_unary_function draw_circle_op image, is_class image\n\t= im_draw_circle image (to_real x) (to_real y) \n\t\t(to_real r) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_circle\")\n{\n\tdraw_circle_op = Operator \"draw_circle\" \n\t\t(draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_line x1 y1 x2 y2 ink image\n\t= oo_unary_function draw_line_op image, is_class image\n\t= im_draw_line image (to_real x1) (to_real y1) \n\t\t(to_real x2) (to_real y2) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_line\")\n{\n\tdraw_line_op = Operator \"draw_line\" \n\t\t(draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (\\x x % base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (\\x idivide x base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= NULL, any (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n/* Linear regression. Return a class with the stuff we need in.\n * from s15.2, p 665 NR in C\n * \n * Also calculate R2, see eg.:\n * https://en.wikipedia.org/wiki/Coefficient_of_determination \n */\nlinreg xes yes\n    = obj\n{\n    obj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [t * y :: [t, y] <- zip2 tes yes] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes];\n\n\t\tsiga = (chi2 / (ss - 2)) ** 0.5 *\n\t\t\t((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5;\n\n\t\t// for compat with linregw, see below\n\t\tq = 1.0;\n\n\t\tR2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes];\n\t}\n\n\tss = len xes;\n\tsx = sum xes;\n\tsy = sum yes;\n\tmy = sy / ss;\n\tsxoss = sx / ss;\n\n\ttes = [x - sxoss :: x <- xes];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Weighted linear regression. Xes, yes and a list of deviations.\n */\nlinregw xes yes devs \n\t= obj\n{\n\tobj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: \n\t\t\t[x, y, sd] <- zip3 xes yes devs];\n\n\t\tsiga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (1 / st2) ** 0.5;\n\n\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\n\t\tR2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes];\n\t}\n\n\twt = [sd ** -0.5 :: sd <- devs];\n\n\tss = sum wt;\n\tsx = sum [x * w :: [x, w] <- zip2 xes wt];\n\tsy = sum [y * w :: [y, w] <- zip2 yes wt];\n\tmy = sy / len xes;\n\tsxoss = sx / ss;\n\n\ttes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Clustering: pass in a list of points, repeatedly merge the\n * closest two points until no two points are closer than the threshold.\n * Return [merged-points, corresponding-weights]. A weight is a list of the\n * indexes we merged to make that point, ie. len weight == how significant\n * this point is.\n *\n * eg. \n *\tcluster 12 [152,154,155,42,159] == \n *\t\t[[155,42],[[1,2,0,4],[3]]]\n */\ncluster thresh points\n\t= oo_unary_function cluster_op points, is_class points\n\t// can't use [0..len points - 1], in case len points == 0\n\t= merge [points, map (converse cons []) (take (len points) [0 ..])],\n\t\tis_list points\n\t= error (_ \"bad arguments to \" ++ \"cluster\")\n{\n\tcluster_op = Operator \"cluster\" \n\t\t(cluster thresh) Operator_type.COMPOUND false;\n\n\tmerge x\n\t\t= x, m < 2 || d > thresh\n\t\t= merge [points', weights']\n\t{\n\t\t[points, weights] = x;\n\t\tm = len points;\n\n\t\t// generate indexes of all possible pairs, avoiding comparing a thing \n\t\t// to itself, and assuming that dist is reflexive\n\t\t// first index is always less than 2nd index\n\t\t// the +1,+2 makes sure we have an increasing generator, otherwise we\n\t\t// can get [3 .. 4] (for example), which will make a decreasing\n\t\t// sequence\n\t\tpairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]];\n\n\t\t// distance function\n\t\t// arg is eg. [3,1], meaning get distance from point 3 to point 1\n\t\tdist x \n\t\t\t= abs (points?i - points?j)\n\t\t{\n\t\t\t[i, j] = x;\n\t\t}\n\n\t\t// smallest distance, then the two points we merge\n\t\tp = minpos (map dist pairs);\n\t\td = dist pairs?p;\n\t\t[i, j] = pairs?p;\n\n\t\t// new point and new weight\n\t\tnw = weights?i ++ weights?j;\n\t\tnp = (points?i * len weights?i + points?j * len weights?j) / len nw;\n\n\t\t// remove element i from a list\n\t\tremove i l = take i l ++ drop (i + 1) l;\n\n\t\t// remove two old points, add the new merged one\n\t\t// i < j (see \"pairs\", above)\n\t\tpoints' = np : remove i (remove j points);\n\t\tweights' = nw : remove i (remove j weights);\n\t}\n}\n\n/* Extract the area of an image around an arrow.\n * Transform the image to make the arrow horizontal, then displace by hd and\n * vd pxels, then cut out a bit h pixels high centered on the arrow.\n */\nextract_arrow hd vd h arrow\n\t= extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im'\n{\n\t// the line as a polar vector\n\tpv = polar (arrow.width, arrow.height);\n\ta = im pv;\n\n\t// smallest rotation that will make the line horizontal\n\ta'\n\t\t= 360 - a, a > 270\n\t\t= 180 - a, a > 90\n\t\t= -a;\n\n\tim' = rotate Interpolate_bilinear a' arrow.image;\n\n\t// look at the start and end of the arrow, pick the leftmost\n\tp\n\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t= (arrow.right, arrow.bottom);\n\n\t// transform that point to im' space\n\tp' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset);\n}\n\n/* You'd think these would go in _convert, but they are not really colour ops,\n * so put them here.\n */\nrad2float image\n\t= oo_unary_function rad2float_op image, is_class image\n\t= im_rad2float image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"rad2float\")\n{\n\trad2float_op = Operator \"rad2float\" \n\t\trad2float Operator_type.COMPOUND_REWRAP false;\n}\n\nfloat2rad image\n\t= oo_unary_function float2rad_op image, is_class image\n\t= im_float2rad image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"float2rad\")\n{\n\tfloat2rad_op = Operator \"float2rad\" \n\t\tfloat2rad Operator_type.COMPOUND_REWRAP false;\n}\n\nsegment x\n\t= oo_unary_function segment_op x, is_class x\n\t= image', is_image x \n\t= error (_ \"bad arguments to \" ++ \"segment\")\n{\n\tsegment_op = Operator \"segment\" \n\t\tsegment Operator_type.COMPOUND_REWRAP false;\n\n\t[image, nsegs] = im_segment x;\n\timage' = im_copy_set_meta image \"n-segments\" nsegs;\n}\n\npoint a b\n\t= oo_binary_function point_op a b, is_class a\n\t= oo_binary'_function point_op a b, is_class b\n\t= im_read_point b x y, is_image b\n\t= [b?x?y], is_matrix b\n\t= [b?x], is_real_list b && y == 0\n\t= [b?y], is_real_list b && x == 0\n\t= error (_ \"bad arguments to \" ++ \"point\")\n{\n\tpoint_op = Operator \"point\" \n\t\t(\\a\\b Vector (point a b)) Operator_type.COMPOUND false;\n\n\t(x, y) \n\t\t= a, is_complex a;\n\t\t= (a?0, a?1), is_real_list a && is_list_len 2 a\n\t\t= error \"bad position format\";\n}\n\n/* One image in, one out. \n */\nsystem_image command x\n\t= oo_unary_function system_image_op x, is_class x\n\t= system x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"system_image\")\n{\n\tsystem_image_op = Operator \"system_image\" \n\t\t(system_image command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem im\n\t\t= image_out\n\t{\n\t\t[image_out, log] = \n\t\t\tim_system_image (get_image im) \"%s.tif\" \"%s.tif\" command;\n\t}\n}\n\n/* Two images in, one out. \n */\nsystem_image2 command x1 x2\n\t= oo_binary_function system_image2_op x1 x2, is_class x1\n\t= oo_binary'_function system_image2_op x1 x2, is_class x2\n\t= system x1 x2, is_image x1 && is_image x2\n\t= error (_ \"bad arguments to \" ++ \"system_image2\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image2 command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Three images in, one out. \n */\nsystem_image3 command x1 x2 x3\n\t= oo_binary_function system_image2_op x2 x3, is_class x2\n\t= oo_binary'_function system_image2_op x2 x3, is_class x3\n\t= system x1 x2 x3, is_image x1 && is_image x2 && is_image x3\n\t= error (_ \"bad arguments to \" ++ \"system_image3\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image3 command x1) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2 x3\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2, x3], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Zero images in, one out. \n */\nsystem_image0 command \n\t= Image image_out\n{\n\t[image_out] = vips_call \"system\" [command] [\n\t\t$out => true,\n\t\t$out_format => \"%s.tif\" \n\t];\n}\n\nhough_line w h x \n\t= oo_unary_function hough_line_op x, is_class x\n\t= hline (to_real w) (to_real h) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_line\")\n{\n\though_line_op = Operator \"hough_line\" \n\t\t(hough_line w h) Operator_type.COMPOUND_REWRAP false;\n\n\thline w h x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_line\" [x] [\n\t\t\t$width => w, \n\t\t\t$height => h\n\t\t];\n\t}\n}\n\nhough_circle s mn mx x \n\t= oo_unary_function hough_circle_op x, is_class x\n\t= hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_circle\")\n{\n\though_circle_op = Operator \"hough_circle\" \n\t\t(hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false;\n\n\thcircle s mn mx x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_circle\" [x] [\n\t\t\t$scale => s, \n\t\t\t$min_radius => mn, \n\t\t\t$max_radius => mx\n\t\t];\n\t}\n}\n\nmapim interp ind in\n\t= oo_binary_function mapim_op ind in, is_class ind\n\t= oo_binary'_function mapim_op ind in, is_class in\n\t= mapim_fn ind in, is_image ind && is_image in\n\t= error (_ \"bad arguments to \" ++ \"mapim\")\n{\n\tmapim_op = Operator \"mapim\" \n\t\t(mapim interp) Operator_type.COMPOUND_REWRAP false;\n\n\tmapim_fn ind im\n\t\t= out\n\t{\n\t\t[out] = vips_call \"mapim\" [im, ind] [$interpolate => interp];\n\t}\n}\n\nperlin cell width height\n\t= Image im\n{\n\t[im] = vips_call \"perlin\" [to_real width, to_real height] [\n\t\t$cell_size => to_real cell \n\t];\n}\n\nworley cell width height\n\t= Image im\n{\n\t[im] = vips_call \"worley\" [to_real width, to_real height] [\n\t\t$cell_size => to_real cell \n\t];\n}\n\ngaussnoise width height mean sigma\n\t= im\n{\n\t[im] = vips_call \"gaussnoise\" [to_real width, to_real height] [\n\t\t$mean => to_real mean,\n\t\t$sigma => to_real sigma\n\t];\n}\n\nflattenimage bg x \n\t= oo_unary_function flatten_op x, is_class x\n\t= flt (to_vector bg) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"flattenimage\")\n{\n\tflatten_op = Operator \"flatten\" \n\t\t(flattenimage bg) Operator_type.COMPOUND_REWRAP false;\n\n\tflt bg x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"flatten\" [x] [\n\t\t\t$background => bg.value \n\t\t];\n\t}\n}\n\npremultiply x \n\t= oo_unary_function premultiply_op x, is_class x\n\t= prem x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"premultiply\")\n{\n\tpremultiply_op = Operator \"premultiply\" \n\t\tpremultiply Operator_type.COMPOUND_REWRAP false;\n\n\tprem x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"premultiply\" [x] [\n\t\t];\n\t}\n}\n\nunpremultiply x \n\t= oo_unary_function unpremultiply_op x, is_class x\n\t= unprem x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"unpremultiply\")\n{\n\tunpremultiply_op = Operator \"unpremultiply\" \n\t\tunpremultiply Operator_type.COMPOUND_REWRAP false;\n\n\tunprem x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"unpremultiply\" [x] [\n\t\t];\n\t}\n}\n\nhist_entropy x \n\t= oo_unary_function hist_entropy_op x, is_class x\n\t= entropy x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hist_entropy\")\n{\n\thist_entropy_op = Operator \"hist_entropy\" \n\t\thist_entropy Operator_type.COMPOUND_REWRAP false;\n\n\tentropy x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"hist_entropy\" [x] [\n\t\t];\n\t}\n}\n\n\n"
  },
  {
    "path": "share/nip2/compat/8.5/_types.def",
    "content": "/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary (\\a op.fn a x) this,\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// we can't call map_trinary directly, since it uses Group and we\n\t// don't support mutually recursive top-level functions :-(\n\t// copy-paste it here, keep in sync with the version in _stdenv\n\tmap_nary fn args\n\t\t= fn args, groups == []\n\t\t= Group (map process [0, 1 .. shortest - 1])\n\t{\n\t\tgroups = filter is_Group args;\n\t\n\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\tprocess n\n\t\t\t= NULL, any (map (is_noval n) args)\n\t\t\t= map_nary fn (map (extract n) args)\n\t\t{\n\t\t\textract n arg\n\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t= arg;\n\t\n\t\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t\t}\n\t}\n\n\t// need ite as a true trinary\n\tite a b c = if a then b else c;\n\n\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t];\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\n\t\t[op.fn this.value x,\n\t\t\top.type == Operator_type.COMPOUND]\n\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[is_list_len 3 value, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.item colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum \"Colour space\" Image_type.colour_spaces default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\n/* An option whose value is a string rather than a number.\n */\nOption_string caption labels item = class\n\tOption caption labels (index (equal item) labels) {\n\tOption_edit caption labels value \n\t\t= this.Option_string caption labels (labels?value);\n}\n\n/* Make an option from an enum.\n */\nOption_enum caption enum item = class\n\tOption_string caption enum.names item {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing item;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum caption enum (enum.names?value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNONE = 0;\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNONE = 0;\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n\tRAD = 6;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* Extract a column.\n\t */\n\tcolumn n = map (extract n) value;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (column col) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (column from);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = this.column 0; \n\tthings = this.column 1; \n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tHISTOGRAM = 10;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tARRAY = 27;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t$MULTIBAND => MULTIBAND,\n\t\t$B_W => B_W,\n\t\t$HISTOGRAM => HISTOGRAM,\n\t\t$XYZ => XYZ,\n\t\t$LAB => LAB,\n\t\t$CMYK => CMYK,\n\t\t$LABQ => LABQ,\n\t\t$RGB => RGB,\n\t\t$UCS => UCS,\n\t\t$LCH => LCH,\n\t\t$LABS => LABS,\n\t\t$sRGB => sRGB,\n\t\t$YXY => YXY,\n\t\t$FOURIER => FOURIER,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$ARRAY => ARRAY\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options generated from this, so match the order to the order in the\n\t * Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t$sRGB => sRGB,\n\t\t$Lab => LAB,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t$Mono => B_W,\n\t\t$sRGB => sRGB,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$Lab => LAB,\n\t\t$LabQ => LABQ,\n\t\t$LabS => LABS,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \n\t\t// \"Image v == 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\t// if one of then/else is an image, get the target format from that\n\t\t// otherwise, let the non-image objects set the target\n\t\ttarget_format \n\t\t\t= get_member_list has_format get_format x, \n\t\t\t\thas_member_list has_format x\n\t\t\t= NULL;\n\n\t\tto_image x = to_image_size width height target_bands target_format x;\n\n\t\t[then', else'] = map to_image x;\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if value then then' else else');\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nKernel_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tLINEAR = 1;\n\tCUBIC = 2;\n\tLANCZOS2 = 3;\n\tLANCZOS3 = 4;\n\n\t// Should introspect to get the list of interpolators :-(\n\t// We can \"dir\" on VipsInterpolate to get a list of them, but we\n\t// can't get i18n'd descriptions until we have more\n\t// introspection stuff in nip2.\n\n\t/* Table to map kernel numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Linear\", \n\t\t_ \"Cubic\",\n\t\t_ \"Lanczos, two lobes\",\n\t\t_ \"Lanczos, three lobes\"\n\t];\n\n\t/* And to vips enum nicknames.\n\t */\n\ttypes = [\n\t\t\"nearest\", \n\t\t\"linear\", \n\t\t\"cubic\", \n\t\t\"lanczos2\", \n\t\t\"lanczos3\"\n\t];\n}\n\nKernel type = class {\n\tvalue = Kernel_type.types?type;\n}\n\nKernel_linear = Kernel Kernel_type.LINEAR;\n\nKernel_picker default = class \n\tKernel kernel.value {\n\t_vislevel = 2;\n\n\tkernel = Option \"Kernel\" Kernel_type.descriptions default;\n}\n\nInterpolate_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\tLBB = 3;\n\tNOHALO = 4;\n\tVSQBS = 5;\n\n\t// Should introspect to get the list of interpolators :-(\n\t// We can \"dir\" on VipsInterpolate to get a list of them, but we\n\t// can't get i18n'd descriptions until we have more\n\t// introspection stuff in nip2.\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Bilinear\", \n\t\t_ \"Bicubic\",\n\t\t_ \"Upsize: reduced halo bicubic (LBB)\",\n\t\t_ \"Upsharp: reduced halo bicubic with edge sharpening (Nohalo)\",\n\t\t_ \"Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)\"\n\t];\n\n\t/* And to vips type names.\n\t */\n\ttypes = [\n\t\t\"VipsInterpolateNearest\",\n\t\t\"VipsInterpolateBilinear\",\n\t\t\"VipsInterpolateBicubic\",\n\t\t\"VipsInterpolateLbb\",\n\t\t\"VipsInterpolateNohalo\",\n\t\t\"VipsInterpolateVsqbs\"\n\t];\n}\n\nInterpolate type options = class {\n\tvalue = vips_object_new Interpolate_type.types?type [] options;\n}\n\nInterpolate_bilinear = Interpolate Interpolate_type.BILINEAR [];\n\nInterpolate_picker default = class \n\tInterpolate interp.value [] {\n\t_vislevel = 2;\n\n\tinterp = Option \"Interpolation\" Interpolate_type.descriptions default;\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t_ \"Perceptual\" => PERCEPTUAL,\n\t\t_ \"Relative\" => RELATIVE,\n\t\t_ \"Saturation\" => SATURATION,\n\t\t_ \"Absolute\" => ABSOLUTE\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t_ \"Point\" => POINT,\n\t\t_ \"Line\" => LINE,\n\t\t_ \"Spline\" => SPLINE,\n\t\t_ \"Bar\" => BAR\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t_ \"YYYY\" => YYYY,\n\t\t_ \"XYYY\" => XYXY,\n\t\t_ \"XYXY\" => XYXY\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n\tto_image dpi = extract_bands 0 3 \n\t\t(graph_export_image (to_real dpi) this);\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [$format => Plot_format.XYYY] value {\n}\n\n/* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate\n * empty slots, for example.\n */\nNULL = class \n\t_Object {\n\too_binary_table op x = [\n\t\t// the only operation we allow is equality .. use pointer equality,\n\t\t// this lets us test a == NULL and a != NULL\n\t\t[this === x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"equal\"],\n\t\t[this !== x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"not_equal\"]\n\t] ++ super.oo_binary_table op x;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.6/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t[_L, _a, _b] = default_value;\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n\n\tCCT_colour = class\n\t\tMenuaction (_ \"Colour from CCT\") (_ \"pick colour by CCT\") {\n\t\taction = widget 6500;\n\n\t\twidget x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tT = Scale \"CCT\" 1800 25000 x;\n\n\t\t\t_result = colour_from_temp (to_real T);\n\n\t\t\tColour_edit space value \n\t\t\t\t= widget (temp_from_colour (Colour space value));\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Convert to\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tscRGB_item = class\n\t\tMenuaction (_ \"_scRGB\") (_ \"convert to scRGB colourspace\") {\n\t\taction x = conv Image_type.scRGB x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Tag as\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tscRGB_item = class\n\t\tMenuaction (_ \"_scRGB\") (_ \"tag as being in scRGB colourspace\") {\n\t\taction x = tag Image_type.scRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum (_ \"Old whitepoint\") Whitepoints \"D65\";\n\t\t\tnew_white = Option_enum (_ \"New whitepoint\") Whitepoints \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCCT_item = class\n\t\tMenuaction (_ \"Calculate temperature\")\n\t\t\t(_ \"estimate CCT using the McCamy approximation\") {\n\t\taction z = map_unary temp_from_colour z;\n\t}\n\n\tColour_item = Colour_new_item.CCT_colour;\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= print_profile, \n\t\t\thas_type image && \n\t\t\tget_type image == Image_type.CMYK &&\n\t\t\thas_bands image && \n\t\t\tget_bands image >= 4\n\t\t= monitor_profile;\n\trender_intents = Option_enum (_ \"Render intent\") Render_intent.names\n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_rad_item = class\n\tMenupullright (_ \"_Radiance\") (_ \"convert to and from Radiance packed format\") {\n\tUnpack_item = class\n\t\tMenuaction (_ \"Unpack\") \n\t\t\t(_ \"unpack Radiance format to float\") {\n\t\taction x = map_unary rad2float x;\n\t}\n\n\tPack_item = class\n\t\tMenuaction (_ \"Pack\") \n\t\t\t(_ \"pack 3-band float to Radiance format\") {\n\t\taction x = map_unary float2rad x;\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n        // get a representative image from an arg\n        get_image x\n            = get_image x.value?0, is_Group x\n            = x;\n\n        _im = get_image x; \n\t\tsample = measure_draw (to_real pacross) (to_real pdown) \n\t\t\t\t(to_real measure) _im;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure_sample (to_real pacross) (to_real pdown) \n\t\t\t\t\t(to_real measure) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.6/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x \n\t\t\t= map_unary sobel x\n\t\t{\n\t\t\tsobel im\n\t\t\t\t= abs (a - 128) + abs (b - 128)\n\t\t\t{\n\t\t\t\ta = conv filter_sobel im;\n\t\t\t\tb = conv (rot270 filter_sobel) im;\n\t\t\t}\n\t\t}\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 2;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 20;\n\t\t\tfs = Scale \"Sharpen flat areas by\" 0 5 0.5;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" 0 5 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tlayers = Scale \"Layers\" 1 100 10;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\", \"Approximate\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf, aconvsep layers]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\t\t\trotate = Option \"Rotate\" [\n\t\t\t\t\"Don't rotate\", \n\t\t\t\t\"4 x 45 degrees\", \n\t\t\t\t\"8 x 45 degrees\", \n\t\t\t\t\"2 x 90 degrees\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_lindetect, !separable && type == 0 && rotate == 1\n\t\t\t\t\t\t= im_compass, !separable && type == 0 && rotate == 2\n\t\t\t\t\t\t= im_gradient, !separable && type == 0 && rotate == 3\n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_conv_f, !separable && type == 1\n\t\t\t\t\t\t= im_convsep_f, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 4) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\t\t\tmax_slope = Scale \"Maxium slope\" 0 10 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width \n\t\t\t\t\t\t\twindow_height \n\t\t\t\t\t\t\tmax_slope in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\nFilter_hough_item = class\n\tMenupullright \"_Hough Transform\" \"transform to parameter space\" {\n\tLine_item = class\n\t\tMenuaction \"_Line\" \"find straight line Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpspace_width = Expression \"Parameter space width\" 64;\n\t\t\tpspace_height = Expression \"Parameter space height\" 64;\n\n\t\t\t_result \n\t\t\t\t= map_unary line a \n\t\t\t{\n\t\t\t\tline a \n\t\t\t\t\t= hough_line \n\t\t\t\t\t\t(to_real pspace_width) (to_real pspace_height) a;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class\n\t\tMenuaction \"_Circle\" \"find circle Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Expression \"Scale down parameter space by\" 10;\n\t\t\tmin_radius = Expression \"Minimum radius\" 10;\n\t\t\tmax_radius = Expression \"Maximum radius\" 30;\n\n\t\t\t_result \n\t\t\t\t= map_unary circle a \n\t\t\t{\n\t\t\t\tcircle a \n\t\t\t\t\t= hough_circle (to_real scale) (to_real min_radius)\n\t\t\t\t\t\t(to_real max_radius) a;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_coordinate_item = class\n\tMenupullright \"_Coordinate Transform\" \"various coordinate transforms\" {\n\t// run a function which wants a complex arg on a non-complex two-band\n\t// image\n\trun_cmplx fn x\n\t\t= re x' ++ im x'\n\t{\n\t\tx' = fn (x?0, x?1);\n\t}\n\n\tPolar_item = class\n\t\tMenuaction \"_Polar\" \"transform to polar coordinates\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result \n\t\t\t\t= map_unary to_polar a \n\t\t\t{\n\t\t\t\tto_polar im \n\t\t\t\t\t= mapim interp.value map' im\n\t\t\t\t{\n\t\t\t\t\t// xy image, origin in the centre, scaled to fit image to\n\t\t\t\t\t// a circle\n\t\t\t\t\txy = make_xy im.width im.height;\n\t\t\t\t\txy' = xy - Vector [im.width / 2, im.height / 2];\n\t\t\t\t\tscale = min [im.width, im.height] / im.width;\n\t\t\t\t\txy'' = 2 * xy' / scale;\n\n\t\t\t\t\t// to polar, scale vertical axis to 360 degrees\n\t\t\t\t\tmap = run_cmplx polar xy'';\n\t\t\t\t\tmap' = map * Vector [1, im.height / 360];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tRectangular_item = class\n\t\tMenuaction \"_Rectangular\" \"transform to rectangular coordinates\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result \n\t\t\t\t= map_unary to_rect a \n\t\t\t{\n\t\t\t\tto_rect im \n\t\t\t\t\t= mapim interp.value map'' im\n\t\t\t\t{\n\t\t\t\t\t// xy image, vertical scaled to 360 degrees\n\t\t\t\t\txy = make_xy im.width im.height;\n\t\t\t\t\txy' = xy * Vector [1, 360 / im.height];\n\n\t\t\t\t\t// to rect, scale to image rect\n\t\t\t\t\tmap = run_cmplx rectangular xy';\n\t\t\t\t\tscale = min [im.width, im.height] / im.width;\n\t\t\t\t\tmap' = map * scale / 2;\n\n\t\t\t\t\tmap'' = map' + Vector [im.width / 2, im.height / 2];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image\" \"use an image to blend two objects\" {\n\t\taction a b c = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ti = Toggle \"Invert mask\" false;\n\n\t\t\t_result \n\t\t\t\t= map_trinary process a b c\n\t\t\t{\n\t\t\t\tprocess a b c \n\t\t\t\t\t= blend condition in1 in2, !i\n\t\t\t\t\t= blend (invert condition) in1 in2\n\t\t\t\t{\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t\t= false,\n\t\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t\t= true;\n\t\t\t\t\t[condition, in1, in2] = sortc compare [a, b, c];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"Blend _Alpha\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t_ \"Normal\" => NORMAL,\n\t\t\t_ \"If Lighter\" => IFLIGHTER,\n\t\t\t_ \"If Darker\" => IFDARKER,\n\t\t\t_ \"Multiply\" => MULTIPLY,\n\t\t\t_ \"Add\" => ADD,\n\t\t\t_ \"Subtract\" => SUBTRACT,\n\t\t\t_ \"Screen\" => SCREEN,\n\t\t\t_ \"Burn\" => BURN,\n\t\t\t_ \"Soft Light\" => SOFTLIGHT,\n\t\t\t_ \"Hard Light\" => HARDLIGHT,\n\t\t\t_ \"Lighten\" => LIGHTEN,\n\t\t\t_ \"Darken\" => DARKEN,\n\t\t\t_ \"Dodge\" => DODGE,\n\t\t\t_ \"Reflect\" => REFLECT,\n\t\t\t_ \"Freeze\" => FREEZE,\n\t\t\t_ \"Bitwise OR\" => OR,\n\t\t\t_ \"Bitwise AND\" => AND\n\t\t];\n\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum \"Blend mode\" names \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\t[mono, colour] = \n\t\t\t\t\tsortc (const (is_colour_type @ get_type)) [a, b];\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t_ \"Grey\",\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t_ \"North-west\",\n\t\t\t\t_ \"North\",\n\t\t\t\t_ \"North-east\",\n\t\t\t\t_ \"West\",\n\t\t\t\t_ \"Centre\",\n\t\t\t\t_ \"East\",\n\t\t\t\t_ \"South-west\",\n\t\t\t\t_ \"South\",\n\t\t\t\t_ \"South-east\",\n\t\t\t\t_ \"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nAutotrace_item = class \n\tMenuaction \"_Trace\" \"convert a bitmap to an SVG file\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tdespeckle = Scale \"Despeckle level\" 1 20 1;\n\t\tline = Scale \"Line threshold\" 1 20 1;\n\t\tcenter = Toggle \"Trace centreline\" false;\n\t\tscale = Scale \"SVG scale\" 0.1 10 1;\n\n\t\tcommand \n\t\t\t= \"autotrace %s \" ++ join_sep \" \" \n\t\t\t\t[ofmt, ofile, desp, lint, cent]\n\t\t{\n\t\t\tprog = search_for_error \"autotrace\"; \n\t\t\tofmt = \"-output-format svg\";\n\t\t\tofile = \"-output-file %s\";\n\t\t\tdesp = \"-despeckle-level \" ++ print despeckle.value;\n\t\t\tlint = \"-line-threshold \" ++ print line.value;\n\t\t\tcent = if center then \"-centerline \" else \"\";\n\t\t}\n\n\t\t_result \n\t\t\t= Image output\n\t\t{\n\t\t\t[output] = vips_call \"system\" \n\t\t\t\t[command] \n\t\t\t\t[$in => [x.value],\n\t\t\t\t $in_format => \"%s.ppm\", \n\t\t\t\t $out => true,\n\t\t\t\t $out_format => \"%s.svg[scale=\" ++ print scale.value ++ \"]\"\n\t\t\t\t];\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.6/Histogram.def",
    "content": "Hist_new_item = class\n\tMenupullright \"_New\" \"new histogram\" {\n\tHist_item = class\n\t\tMenuaction \"_Identity\" \"make an identity histogram\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\t_result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d);\n\t\t}\n\t}\n\n\tHist_new_from_matrix = Matrix_buildlut_item; \n\n\tHist_from_image_item = class\n\t\tMenuaction \"Ta_g Image As Histogram\" \"set image Type to Histogram\" {\n\t\taction x = hist_tag x;\n\t}\n\n\tTone_item = class \n\t\tMenuaction \"_Tone Curve\" \"make a new tone mapping curve\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\t_result \n\t\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t\t{\n\t\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_convert_to_hist_item = class \n\tMenuaction \"Con_vert to Histogram\" \"convert anything to a histogram\" {\n\taction x = hist_tag (to_image x);\n}\n\nHist_find_item = class \n\tMenupullright \"_Find\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n\n\tIndexed_item = class\n\t\tMenuaction \"_Indexed\" \n\t\t\t\"use a 1-band index image to pick bins for an n-band image\" {\n\t\taction x y  = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcombine = Combine_picker Combine_type.SUM;\n\n\t\t\t_result\n\t\t\t\t= map_binary map x y\n\t\t\t{\n\t\t\t\tmap a b\n\t\t\t\t\t= hist_find_indexed combine.value index im\n\t\t\t\t{\n\t\t\t\t\t[im, index] = sortc (const is_index) [a, b];\n\n\t\t\t\t\tis_index x\n\t\t\t\t\t\t= has_image x && b == 1 && \n\t\t\t\t\t\t\t(f == Image_format.UCHAR || f == Image_format.USHORT)\n\t\t\t\t\t{\n\t\t\t\t\t\tim = get_image x;\n\t\t\t\t\t\tb = get_bands x;\n\t\t\t\t\t\tf = get_format x;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\t[im, hist] = sortc (const is_hist) [a, b];\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Integrate\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate\" \n\t\t\"find point-to-point differences (inverse of Integrate)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_inv_item = class \n\tMenuaction \"In_vert\" \"invert a histogram\" {\n\taction x = map_unary hist_inv x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\nHist_entropy_item = class Menuaction \"Entropy\" \"calculate histogram entropy\" {\n\taction x = hist_entropy x;\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\tarea = extract_arrow \n\t\t\t\t\tdisplace.value vdisplace.value width.value arrow;\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize Kernel_linear 1 (1 / width.value) area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary (extract_arrow \n\t\t\t\tdisplace.value vdisplace.value width.value) x;\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcaption = Expression \"Chart caption\" \"none\";\n\t\tformat = Option_enum \"Format\" Plot_format.names \"YYYY\";\n\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\t\txcaption = Expression \"X axis caption\" \"none\";\n\t\tycaption = Expression \"Y axis caption\" \"none\";\n\t\tseries_captions = Expression \"Series captions\" [\"Band 0\"];\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => style.value, $format => format.value] ++ \n\t\t\t\t\trange ++ captions;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\tcaptions \n\t\t\t\t= concat (map test caption_options) ++ \n\t\t\t\t  [$series_captions => series_captions.expr]\n\t\t\t{\n\t\t\t\tcaption_options = [\n\t\t\t\t\t$caption => caption.expr,\n\t\t\t\t\t$xcaption => xcaption.expr,\n\t\t\t\t\t$ycaption => ycaption.expr\n\t\t\t\t];\n\t\t\t\ttest x\n\t\t\t\t\t= [], value == \"none\"\n\t\t\t\t\t= [option_name => value]\n\t\t\t\t{\n\t\t\t\t\t[option_name, value] = x;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow 0 0 1 x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.6/Image.def",
    "content": "Image_new_item = class Menupullright \"_New\" \"make new things\" {\n\tImage_black_item = class Menuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \"Image type\"\n\t\t\t\tImage_type.type_names \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region on image using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\t[target, x] = sortc compare [a, b];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\nImage_number_format_item = class\n\tMenupullright \"_Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_header_item = class \n\tMenupullright \"_Header\" \"do stuff to the image header\" {\n\n\tImage_get_item = class\n\t\tMenupullright \"_Get\" \"get header fields\" {\n\n\t\t// the header fields we can get\n\t\tfields = class {\n\t\t\ttype = 0;\n\t\t\twidth = 1;\n\t\t\theight = 2;\n\t\t\tformat = 3;\n\t\t\tbands = 4;\n\t\t\txres = 5;\n\t\t\tyres = 6;\n\t\t\txoffset = 7;\n\t\t\tyoffset = 8;\n\t\t\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t$width => width,\n\t\t\t\t$height => height,\n\t\t\t\t$bands => bands,\n\t\t\t\t$format => format,\n\t\t\t\t$type => type,\n\t\t\t\t$xres => xres,\n\t\t\t\t$yres => yres,\n\t\t\t\t$xoffset => xoffset,\n\t\t\t\t$yoffset => yoffset,\n\t\t\t\t$coding => coding\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum (_ \"Field\") field_names name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tCustom_item = class\n\t\t\tMenuaction \"C_ustom\" \"get any header field\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tfield = String \"Field\" \"Xsize\";\n\t\t\t\tparse = Option \"Parse\" [\n\t\t\t\t\t\"No parsing\",\n\t\t\t\t\t\"Parse string as integer\",\n\t\t\t\t\t\"Parse string as real\",\n\t\t\t\t\t\"Parse string as hh:mm:ss\"\n\t\t\t\t] 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary (wrap @ process @ get_header field.value) x\n\t\t\t\t{\n\t\t\t\t\tparse_str parse str = parse (split is_space str)?0;\n\n\t\t\t\t\tparse_field name cast parse x\n\t\t\t\t\t\t= cast x, is_number x\n\t\t\t\t\t\t= parse_str parse x, is_string x\n\t\t\t\t\t\t= error (\"not \" ++ name);\n\n\t\t\t\t\tget_int = parse_field \"int\" \n\t\t\t\t\t\tcast_signed_int parse_int;\n\t\t\t\t\tget_float = parse_field \"float\" \n\t\t\t\t\t\tcast_float parse_float;\n\t\t\t\t\tget_time = parse_field \"hh:mm:ss\" \n\t\t\t\t\t\tcast_signed_int parse_time;\n\n\t\t\t\t\twrap x\n\t\t\t\t\t\t= Real x, is_real x\n\t\t\t\t\t\t= Vector x, is_real_list x\n\t\t\t\t\t\t= Image x, is_image x\n\t\t\t\t\t\t= Bool x, is_bool x\n\t\t\t\t\t\t= Matrix x, is_matrix x\n\t\t\t\t\t\t= String \"String\" x, is_string x\n\t\t\t\t\t\t= List x, is_list x\n\t\t\t\t\t\t= x;\n\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tget_int, \n\t\t\t\t\t\tget_float,\n\t\t\t\t\t\tget_time\n\t\t\t\t\t]?parse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum \"Image type\" Image_type.type_names \n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_cache_item = class\n\tMenuaction \"C_ache\" \"cache calculated image pixels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttile_width = Number \"Tile width\" 128;\n\t\ttile_height = Number \"Tile height\" 128;\n\t\tmax_tiles = Number \"Maximum number of tiles to cache\" (-1);\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= cache (to_real tile_width) (to_real tile_height) \n\t\t\t\t\t(to_real max_tiles) image;\n\t\t}\n\t}\n}\n\n#separator\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\t// we can't use id here since we want to \"declass\"\n\t\t\t\t\t\t// the members of x ... consider if x is a crop class,\n\t\t\t\t\t\t// for example, we don't want to inherit from crop, we\n\t\t\t\t\t\t// want to make a new image class\n\t\t\t\t\t\trot180 @ rot180,\n\t\t\t\t\t\trot90,\n\t\t\t\t\t\trot180,\n\t\t\t\t\t\trot270\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate interp angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary straighten x\n\t\t\t\t{\n\t\t\t\t\tstraighten arrow\n\t\t\t\t\t\t= rotate interp angle'' arrow.image\n\t\t\t\t\t{\n\t\t\t\t\t\tx = arrow.width;\n\t\t\t\t\t\ty = arrow.height;\n\t\t\n\t\t\t\t\t\tangle = im (polar (x, y));\n\t\t\n\t\t\t\t\t\tangle'\n\t\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t\t= angle;\n\t\t\n\t\t\t\t\t\tangle''\n\t\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize kernel xfactor yfactor image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\taspect = Toggle \"Break aspect ratio\" false;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize kernel h v image, aspect\n\t\t\t\t\t\t= resize kernel fac fac image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac > yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\tmin_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac < yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\t[h, v] = [\n\t\t\t\t\t\t\tmax_factor, \n\t\t\t\t\t\t\tmin_factor, \n\t\t\t\t\t\t\t[xfac, 1], \n\t\t\t\t\t\t\t[1, yfac]]?which;\n\n\t\t\t\t\t\tfac \n\t\t\t\t\t\t\t= h, v == 1\n\t\t\t\t\t\t\t= v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_within_item = class\n\t\t\tMenuaction \"Size _Within\" \"size to fit within a rectangle\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\t// the rects we size to fit within\n\t\t\t\t_rects = [\n\t\t\t\t\t[2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], \n\t\t\t\t\t[1280, 1024], [1024, 768], [800, 600], [640, 480] \n\t\t\t\t];\n\n\t\t\t\twithin = Option \"Fit within (pixels)\" (\n\t\t\t\t\t[print w ++ \" x \" ++ print h :: [w, h] <- _rects] ++\n\t\t\t\t\t[\"Custom\"]\n\t\t\t\t) 4;\n\t\t\t\tcustom_width = Expression \"Custom width\" 1000;\n\t\t\t\tcustom_height = Expression \"Custom height\" 1000;\n\t\t\t    size = Option \"Page size\" [\n\t\t\t\t\t\"Full page\", \"Half page\", \"Quarter page\" \n\t\t\t\t] 0;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t \t_result\n\t\t\t\t \t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\txdiv = [1, 2, 2]?size;\n\t\t\t\t\tydiv = [1, 1, 2]?size;\n\t\t\t\t\tallrect = _rects ++ [\n\t\t\t\t\t\t[custom_width.expr, custom_height.expr]\n\t\t\t\t\t];\n\t\t\t\t\t[width, height] = allrect?within;\n\n\t\t\t\t\tprocess x\n\t\t\t\t\t\t= resize kernel fac fac x, fac < 1\n\t\t\t\t\t\t= x\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = (width / xdiv) / x.width;\n\t\t\t\t\t\tyfac = (height / ydiv) / x.height;\n\t\t\t\t\t\tfac = min_pair xfac yfac;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_map_item = class\n\t\tMenuaction \"_Map\" \"map an image through a 2D transform image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result\n\t\t\t\t= map_binary trans a b\n\t\t\t{\n\t\t\t\ttrans a b\n\t\t\t\t\t= mapim interp.value in index\n\t\t\t\t{\n\t\t\t\t\t// get the index image first\n\t\t\t\t\t[index, in] = sortc (const is_twocomponent) [a, b];\n\n\t\t\t\t\t// is a two-component image, ie. one band complex, or\n\t\t\t\t\t// two-band non-complex\n\t\t\t\t\tis_twocomponent x\n\t\t\t\t\t\t= is_nonc x || is_c x;\n\t\t\t\t\tis_nonc x\n\t\t\t\t\t\t= has_bands x && get_bands x == 2 && \n\t\t\t\t\t\t\thas_format x && !is_complex_format (get_format x);\n\t\t\t\t\tis_c x\n\t\t\t\t\t\t= has_bands x && get_bands x == 1 && \n\t\t\t\t\t\t\thas_format x && is_complex_format (get_format x);\n\t\t\t\t\tis_complex_format f\n\t\t\t\t\t\t= f == Image_format.COMPLEX || \n\t\t\t\t\t\t\tf == Image_format.DPCOMPLEX;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\" [\"Nearest\", \"Bilinear\"] 1;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_trn {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t[sample', trn, err] = transform_search \n\t\t\t\t\tmax_err max_iter order interp wrap\n\t\t\t\t\tsample reference;\n\t\t\t\ttransformed_image = Image sample';\n\t\t\t\t_trn = Transform trn reference.width reference.height;\n\t\t\t\tfinal_error = err;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\t[i, t] = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tBandwise_item = Image_join_item.Bandwise_item;\n\n    sep1a = Menuseparator;\n\n\tBandand_item = class\n\t\tMenuaction \"Bitwise Band AND\" \"bitwise AND of image bands\" {\n\t\taction x = bandand x;\n\t}\n\n\tBandor_item = class\n\t\tMenuaction \"Bitwise Band OR\" \"bitwise OR of image bands\" {\n\t\taction x = bandor x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldl1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_alpha_item = class \n\tMenupullright \"_Alpha\" \"manipulate image alpha\" {\n\n\tAdd_item = class Menuaction \"_Add\" \"add alpha\" {\n\t\taction x = class\n\t\t\t_result { \n\t\t\t_vislevel = 3;\n\n\t\t\topacity = Expression \"Opacity (255 == solid)\" 255;\n\t\t\t\n\t\t\t_result = x ++ to_real opacity;\n\t\t}\n\t}\n\n\tFlatten_item = class Menuaction \"_Flatten\" \"flatten alpha out of image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbg = Expression \"Background\" 0;\n\n\t\t\t_result = map_unary (flattenimage bg) x;\n\t\t}\n\t}\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract alpha\" {\n\t\taction x \n\t\t\t= map_unary exb x\n\t\t{\n\t\t\texb x = extract_bands (x.bands - 1) 1 x;\n\t\t}\n\t}\n\n\tDrop_item = class Menuaction \"_Drop\" \"drop alpha\" {\n\t\taction x \n\t\t\t= map_unary exb x\n\t\t{\n\t\t\texb x = extract_bands 0 (x.bands - 1) x;\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tPremultiply_item = class Menuaction \"_Premultiply\" \"premultiply alpha\" {\n\t\taction x = premultiply x;\n\t}\n\n\tUnpremultiply_item = class \n\t\tMenuaction \"_Unpremultiply\" \"unpremultiply alpha\" {\n\t\taction x = unpremultiply x; \n\t}\n\n    sep2 = Menuseparator;\n\n\tComposite2_item = class \n\t\tMenuaction \"_Composite two\" \"composite a pair of images\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tblend = Option_enum (_ \"Blend mode\") modes \"over\"\n\t\t\t{\n\t\t\t\tmodes = Blend_type.types;\n\t\t\t}\n\t\t\tcompositing_space = Option_enum (_ \"Compositing space\") spaces \"sRGB\"\n\t\t\t{\n\t\t\t\tspaces = Image_type.image_colour_spaces;\n\t\t\t}\n\t\t\tpremultiplied = Toggle (_ \"Premultiplied\") false;\n\n\t\t\t_result \n\t\t\t\t= Image output\n\t\t\t{\n\t\t\t\t[output] = vips_call \"composite\" \n\t\t\t\t\t[[y.value, x.value], blend.value] \n\t\t\t\t\t[$compositing_space => compositing_space.value_thing,\n\t\t\t\t\t $premultiplied => premultiplied.value\n\t\t\t\t\t];\n\t\t\t}\n\t\t}\n\t}\n\n\tComposite3_item = class \n\t\tMenuaction \"_Composite three\" \"composite three images\" {\n\t\taction x y z = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tblend1 = Option_enum (_ \"Blend mode\") modes \"over\"\n\t\t\t{\n\t\t\t\tmodes = Blend_type.types;\n\t\t\t}\n\t\t\tblend2 = Option_enum (_ \"Blend mode\") modes \"over\"\n\t\t\t{\n\t\t\t\tmodes = Blend_type.types;\n\t\t\t}\n\t\t\tcompositing_space = Option_enum (_ \"Compositing space\") spaces \"sRGB\"\n\t\t\t{\n\t\t\t\tspaces = Image_type.image_colour_spaces;\n\t\t\t}\n\t\t\tpremultiplied = Toggle (_ \"Premultiplied\") false;\n\n\t\t\t_result \n\t\t\t\t= Image output\n\t\t\t{\n\t\t\t\t[output] = vips_call \"composite\" \n\t\t\t\t\t[[z.value, y.value, x.value], [blend1.value, blend2.value]] \n\t\t\t\t\t[$compositing_space => compositing_space.value_thing,\n\t\t\t\t\t $premultiplied => premultiplied.value\n\t\t\t\t\t];\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x \n\t\t= crop x [l, t, w, h]\n\t{\n\t\tfields = [\n\t\t\t[has_left, get_left, 0],\n\t\t\t[has_top, get_top, 0],\n\t\t\t[has_width, get_width, 100],\n\t\t\t[has_height, get_height, 100]\n\t\t];\n\n\t\t[l, t, w, h] \n\t\t\t= map get_default fields\n\t\t{\n\t\t\tget_default line\n\t\t\t\t= get x, has x\n\t\t\t\t= default\n\t\t\t{\n\t\t\t\t[has, get, default] = line;\n\t\t\t}\n\t\t}\n\t}\n\n\tcrop x geo = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tl = Expression \"Crop left\" ((int) (geo?0 + geo?2 / 4));\n\t\tt = Expression \"Crop top\" ((int) (geo?1 + geo?3 / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (geo?2 / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (geo?3 / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t[_a', _b'] = sortc _pred [a, b];\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_draw_item = class \n\tMenupullright \"_Draw\" \"draw lines, circles, rectangles, floods\" {\n\tLine_item = class Menuaction \"_Line\" \"draw line on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tx1 = Expression \"Start x\" 0;\n\t\t\ty1 = Expression \"Start y\" 0;\n\t\t\tx2 = Expression \"End x\" 100;\n\t\t\ty2 = Expression \"End y\" 100;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary line x\n\t\t\t{\n\t\t\t\tline im \n\t\t\t\t\t= draw_line x1 y1 x2 y2 i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tRect_item = class Menuaction \"_Rectangle\" \"draw rectangle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\trx = Expression \"Left\" 50;\n\t\t\try = Expression \"Top\" 50;\n\t\t\trw = Expression \"Width\" 100;\n\t\t\trh = Expression \"Height\" 100;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\tt = Scale \"Line thickness\" 1 50 3;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary rect x\n\t\t\t{\n\t\t\t\trect im \n\t\t\t\t\t= draw_rect_width rx ry rw rh f t i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class Menuaction \"_Circle\" \"draw circle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcx = Expression \"Centre x\" 100;\n\t\t\tcy = Expression \"Centre y\" 100;\n\t\t\tr = Expression \"Radius\" 50;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary circle x\n\t\t\t{\n\t\t\t\tcircle im \n\t\t\t\t\t= draw_circle cx cy r f i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tFlood_item = class Menuaction \"_Flood\" \"flood bounded area of image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsx = Expression \"Start x\" 0;\n\t\t\tsy = Expression \"Start y\" 0;\n\n\t\t\te = Option \"Flood while\" [\n\t\t\t\t\"Not equal to ink\",\n\t\t\t\t\"Equal to start point\"\n\t\t\t] 0;\n\n\t\t\t// pick a default ink that won't flood, if we can\n\t\t\ti \n\t\t\t\t= Expression \"Ink\" default_ink\n\t\t\t{\n\t\t\t\tdefault_ink\n\t\t\t\t\t= [0], ! has_image x\n\t\t\t\t\t= pixel;\n\t\t\t\tpixel = map mean (bandsplit (extract_area sx sy 1 1 im));\n\t\t\t\tim = get_image x;\n\t\t\t}\n\n\t\t\t_result \n\t\t\t\t= map_unary flood x\n\t\t\t{\n\t\t\t\tflood im \n\t\t\t\t\t= draw_flood sx sy i.expr im, e == 0\n\t\t\t\t\t= draw_flood_blob sx sy i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tDraw_scalebar_item = class Menuaction \"_Scale\" \"draw scale bar\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpx = Expression \"Left\" 50;\n\t\t\tpy = Expression \"Top\" 50;\n\t\t\twid = Expression \"Width\" 100;\n\t\t\tthick = Scale \"Line thickness\" 1 50 3;\n\t\t\ttext = String \"Dimension text\" \"50μm\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\tpos = Option \"Position Text\" [\"Above\", \"Below\"] 1;\n\t\t\tvp = Option \"Dimension by\" [\n\t\t\t\t\"Inner Vertical Edge\", \n\t\t\t\t\"Centre of Vertical\", \n\t\t\t\t\"Outer Vertical Edge\"\n\t\t\t] 1;\n            dpi = Expression \"DPI\" 100;\n            ink = Colour \"Lab\" [50,0,0];\n      \n            _result\n                = map_unary process x\n            {\n                process im\n                    = blend (Image scale) ink' im\n                {\n                    // make an ink compatible with the image\n                    ink' = colour_transform_to (get_type im) ink;\n\n                    x = to_real px;\n                    y = to_real py;\n                    w = to_real wid;\n                    d = to_real dpi;\n\n                    t = floor thick;\n\n                    bg = image_new (get_width im) (get_height im) (get_bands im)\n                        (get_format im) (get_coding im) (get_type im) 0 0 0;\n                    draw_block x y w t im =\n                        draw_rect_width x y w t true 1 [255] im;\n                    label = im_text text.value font.value w 1 d;\n                    lw = get_width label;\n                    lh = get_height label;\n                    ly = [y - lh - t, y + 2 * t]?pos;\n                    vx = [\n\t\t\t\t\t\t[x - t, x + w],\n\t\t\t\t\t\t[x - t / 2, x + w - t / 2],\n\t\t\t\t\t\t[x, x + w - t]\n\t\t\t\t\t]?vp;\n\n\t\t\t\t\tscale = (draw_block x y w t @\n\t\t\t\t\t\tdraw_block vx?0 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tdraw_block vx?1 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tinsert_noexpand (x + w / 2 - lw / 2) ly label)\n\t\t\t\t\t\tbg;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise Join\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t// we can't use map_unary since chop-into-tiles returns a group of\n\t\t\t// groups and we want to be able to reassemble that\n\t\t\t// TODO: chop-into-tiles should return an array class which\n\t\t\t// displays as group but does not have the looping behaviour?\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n\n\tArrayFL_item = class\n\t\tMenuaction \"_Array from List\"\n\t\t\t\"join a list of images into a single image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tncol = Number \"Max. Number of Columns\" 1;\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\t\t\tsnake = Toggle \"Reverse the order of every other row\" false; \n\n\t\t\t_l \n\t\t\t\t= split_lines ncol.value x.value, is_Group x\n\t\t\t\t= split_lines ncol.value x;\n\n\t\t\t_l'\n\t\t\t\t= map2 reverse_if_odd [0..] _l, snake\n\t\t\t\t= _l\n\t\t\t{\n\t\t\t\treverse_if_odd n x\n\t\t\t\t\t= reverse x, n % 2 == 1\n\t\t\t\t\t= x;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= (image_set_origin 0 0 @\n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value\n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list _l'));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tNoise_item = class\n\t\tMenupullright \"_Noise\" \"various noise generators\" {\n\t\tGaussian_item = class \n\t\t\tMenuaction \"_Gaussian\" \"make an image of gaussian noise\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t\t_result = Image (gaussnoise nwidth nheight \n\t\t\t\t\tmean.value deviation.value);\n\t\t\t}\n\t\t}\n\n\t\tFractal_item = class \n\t\t\tMenuaction \"_Fractal\" \"make a fractal noise image\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t\t}\n\t\t}\n\n\t\tPerlin_item = class \n\t\t\tMenuaction \"_Perlin\" \"Perlin noise image\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\t\tcell_size = Expression \"Cell size (pixels)\" 8;\n\t\t\t\teight = Toggle \"Eight bit output\" true;\n\n\t\t\t\t_result \n\t\t\t\t\t= 128 * im + 128, eight\n\t\t\t\t\t= im\n\t\t\t\t{\n\t\t\t\t\tim = perlin cell_size nwidth nheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tWorley_item = class \n\t\t\tMenuaction \"_Worley\" \"Worley noise image\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnwidth = Expression \"Image width (pixels)\" 512;\n\t\t\t\tnheight = Expression \"Image height (pixels)\" 512;\n\t\t\t\tcell_size = Expression \"Cell size (pixels)\" 256;\n\n\t\t\t\t_result \n\t\t\t\t\t= worley cell_size nwidth nheight;\n\t\t\t}\n\t\t}\n\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\twrap = Expression \"Wrap text at\" 500;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\n\t\t\t_result = Image (im_text text.value font.value \n\t\t\t\t(to_real wrap) align.value (to_real dpi));\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n\tColour_atlas_item = class\n\tMenuaction \"_Colour Atlas\"\n\t\t\"make a grid of patches grouped around a colour\" {\n\t\taction = class \n\t\t\t_result {   \n\t\t\t_vislevel = 3;\n       \n\t\t\tstart = Colour_picker \"Lab\" [50,0,0];\n\t\t\tnstep = Expression \"Number of steps\" 9;\n\t\t\tssize = Expression \"Step size\" 10; \n\t\t\tpsize = Expression \"Patch size\" 32;\n\t\t\tsepsize = Expression \"Separator size\" 4;\n\t\n\t\t\t_result\n\t\t\t\t= colour_transform_to (get_type start) blocks'''\n\t\t\t{\n\t\t\t\tsize = (to_real nstep * 2 + 1) * to_real psize - \n\t\t\t\t\tto_real sepsize;\n\t\t\t\txy = make_xy size size; \n\n\t\t\t\txy_grid = (xy % to_real psize) < \n\t\t\t\t\t(to_real psize - to_real sepsize);\n\t\t\t\tgrid = xy_grid?0 & xy_grid?1;\n\n\t\t\t\tblocks = (int) (to_real ssize * ((int) (xy / to_real psize)));\n\t\t\t\tlab_start = colour_transform_to Image_type.LAB start;\n\t\t\t\tblocks' = blocks - to_real nstep * to_real ssize + \n\t\t\t\t\tVector (tl lab_start.value);\n\t\t\t\tblocks'' = hd lab_start.value ++ Image blocks';\n\t\t\t\tblocks''' \n\t\t\t\t\t= image_set_type Image_type.LAB blocks'', Image grid\n\t\t\t\t\t= 0;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.6/Magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate Magick.def\n   13-Apr-2014 snibgo\n     Put \"new image\" items into sub-menu.\n     New class VirtualPixlBack.\n   17-Apr-2014 snibgo\n     Many small changes.\n     A few new menu options.\n     Created sub-menu for multi-input operations.\n   3-May-2014 jcupitt\n     Put quotes around ( in shadow to help unix\n\n   Last update: 17-Apr-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n*/\n\n// We don't need Noop.\n/*===\nMagick_noop_item = class\n\tMenuaction \"_Noop\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_testPar_item = class\n\tMenuaction \"_TestPar\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"( +clone ) +append \",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/* Removed Read_item and Write_item, much better to use nip2 load/save image.\n * Plus they can load all libMagick formats anyway.\n */\n\n\n// Put \"new image\" items into sub-menu\nMagick_NewImageMenu_item = class\n\tMenupullright \"_New image\" \"make a new image\" {\n\n\tMagick_newcanvas_item = class\n\t\tMenuaction \"_Solid colour\" \"make image of solid colour\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tcolour = Magick.generalcol_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"\\\"canvas:\" ++ colour._flag ++ \"\\\"\", \n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_builtin_item = class\n\t\tMenuaction \"_Built-in image\" \"create a built-in image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbuiltin = Magick.builtin_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tbuiltin._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_gradient_item = class\n\t\tMenuaction \"_Gradient\" \"make a linear gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\ttopColour = Magick.generalcol_widget;\n\t\t\tbottomColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"gradient:\", \n\t\t\t\t\ttopColour._flag, \"-\", bottomColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_hald_item = class\n\t\tMenuaction \"_Hald-clut image\" \"create an identity hald-clut image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torder = Expression \"order\" 8;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"hald:\" ++ print order.expr,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_pattern_item = class\n\t\tMenuaction \"_Pattern\" \"create pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tpattern = Magick.pattern_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tpattern._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_plasma_item = class\n\t\tMenuaction \"_Plasma image\" \"create plasma image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\t// FIXME? ColourA-ColourB.\n\t\t\t// FIXME? Allow plasma:fractal?\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"plasma:\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_radialgradient_item = class\n\t\tMenuaction \"_Radial gradient\" \n\t\t\t\"make a radial gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tinnerColour = Magick.generalcol_widget;\n\t\t\touterColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"radial-gradient:\", \n\t\t\t\t\tinnerColour._flag, \"-\", outerColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n}  // end Magick_NewImageMenu_item\n\n\nMagick_MultiMenu_item = class\n\tMenupullright \"_Multiple inputs\" \"make an image from multiple images\" {\n\n\tMagick_composite_item = class\n\t\tMenuaction \"_Composite\" \"composite two images (without mask)\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag,\n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_compositeMask_item = class\n\t\tMenuaction \"_Composite masked\" \"composite two images (with mask)\" {\n\t\taction x y z = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag, \n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system3 command x y z; \n\t\t}\n\t}\n\n\t// FIXME: other operations like remap that take another image as arguments are:\n\t// mask (pointless?), texture, tile (pointless?)\n\n\t// FIXME: operations that take a filename that isn't an image:\n\t// cdl, profile\n\n\tMagick_clut_item = class\n\t\tMenuaction \"_Clut\" \"replace values using second image as colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// FIXME: uses -intensity \"when mapping greyscale CLUT image to alpha channel if set by -channels\"\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_haldclut_item = class\n\t\tMenuaction \"_Hald clut\" \"replace values using second image as Hald colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-hald-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\n\t// Encipher and decipher: key files can be text or image files.\n\n\tMagick_encipher_item = class\n\t\tMenuaction \"_Encipher/Decipher\" \"encipher or decipher an image image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname = Pathname \"Read key file\" \"\";\n\t\t\tisDecipher = Toggle \"Decipher\" false;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname.value == \"\" then \"\" else (\n\t\t\t\t\t( if isDecipher then \"-decipher \" else \"-encipher \") ++\n\t\t\t\t\t( \"\\\"\" ++ pathname.value ++ \"\\\"\" )\n\t\t\t\t),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_profile_item = class\n\t\tMenuaction \"_Profile\" \"assigns/applies an ICC profile\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname1 = Pathname \"Read profile file\" \"\";\n\t\t\tpathname2 = Pathname \"Read profile file\" \"\";\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname1.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname1.value ++ \"\\\"\"),\n\t\t\t\tif pathname2.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname2.value ++ \"\\\"\"),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_remap_item = class\n\t\tMenuaction \"_Remap\" \"reduce colours to those in another image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-remap\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n}  // end Magick_MultiMenu_item\n\n\nMagick_image_type_item = class\n\tMenuaction \"_Image Type\" \"change image type\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\timagetype = Magick.imagetype_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\timagetype._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nsep2 = Menuseparator;\n\nMagick_alpha_item = class\n\tMenuaction \"_Alpha\" \"add/remove alpha channel\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\talpha = Magick.alpha_widget; \n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\talpha._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_annotate_item = class\n\tMenuaction \"_Annotate\" \"add text annotation\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttext = Magick.text_widget;\n\t\tfont = Magick.Font_widget;\n\t\tgeometry = Magick.AnnotGeometry_widget; \n\t\tgravity = Magick.gravity_widget; \n\t\tforeground = Magick.foreground_widget;\n\t\tundercol = Magick.undercol_widget;\n\t\tantialias = Magick.antialias_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfont._flag,\n\t\t\tantialias._flag,\n\t\t\tgravity._flag,\n\t\t\tforeground._flag,\n\t\t\tundercol._flag,\n\t\t\t\"-annotate\", \n\t\t\tgeometry._flag, \n\t\t\t\"\\\"\" ++ text.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoGamma_item = class\n\tMenuaction \"_AutoGamma\" \"automatic gamma\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-gamma\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoLevel_item = class\n\tMenuaction \"_AutoLevel\" \"automatic level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-level\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_blurSharpMenu_item = class\n\tMenupullright \"_Blur/Sharpen\" \"blur and sharpen\" {\n\n\tMagick_adaptive_blur_item = class\n\t\tMenuaction \"_Adaptive Blur\" \"blur less near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\t// note: adaptive-blur doesn't regard VP.\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-adaptive-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blur_item = class\n\t\tMenuaction \"_Blur\" \"blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_gaussianBlur_item = class\n\t\tMenuaction \"_Gaussian Blur\" \"blur with a Gaussian operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-gaussian-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_motionBlur_item = class\n\t\tMenuaction \"_Motion Blur\" \"simulate motion blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tangle = Scale \"angle\" (-360) 360 0;\n\t\t\tchannels = Magick.ch_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-motion-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_rotationalBlur_item = class\n\t\tMenuaction \"_RotationalBlur\" \"blur around the centre\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-radial-blur\", \n\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_selectiveBlur_item = class\n\t\tMenuaction \"_Selective Blur\" \"blur where contrast is less than or equal to threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-selective-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++  \"+\" ++\n\t\t\t\t\tprint threshold.value ++ \"%%\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMagick_adaptive_sharpen_item = class\n\t\tMenuaction \"_Adaptive Sharpen\" \"sharpen more near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\t\"-adaptive-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_sharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"sharpen\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_unsharpen_item = class\n\t\tMenuaction \"_Unsharp\" \"sharpen with unsharp mask\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tgain = Scale \"Gain\" (-10) 10 1;\n\t\t\tthreshold = Scale \"Threshold\" 0 1 0.05;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-unsharp\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint gain.value ++ \"+\" ++\n\t\t\t\t\tprint threshold.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end BlurSharpMenu_item\n\n\nMagick_border_item = class\n\tMenuaction \"_Border\" \"add border of given colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcompose = Magick.compose_widget;\n\t\twidth = Expression \"Width\" 3;\n\t\tbordercol = Magick.bordercol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag,\n\t\t\tbordercol._flag,\n\t\t\t\"-border\", \n\t\t\tprint width.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_brightCont_item = class\n\tMenuaction \"_Brightness-contrast\" \"adjust the brightness and/or contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbri = Scale \"brightness\" (-100) 100 0;\n\t\tcon = Scale \"contrast\" (-100) 100 0;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-brightness-contrast\", \n\t\t\tprint bri.value ++ \"x\" ++ print con.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// Note: canny requires ImageMagick 6.8.9-0 or later.\n\nMagick_canny_item = class\n\tMenuaction \"_Canny\" \"detect a wide range of edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tlowPc = Scale \"lower percent\" 0 100 10;\n\t\thighPc = Scale \"lower percent\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-canny\", \n\t\t\tconcat [\"\\\"\",\n\t\t\t\tprint radius.value ++ \"x\" ++ \n\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\tprint lowPc.value ++ \"%%+\" ++\n\t\t\t\tprint highPc.value ++ \"%%\" ++ \"\\\"\"\n\t\t\t],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_charcoal_item = class\n\tMenuaction \"_Charcoal\" \"simulate a charcoal drawing\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tfactor = Scale \"factor\" 0 50 1;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-charcoal\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_chop_item = class\n\tMenuaction \"_Chop\" \"remove pixels from the interior\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-chop\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorize_item = class\n\tMenuaction \"_Colorize\" \"colorize by given amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tval = Scale \"value\" 0 100 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-colorize\", \n\t\t\tprint val.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colors_item = class\n\tMenuaction \"_Colors\" \"reduce number of colors\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\t\tquantize = Magick.colorspace_widget;\n\t\tcolors = Expression \"Colours\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-quantize\", quantize._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\tdither._flag,\n\t\t\t\"-colors\", \n\t\t\tprint colors.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: color-matrix?\n\nMagick_colorspace_item = class\n\tMenuaction \"_Colourspace\" \"convert to arbitrary colourspace\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolsp = Magick.colorspace_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-colorspace\",\n\t\t\tcolsp._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorspaceGray_item = class\n\tMenuaction \"_Colourspace gray\" \"convert to gray using given intensity method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-colorspace gray\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrast_item = class\n\tMenuaction \"_Contrast\" \"increase or reduce the contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tisReduce = Toggle \"reduce contrast\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t(if isReduce then \"+\" else \"-\") ++ \"contrast\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrastStretch_item = class\n\tMenuaction \"_Contrast stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-contrast-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: convolve (bias, kernel)\n\nMagick_crop_item = class\n\tMenuaction \"_Crop\" \"cut out a rectangular region\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-crop\",\n\t\t\tgeometry._flag,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_deskew_item = class\n\tMenuaction \"_Deskew\" \"straighten the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\t// FIXME: toggle auto-crop?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-deskew\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_despeckle_item = class\n\tMenuaction \"_Despeckle\" \"reduce the speckles\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-despeckle\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_distort_item = class\n\tMenuaction \"_Distort\" \"distort using a method and arguments\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tdistort = Magick.distort_widget;\n\t\targs = String \"Arguments\" \"1,0\";\n\t\tisPlus = Toggle \"Extend to show entire image\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t(if isPlus then \"+\" else \"-\") ++ \"distort\",\n\t\t\tdistort._flag,\n\t\t\targs.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_draw_item = class\n\tMenuaction \"_Draw\" \"annotate with one or more graphic primitives\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\targs = String \"Arguments\" \"line 0,0 9,9 rectangle 10,10 20,20\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-draw\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_edge_item = class\n\tMenuaction \"_Edge\" \"detect edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-edge\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_emboss_item = class\n\tMenuaction \"_Emboss\" \"emboss\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-emboss\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_enhance_item = class\n\tMenuaction \"_Enhance\" \"enhance a noisy image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-enhance\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_equalize_item = class\n\tMenuaction \"_Equalize\" \"equalize the histogram\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-equalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_evaluate_item = class\n\tMenuaction \"_Evaluate\" \"evaluate an expression on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\toperation = Magick.evaluate_widget;\n\t\tval = Expression \"value\" 5;\n\t\tisPc = Toggle \"Value is percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag, \n\t\t\toperation._flag, \n\t\t\tprint val.expr ++ if isPc then \"%%\" else \"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_extent_item = class\n\tMenuaction \"_Extent\" \"set the image size and offset\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-extent\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_FlipFlopMenu_item = class\n\tMenupullright \"_Flip/flop\" \"flip/flop/transverse/transpose\" {\n\n\tMagick_flip_item = class\n\t\tMenuaction \"_Flip vertically\" \"mirror upside-down\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flip\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_flop_item = class\n\t\tMenuaction \"_Flop horizontally\" \"mirror left-right\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flop\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transpose_item = class\n\t\tMenuaction \"_Transpose\" \"mirror along the top-left to bottom-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transpose +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transverse_item = class\n\t\tMenuaction \"_Transverse\" \"mirror along the bottom-left to top-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transverse +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end Magick_FlipFlopMenu_item\n\n\nMagick_floodfill_item = class\n\tMenuaction \"_Floodfill\" \"recolour neighbours that match\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tfuzz = Magick.fuzz_widget;\n\t\tcoordinate = Magick.coordinate_widget;\n\n\t\t// -draw \"color x,y floodfill\"\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-draw \\\" color\",\n\t\t\tcoordinate._flag,\n\t\t\t\"floodfill \\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_frame_item = class\n\tMenuaction \"_Frame\" \"surround with border or beveled frame\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tborder = Magick.bordercol_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tmatte = Magick.mattecol_widget;\n\t\tgeometry = Magick.FrameGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tborder._flag, \n\t\t\tmatte._flag, \n\t\t\t\"-frame\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_function_item = class\n\tMenuaction \"_Function\" \"evaluate a function on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfunction = Magick.function_widget;\n\t\t// FIXME: explain values; use sensible defaults.\n\t\tvalues = String \"values\" \"0,0,0,0\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-function\", \n\t\t\tfunction._flag, \n\t\t\tvalues.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_fx_item = class\n\tMenuaction \"_Fx\" \"apply a mathematical expression\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\targs = String \"Expression\" \"u*1/2\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\tinterpolate._flag,\n\t\t\tvirtpixback._flag,\n\t\t\t\"-fx\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gamma_item = class\n\tMenuaction \"_Gamma\" \"apply a gamma correction\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tgamma = Magick.gamma_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-gamma\",\n\t\t\tprint gamma.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradient_item = class\n\tMenuaction \"_Gradient\" \"apply a linear gradient\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolourA = Magick.generalcol_widget;\n\t\tcolourB = Magick.generalcol_widget;\n\n\t\tposition = Option \"colourA is at\" [\n\t\t\t\t\"top\", \"bottom\", \n\t\t\t\t\"left\", \"right\", \n\t\t\t\t\"top-left\", \"top-right\", \n\t\t\t\t\"bottom-left\", \"bottom-right\"] 0;\n\t\t_baryArg\n\t\t\t= concat [\"0,0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 0\n\t\t\t= concat [\"0,0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 1\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],0,\", colourB._flag], position.value == 2\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],0,\", colourA._flag], position.value == 3\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourB._flag], position.value == 4\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 5\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 6\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourA._flag], position.value == 7\n\t\t\t= \"dunno\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color barycentric \\\"\" ++ _baryArg ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradientCorn_item = class\n\tMenuaction \"_Gradient corners\" \n\t\t\"apply a bilinear gradient between the corners\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour_top_left = Magick.generalcol_widget;\n\t\tcolour_top_right = Magick.generalcol_widget;\n\t\tcolour_bottom_left = Magick.generalcol_widget;\n\t\tcolour_bottom_right = Magick.generalcol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color bilinear \\\"\" ++\n\t\t\t\t\"0,0,\" ++ colour_top_left._flag ++\n\t\t\t\t\",%%[fx:w-1],0\" ++ colour_top_right._flag ++\n\t\t\t\t\",0,%%[fx:h-1]\" ++ colour_bottom_left._flag ++\n\t\t\t\t\",%%[fx:w-1],%%[fx:h-1]\" ++ colour_bottom_right._flag ++ \"\\\"\",\n\t\t\t\"+depth\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_histogram_item = class\n\tMenuaction \"_Histogram\" \"make a histogram image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-define histogram:unique-colors=false histogram:\" ++\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_implode_item = class\n\tMenuaction \"_Implode\" \"implode pixels about the center\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfactor = Scale \"factor\" 0 20 1;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\t// FIXME: virtual-pixel?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tinterpolate._flag,\n\t\t\t\"-implode\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_level_item = class\n\tMenuaction \"_Level\" \"adjust the level of channels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"black point\" (-100) 200 0;\n\t\twht = Scale \"white point\" (-100) 200 100;\n\t\tgam = Scale \"gamma\" 0 30 1;\n\t\tisPc = Toggle \"Levels are percent\" true;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \",\" ++ \n\t\t\t\tprint wht.value ++ (if isPc then \"%%\" else \"\") ++ \",\" ++ \n\t\t\t\tprint gam.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_levelCols_item = class\n\tMenuaction \"_Level colors\" \"adjust levels to given colours\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcolour_black = Magick.generalcol_widget;\n\t\tcolour_white = Magick.generalcol_widget;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level-colors\",\n\t\t\t\"\\\"\" ++ colour_black._flag ++ \",\" ++ colour_white._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_linearStretch_item = class\n\tMenuaction \"_Linear stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-linear-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_magnify_item = class\n\tMenuaction \"_Magnify\" \"double the size of the image with pixel art scaling\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-magnify\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_modulate_item = class\n\tMenuaction \"_Modulate\" \"modulate brightness, saturation and hue\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmodcolsp = Magick.ModColSp_widget;\n\t\tbright = Scale \"brightness\" 0 200 100;\n\t\tsat = Scale \"saturation\" 0 200 100;\n\t\thue = Scale \"hue\" 0 200 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tmodcolsp._flag,\n\t\t\t\"-modulate\",\n\t\t\tprint bright.value ++ \",\" ++ print sat.value ++ \",\" ++ \n\t\t\t\tprint hue.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_monochrome_item = class\n\tMenuaction \"_Monochrome\" \"transform to black and white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// FIXME: also intensity?\n\n\t\tintensity = Magick.intensity_widget;\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tdither._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\t\"-monochrome\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_morphology_item = class\n\t// See http://www.imagemagick.org/Usage/morphology/\n\tMenuaction \"_Morphology\" \"apply a morphological method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmethod = Magick.morphmeth_widget;\n\t\titer = Expression \"Iterations (-1=repeat until done)\" 1;\n\n\t\tkernel = Magick.kernel_widget;\n\t\t// FIXME: custom kernel eg \"3x1+2+0:1,0,0\"\n\t\t//   width x height + offsx + offsy : {w*h values}\n\t\t//   each value is 0.0 to 1.0 or \"NaN\" or \"-\"\n\n\t\t// kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0\n\t\t// but\n\t\t//   ring takes: radius1, radius2, scale\n\t\t//   rectangle and comet take: width x height + offsx + offsy\n\t\t//   blur takes: radius x sigma\n\t\t// FIXME: for now, simply allow any string input.\n\t\tkernel_arg = String \"Kernel arguments\" \"\";\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-morphology\",\n\t\t\tmethod._flag ++ \":\" ++ print iter.expr, \n\t\t\tkernel._flag ++\n\t\t\t(if kernel_arg.value == \"\" then \"\" else \":\") ++ kernel_arg.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_negate_item = class\n\tMenuaction \"_Negate\" \"negate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-negate\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_addNoise_item = class\n\tMenuaction \"_add Noise\" \"add noise\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tattenuate = Scale \"attenuate\" 0 1.0 1.0;\n\t\tnoise = Magick.noise_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-attenuate\", \n\t\t\tprint attenuate.value,\n\t\t\tnoise._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_normalize_item = class\n\tMenuaction \"_Normalize\" \"normalize\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-normalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_opaque_item = class\n\tMenuaction \"_Opaque\" \"change this colour to the fill colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfill = Magick.foreground_widget;\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfill._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"opaque\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_paint_item = class\n\tMenuaction \"_Paint\" \"simulate an oil painting\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"radius\" 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-paint\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/*=== FIXME Bug; remove for now.\nPolaroid_item = class\n\tMenuaction \"_Polaroid\" \"simulate a polaroid picture\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle\" (-90) 90 20;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-polaroid\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_posterize_item = class\n\tMenuaction \"_Posterize\" \"reduce to (n) levels per channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tlevels = Expression \"levels\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-posterize\",\n\t\t\tprint levels.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_raise_item = class\n\tMenuaction \"_Raise\" \"lighten or darken image edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthk = Expression \"Thickness\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-raise\",\n\t\t\tprint thk.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_resize_item = class\n\tMenuaction \"_Resize\" \"resize to given width and height\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfilter = Magick.filter_widget;\n\t\ttype = Magick.ResizeType_widget;\n\t\twidth = Scale \"Width\" 1 100 10;\n\t\theight = Scale \"Height\" 1 100 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfilter._flag,\n\t\t\t\"-\" ++ type._flag,\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"!\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_roll_item = class\n\tMenuaction \"_Roll\" \"roll an image horizontally or vertically\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trollx = Expression \"X\" 3;\n\t\trolly = Expression \"Y\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-roll\",\n\t\t\t(if rollx.expr >= 0 then \"+\" else \"\") ++ print rollx.expr ++\n\t\t\t(if rolly.expr >= 0 then \"+\" else \"\") ++ print rolly.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_rotate_item = class\n\tMenuaction \"_Rotate\" \"rotate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"+distort\",\n\t\t\t\"SRT\",\n\t\t\tprint angle.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -segment, but cluster-threshold should be percentage of image area.\n\nMagick_sepia_item = class\n\tMenuaction \"_Sepia tone\" \"simulate a sepia-toned photo\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sepia-tone\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shade_item = class\n\tMenuaction \"_Shade\" \"shade with a distant light source\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tazimuth = Scale \"Azimuth (degrees)\" (-360) 360 0;\n\t\televation = Scale \"Elevation (degrees)\" 0 90 45;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shade\",\n\t\t\tprint azimuth.value ++ \"x\" ++ print elevation.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shadow_item = class\n\tMenuaction \"_Shadow\" \"simulate a shadow\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshadowCol = Magick.generalcol_widget;\n\t\topacity = Scale \"Opacity (percent)\" 0 100 75;\n\t\tsigma = Scale \"Sigma\" 0 30 2;\n\t\t// FIXME: make offsets a single widget?\n\t\toffsx = Scale \"X-offset\" (-20) 20 4;\n\t\toffsy = Scale \"Y-offset\" (-20) 20 4;\n\t\tarePc = Toggle \"offsets are percentages\" false;\n\n\t\t// FIXME: raw operation creates page offset, which vips dislikes.\n\t\t// So we take this futher, compositing with source.\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"(\\\" +clone\",\n\t\t\t\"-background\", \"\\\"\" ++ shadowCol._flag ++ \"\\\"\",\n\t\t\t\"-shadow\",\n\t\t\tconcat [\n\t\t\t\t\"\\\"\",\n\t\t\t\tprint opacity.value, \"x\", print sigma.value,\n\t\t\t\t(if offsx.value >= 0 then \"+\" else \"\"), print offsx.value,\n\t\t\t\t(if offsy.value >= 0 then \"+\" else \"\"), print offsy.value,\n\t\t\t\t(if arePc then \"%%\" else \"\"),\n\t\t\t\t\"\\\"\"\n\t\t\t],\n\t\t\t\"\\\")\\\" +swap -background None -layers merge\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shave_item = class\n\tMenuaction \"_Shave\" \"shave pixels from the edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 0 50 10;\n\t\theight = Scale \"Height\" 0 50 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shave\",\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shear_item = class\n\tMenuaction \"_Shear\" \"shear along the x-axis and/or y-axis\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-shear\",\n\t\t\tprint shearX.expr ++ \"x\" ++ print shearY.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sigmoid_item = class\n\tMenuaction \"_Sigmoid\" \"increase or decrease mid-tone contrast sigmoidally\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcontrast = Scale \"contrast\" 0 30 3;\n\t\tmidpoint = Scale \"mid-point (percent)\" 0 100 50;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"sigmoidal-contrast\",\n\t\t\t\"\\\"\" ++ print contrast.value ++ \"x\" ++ \n\t\t\t\tprint midpoint.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sketch_item = class\n\tMenuaction \"_Sketch\" \"simulate a pencil sketch\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tangle = Scale \"angle\" (-360) 360 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sketch\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if angle >= 0 then (\"+\" ++ print angle.value) else \"\"),\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_solarize_item = class\n\tMenuaction \"_Solarize\" \"negate all pixels above a threshold level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-solarize\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -sparse-color needs abitrary list of {x,y,colour}.\n\nMagick_splice_item = class\n\tMenuaction \"_Splice\" \"splice a colour into the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-splice\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_spread_item = class\n\tMenuaction \"_Spread\" \"displace pixels by random amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tamount = Expression \"Amount (pixels)\" 5;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"-spread\",\n\t\t\tprint amount.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_statistic_item = class\n\tMenuaction \"_Statistic\" \"replace each pixel with statistic from neighbourhood\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width\" 5;\n\t\theight = Expression \"Height\" 5;\n\t\tstatisticType = Magick.StatType_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-statistic\", \n\t\t\tstatisticType._flag, \n\t\t\tprint width.expr ++ \"x\" ++ print height.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_swirl_item = class\n\tMenuaction \"_Swirl\" \"swirl around the centre\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Magick.angle_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-swirl\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_thresholdMenu_item = class\n\tMenupullright \"_Threshold\" \"make black or white\" {\n\n\tMagick_threshold_item = class\n\t\tMenuaction \"_Threshold\" \"apply black/white threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-threshold\", \n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blackThreshold_item = class\n\t\tMenuaction \"_Black threshold\" \"where below threshold set to black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-black-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_whiteThreshold_item = class\n\t\tMenuaction \"_White threshold\" \"where above threshold set to white\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-white-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_latThreshold_item = class\n\t\tMenuaction \"_Local Adaptive Threshold\" \"where above average plus offset set to white, otherwise black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twidth = Expression \"Width\" 10;\n\t\t\theight = Expression \"Height\" 10;\n\t\t\toffset = Scale \"Offset (percent)\" (-100) 100 0;\n\t\t\t// note: \"-lat\" doesn't respond to channels\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-lat\",\n\t\t\t\tconcat [\"\\\"\", print width.expr, \"x\", print height.expr, \n\t\t\t\t\t(if offset.value >= 0 then \"+\" else \"\"), print offset.value,\n\t\t\t\t\t\"%%\\\"\"\n\t\t\t\t],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_randThreshold_item = class\n\t\tMenuaction \"_Random Threshold\" \"between specified limits, apply random threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tlow = Scale \"Low threshold\" 0 100 10;\n\t\t\thigh = Scale \"High threshold\" 0 100 90;\n\t\t\tisPc = Toggle \"Thresholds are percent\" true;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-random-threshold\", \n\t\t\t\t\"\\\"\" ++ print low.value ++ \"x\" ++ print high.value ++\n\t\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end ThresholdMenu_item\n\n\n// Note: alternatives include:\n// convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif\n\nMagick_tile_item = class\n\tMenuaction \"_Tile\" \"fill given size with tiled image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tsize = Magick.Size_widget;\n\n\t\tcommand = Magick.command [\n\t\t\tsize._flag,\n\t\t\t\"tile:\" ++ \"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_tint_item = class\n\tMenuaction \"_Tint\" \"apply a tint\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tamount = Scale \"amount (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-tint\",\n\t\t\t// snibgo note: although the amount is a percentage, it doesn't need \"%\" character.\n\t\t\tprint amount.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_transparent_item = class\n\tMenuaction \"_Transparent\" \"make this colour transparent\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"transparent\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_trim_item = class\n\tMenuaction \"_Trim\" \"trims away border\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfuzz = Magick.fuzz_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-trim +repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_uniqueCols_item = class\n\tMenuaction \"_Unique colours\" \"discard all but one of any pixel color\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-unique-colors\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_vignette_item = class\n\tMenuaction \"_Vignette\" \"soften the edges in vignette style\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\trx = Scale \"Rolloff x (percent)\" 0 100 10;\n\t\try = Scale \"Rolloff y (percent)\" 0 100 10;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-vignette\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if rx.value >= 0 then \"+\" else \"\") ++ print rx.value ++\n\t\t\t\t(if ry.value >= 0 then \"+\" else \"\") ++ print ry.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_wave_item = class\n\tMenuaction \"_Wave\" \"shear the columns into a sine wave\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tamplitude = Scale \"Amplitude (pixels)\" 0 100 10;\n\t\twavelength = Scale \"Wavelength (pixels)\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-wave\",\n\t\t\tprint amplitude.value ++ \"x\" ++ print wavelength.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\n"
  },
  {
    "path": "share/nip2/compat/8.6/Makefile.am",
    "content": "startdir = $(pkgdatadir)/compat/8.6\n\nstart_DATA = \\\n\tColour.def \\\n\t_convert.def \\\n\tFilter.def \\\n\t_generate.def \\\n\tHistogram.def \\\n\tImage.def \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_list.def \\\n\t_magick.def \\\n\tMagick.def \\\n\tMath.def \\\n\tMatrix.def \\\n\t_Object.def \\\n\tObject.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\tTasks.def \\\n\t_types.def \\\n\tWidgets.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/compat/8.6/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_AND\" \"bitwise AND of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_OR\" \"bitwise OR of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"_XOR\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_NOT\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBandand_item = Image_band_item.Bandand_item; \n\n\tBandor_item = Image_band_item.Bandor_item; \n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tDifference_item = class \n\t\tMenuaction \"_Difference\" \"difference of two lists\" {\n\t\taction a b = map_binary difference a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tValue_item = class \n\t\tMenuaction \"_Value\" \"value of point in object\" {\n\t\taction a = class _result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tposition = Expression \"Coordinate\" (0, 0);\n\t\n\t\t\t_result = map_binary point position.expr a;\n\t\t}\n\t}\n\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tSkew_item = class \n\t\tMenuaction \"S_kew\" \"skew of image or list or vector\" {\n\t\taction a = map_unary skew a;\n\t}\n\n\tKurtosis_item = class \n\t\tMenuaction \"Kurtosis\" \"kurtosis of image or list or vector\" {\n\t\taction a = map_unary kurtosis a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \n\t\t\t\"position of centre of gravity of histogram\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = linreg xes yes;\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = linregw xes yes devs;\n\t}\n\n\tCluster_item = class \n\t\tMenuaction \"_Cluster\" \"cluster a list of numbers\" {\n\t\taction l = class {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tthresh = Expression \"Threshold\" 10;\n\t\n\t\t\t[_r, _w] = cluster thresh.expr l;\n\t\n\t\t\tresult = _r;\n\t\t\tweights = _w;\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.6/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_identity_item = class \n\t\tMenuaction \"_Identity\" \"make an identity matrix\" {\n\t\taction = identity (identity_matrix 5);\n\t\t\n\t\tidentity v = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix (identity_matrix (to_real s)), to_real s != len v;\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = identity value;\n\t\t}\n\t}\n\n\tMatrix_series_item = class \n\t\tMenuaction \"_Series\" \"make a series\" {\n\t\taction = series (mkseries 0 1 5);\n\n\t\tmkseries s t e \n\t\t\t= transpose [[to_real s, to_real s + to_real t .. to_real e]];\n\n\t\tseries v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t_s = v?0?0;\n\t\t\t_t = v?1?0 - v?0?0;\n\t\t\t_e = (last v)?0;\n\n\t\t\ts = Expression \"Start value\" _s;\n\t\t\tt = Expression \"Step by\" _t;\n\t\t\te = Expression \"End value\" _e;\n\n\t\t\t_result \n\t\t\t\t= Matrix (mkseries s t e), \n\t\t\t\t\t\tto_real s != _s || to_real t != _t || to_real e != _e\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = series value;\n\t\t}\n\t}\n\n\tMatrix_square_item = class \n\t\tMenuaction \"_Square\" \"make a square matrix\" {\n\t\taction = square (mksquare 5);\n\n\t\tmksquare s = replicate s (take s [1, 1 ..]);\n\n\t\tsquare v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == to_real s\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mksquare (to_real s); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = square value;\n\t\t}\n\t}\n\n\tMatrix_circular_item = class \n\t\tMenuaction \"_Circular\" \"make a circular matrix\" {\n\t\taction = circle (mkcircle 3);\n\n\t\tmkcircle r\n\t\t\t\t= map2 (map2 pyth) xes yes\n\t\t{\n\t\t\tline = [-r .. r];\n\t\t\txes = replicate (2 * r + 1) line;\n\t\t\tyes = transpose xes;\n\t\t\tpyth a b \n\t\t\t\t\t= 1, (a**2 + b**2) ** 0.5 <= r\n\t\t\t\t\t= 0;\n\t\t}\n\n\t\tcircle v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tr = Expression \"Radius\" ((len v - 1) / 2);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mkcircle (to_real r); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = circle value;\n\t\t}\n\t}\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\nMatrix_sort_item = class \n\tMenuaction \"_Sort\" \"sort by column or row\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\to = Option (_ \"Orientation\") [\n\t\t\t_ \"Sort by column\",\n\t\t\t_ \"Sort by row\"\n\t\t] 0;\n\t\ti = Expression (_ \"Sort on index\") 0;\n\t\td = Option (_ \"Direction\") [\n\t\t\t_ \"Ascending\",\n\t\t\t_ \"Descending\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary sort x\n\t\t{\n\t\t\tidx = to_real i;\n\t\t\tpred a b \n\t\t\t\t= a?idx <= b?idx, d == 0\n\t\t\t\t= a?idx >= b?idx;\n\t\t\tsort x\n\t\t\t\t= (x.Matrix_base @ sortc pred) x.value,\n\t\t\t\t\to == 0\n\t\t\t\t= (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value;\n\t\t}\n\t}\n}\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ \n\t\t\t\t\trange;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.6/Object.def",
    "content": "Object_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nObject_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nObject_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nObject_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nObject_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.6/Preferences.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.6.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"680\" window_height=\"800\" filename=\"$VIPSHOME/share/$PACKAGE/start/Preferences.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"100\" lpane_open=\"false\" rpane_position=\"400\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"Preferences\">\n    <Column x=\"0\" y=\"3067\" open=\"false\" selected=\"false\" sform=\"false\" next=\"99\" name=\"B\" caption=\"Interface column -- don't touch this!\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"CSV_SEPARATOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"O1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PRINT_CARTIESIAN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F10.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"USE_GRAPHICSMAGICK\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D45.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_PANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"237\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"788\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"700\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"100\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RELOAD\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D42.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_STATUSBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR_STYLE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MATRIX_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_RECOMP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"N2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_MAX_UNDO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[-1,0,1,5,10]?N1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_FONT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"N4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_INTERLACE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_LINELENGTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D41.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A6.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE_FILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PPM_MODE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"G1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_LAYOUT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C16.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C18.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_MULTI_RES\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_FORMAT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_PREDICTOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_BIGTIFF\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_START\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D25.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_SEARCH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D2.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_TMP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_SLIDER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D28.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_REGION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D29.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_AUTO_WS_SAVE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D30.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_DISPLAY_LED\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLKITBROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_MAX_HEAP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D38.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PIN_FILESEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_STATUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CONVERSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_RULERS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CROSSHAIR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL_HQ\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E21.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_TRACE_FUNCTIONS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"H1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_DEVICE\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CHANNEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_BRIGHTNESS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_COLOUR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CONTRAST\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_HUE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_FRAMES\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J13.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_MONO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J14.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_LEFT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_TOP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_ASPECT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_MAX_BLEND_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_REFINE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_WINDOW_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_OBJECT_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_BALANCE_GAMMA\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"680\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER_REMOTE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"POPUP_NEW_ROWS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_HISTORY_MAX\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D43.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_CPUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D44.value\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2831\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"I\" caption=\"Mosaic defaults\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Maximum blend width&quot; 0 100 10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Refine tie-points&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search windows this size&quot; 30\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search for objects this size&quot; 10\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Image gamma for mosaic balance&quot; 1 3 1.6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2495\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"J\" caption=\"Video for linux\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"J2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;Device&quot; &quot;/dev/video&quot;\"/>\n            <Pathname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Channel&quot; [&quot;TV&quot;, &quot;Composite 1&quot;, &quot;Composite 2&quot;, &quot;Composite 3&quot;] 1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Brightness&quot; 0 32767 23000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Colour&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Contrast&quot; 0 32767 27000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Hue&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Number of frames to average&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Grab monochrome&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2208\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"K\" caption=\"General video capture\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"K1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Crop video: \" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Crop video&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop left&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop top&quot; 6\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number  &quot;Crop width&quot; 747\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop height&quot; 570\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Aspect ratio (stretch vertically\\nby this much)&quot; 1.202\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2072\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"M\" caption=\"PNG save options\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"M1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Compression&quot; (map print [0..9]) 6\"/>\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Interlace&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1970\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"G\" caption=\"PPM/PGM/PBM save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"PPM mode\" labelsn=\"2\" labels0=\"Binary\" labels1=\"ASCII\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Mode&quot; [&quot;Binary&quot;, &quot;ASCII&quot;] 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1620\" open=\"true\" selected=\"true\" sform=\"false\" next=\"27\" name=\"C\" caption=\"TIFF save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Compression&quot; [&quot;None&quot;, &quot;LZW&quot;, &quot;Zip (deflate)&quot;, &quot;PACKBITS&quot;, &quot;JPEG&quot;, &quot;CCITTFAX4&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;JPEG quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Deflate/LZW predictor&quot; [&quot;None&quot;,&quot;Horizontal difference&quot;,&quot;Floating-point&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Layout\" labelsn=\"2\" labels0=\"Strip\" labels1=\"Tile\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Layout&quot; [&quot;Strip&quot;, &quot;Tile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile width&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile height&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Multi-res&quot; [&quot;Single image&quot;, &quot;Image pyramid&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Format&quot; [&quot;No truncation&quot;,&quot;Save 1 band 8 bit images as 1 bit&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Save as BigTIFF&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1518\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"O\" caption=\"CSV save\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"String &quot;Separator character&quot; &quot;\\t&quot;\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1348\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"A\" caption=\"JPEG save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;ICC profile&quot; [&quot;Use image profile, if any&quot;, &quot;Embed profile from file&quot;, &quot;Don't attach a profile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Pathname/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;ICC profile file&quot; &quot;$VIPSHOME/share/nip2/data/sRGB.icm&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1144\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"F\" caption=\"Widgets\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Pin up file requestors&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Main window toolbar&quot; [&quot;Default style&quot;, &quot;Icon only&quot;, &quot;Text only&quot;, &quot;Icon and text&quot;, &quot;Icon and text to right&quot;] 0\"/>\n            <Option caption=\"Main window toolbar\" labelsn=\"5\" labels0=\"Default style\" labels1=\"Icon only\" labels2=\"Text only\" labels3=\"Icon and text\" labels4=\"Icon and text to right\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display LEDs in workspace&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display complex numbers as coordinates&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1044\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"H\" caption=\"Debug options\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Disassemble functions\" value=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;untitled&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"906\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"L\" caption=\"Help browser\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"L2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Command to start browser&quot; &quot;firefox&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Go-to-page argument&quot; &quot;-remote 'openURL(%s)'&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"734\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"N\" caption=\"Paintbox \">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Max undo steps\" labelsn=\"5\" labels0=\"Unlimited\" labels1=\"None\" labels2=\"1\" labels3=\"5\" labels4=\"10\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Max undo steps&quot; [&quot;Unlimited&quot;, &quot;None&quot;, &quot;1&quot;, &quot;5&quot;, &quot;10&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Fontname &quot;Default paintbox font&quot; &quot;Sans 12&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Fontname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update during paint&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"458\" open=\"true\" selected=\"false\" sform=\"false\" next=\"27\" name=\"E\" caption=\"Image display\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"E20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use crosshair cursor in image windows&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Thumbnail size&quot; 64\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;High-quality thumbnails&quot; false\"/>\n            <Toggle/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window width&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window height&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto image window pop up&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"46\" name=\"D\" caption=\"Calculation\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Data path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;data&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;data&quot;], &quot;.&quot;]\"/>\n            <Expression caption=\"Data path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Temporary files&quot; (path_relative [&quot;$SAVEDIR&quot;, &quot;tmp&quot;])\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Start path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;start&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;start&quot;]]\"/>\n            <Expression caption=\"Start path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D28\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update sliders during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update sliders during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D29\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update regions during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update regions during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D30\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto workspace save&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D42\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto-reload on file change&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D41\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Text display length (characters)&quot; 80\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D38\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Heap size (per workspace)&quot; 600000\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D43\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of VIPS functions to memoise&quot; 20000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D44\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of CPUs to use (0 for autodetect)&quot; 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D45\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use GraphicsMagick for Magick menu&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/compat/8.6/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\n\tCsv_import_item = class\n\t\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tstart_line = Expression \"Start at line\" 1;\n\t\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_csv2vips filename)\n\t\t\t{\n\t\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\t\tescape x \n\t\t\t\t\t= foldr prefix [] x\n\t\t\t\t{\n\t\t\t\t\tprefix x l\n\t\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t\t= x : l;\n\t\t\t\t}\n\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tRaw_import_item = class\n\t\tMenuaction \"_Raw Import\" \"read a file of binary values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tacross = Expression \"Pixels across\" 100;\n\t\t\tdown = Expression \"Pixels down\" 100;\n\t\t\tbytes = Expression \"Bytes per pixel\" 3;\n\t\t\tskip = Expression \"Skip over initial bytes\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_binfile path.value \n\t\t\t\t\tacross.expr down.expr bytes.expr skip.expr)\n\t\t\t{\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// interpret Analyze header for layout and calibration\n\tAnalyze7_header_item = class\n\t\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\t\"examine the Analyze header and set layout and value\" {\n\t\taction x \n\t\t\t= x'''\n\t\t{\n\t\t\t// read bits of header\n\t\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\t\tdim0 = dim 0 x;\n\t\t\tdim1 = dim 1 x;\n\t\t\tdim2 = dim 2 x;\n\t\t\tdim3 = dim 3 x;\n\t\t\tdim4 = dim 4 x;\n\t\t\tdim5 = dim 5 x;\n\t\t\tdim6 = dim 6 x;\n\t\t\tdim7 = dim 7 x;\n\t\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\t\n\t\t\t// oops, now a nop\n\t\t\tx' = x;\n\t\n\t\t\t// lay out higher dimensions width-ways\n\t\t\tx'' \n\t\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\t\tdim0 == 7\n\t\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\t\n\t\t\t// multiply by scale factor to get kBeq\n\t\t\tx''' = x'' * (cal_max / glmax);\n\t\t}\n\t}\n\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\t[image, patch] = sortc larger [a, b];\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n\t\t\tsample = measure_draw 6 4 (to_real measure) image;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\tmode = Option \"Input LUT\" [\n\t\t\t\t\"Linearize from chart greyscale\",\n\t\t\t\t\"Fit intercept from chart greyscale\",\n\t\t\t\t\"Linear input, set brightness from chart\",\n\t\t\t\t\"Linear input\"\n\t\t\t] 0;\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = measure_sample 6 4 (to_real measure) image;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb \n\t\t\t\t= Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0\n\t\t\t\t= Matrix [0: intercepts, replicate (_camera.width + 1) 1], \n\t\t\t\t\tmode == 1\n\t\t\t\t= Matrix [[0, 0], [1, 1]]\n\t\t\t{\n\t\t\t\tintercepts = [(linreg _true_grey_Y' cam).intercept :: \n\t\t\t\t\tcam <- transpose _camera_grey'];\n\t\t\t}\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\t// plot from 0 explicitly so we see the effect of mode1 (intercept\n\t\t\t// from greyscale)\n\t\t\tlinearising_lut = Plot [$ymin => 0] _linear_lut;\n\n\t\t\t// map an image though the lineariser\n\t\t\tlinear x\n\t\t\t\t= hist_map linearising_lut.value x, mode == 0 || mode == 1\n\t\t\t\t= x;\n\n\t\t\t// map the chart measurements though the lineariser\n\t\t\t_camera' = (to_matrix @ linear @ to_image) _camera;\n\n\t\t\t// solve for RGB -> XYZ\n\t\t\t// normalise: the 2nd row is what makes Y, so divide by that to\n\t\t\t// get Y in 0-1.\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\t_full_M = transpose (_pinv * (transpose _camera' * _true_XYZ));\n\t\t\tM = _full_M / scale;\n\t\t\tscale = sum _full_M.value?1;\n\n\t\t\t// now turn the camera to LAB and calculate dE76\n\t\t\t_camera'' = (to_matrix @ \n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @ \n\t\t\t\trecomb M @ \n\t\t\t\tmultiply scale @\n\t\t\t\tto_image) _camera';\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tavg_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0 && i < len macbeth_names\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\n\t\t\t// normalise brightness ... in linear mode, we optionally don't\n\t\t\t// set the brightness from the Macbeth chart\n\t\t\tnorm x \n\t\t\t\t= x * scale, mode != 3\n\t\t\t\t= x;\n\n\t\t\t// convert RGB camera to Lab\n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tnorm @\n\t\t\t\trecomb M @\n\t\t\t\tcast_float @\n\t\t\t\tlinear) image.value;\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b = class\n\t\t\t(map_binary process a b) {\n\t\t\tprocess a b\n\t\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t\t{\n\t\t\t\t// the name of the calib object we need\n\t\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t\t// get the Calibrate_chart arg first\n\t\t\t\t[image, calib] = sortc (const (is_instanceof calib_name)) \n\t\t\t\t\t[a, b];\n\n\t\t\t\tresult = (Image @\n\t\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\t\tcalib.norm @\n\t\t\t\t\trecomb calib.M @\n\t\t\t\t\tcast_float @\n\t\t\t\t\tcalib.linear) image.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [$style => style.value] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\t!is_list_len 2 images\n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = all (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize Kernel_linear xfactor yfactor scale_im;\n\t\t\t_offset_im = resize Kernel_linear xfactor yfactor offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.6/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.6/_Object.def",
    "content": "/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0|1|2|3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \n\tjoin_sep \"|\" Image_type.colour_spaces.names];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide|VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad properties for \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"where\" ++ \"\\n\" ++ arg_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make arg type notes\n\targ_types = join_sep \"\\n\" (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"\\n\" ++ _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = join_sep \"\\n\" all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if those fail as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if that fails as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary'_function op a b\n\t= matches1?0, matches1 != []\n\t= matches2?0, op.symmetric && matches2 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0, matches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t// these should always be defined\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x = oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x = oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op = oo_unary_function (oo_unary_lookup op) this;\n\n\too_binary_table op x = [];\n\too_unary_table op = [];\n}\n"
  },
  {
    "path": "share/nip2/compat/8.6/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make a Vector ... works for Vector/Image/Real, plus image/real\n */\nto_vector x\n\t= to_vector x.expr, is_Expression x\n\t= x, is_Vector x\n\t= oo_unary_function to_vector_op x, is_class x\n\t= tov x\n{\n\tto_vector_op = Operator \"to_vector\" tov Operator_type.COMPOUND false;\n\n\ttov x\n\t\t= Vector (itov x), is_image x\n\t\t= Vector [x], is_real x\n\t\t= Vector x, is_real_list x\n\t\t= Vector x?0, is_matrix x && len x == 1\n\t\t= Vector (transpose x)?0, is_matrix x && len x?0 == 1\n\t\t= error (_ \"bad arguments to \" ++ \"to_vector\");\n\n\titov i\n\t\t= v, is_image i \n\t\t= error (_ \"not image\")\n\t{\n\t\tm = im_vips2mask ((double) i);\n\t\tv \n\t\t\t= m.value?0, m.height == 1\n\t\t\t= (transpose m.value)?0, m.width == 1\n\t\t\t= error (_ \"image is not 1xN or Nx1\");\n\t}\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= Image x.value, is_Plot x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n// like to_image, but we do 1x1 pixel + x, then embed it up\n// always make an unwrapped image for speed ... this gets used by ifthenelse\n// and stuff like that\n// format can be NULL, meaning set format from x\nto_image_size width height bands format x\n\t= x, is_image x\n\t= x.value, is_Image x\n\t= im''\n{\n\t// we want x to set the target format if we don't have one, so we\n\t// can't use image_new\n\tim = im_black 1 1 bands + x;\n\tim'\n\t\t= clip2fmt format im, format != NULL\n\t\t= im;\n\tim'' = embed 1 0 0 width height im';\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && is_list_len 3 x\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\nto_int x = (int) (to_real x);\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The outermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x \n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), !is_list_len 2 parts \n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, !is_list_len 4 parts \n\t= sign * (abs ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", \n\t\tmember \".0123456789\",\n\t\tmember \"eE\", \n\t\tmember \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tsign \n\t\t= 1, ipart >= 0\n\t\t= -1;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), !is_list_len 5 parts \n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t$D93 => D93_whitepoint,\n\t$D75 => D75_whitepoint,\n\t$D65 => D65_whitepoint,\n\t$D55 => D55_whitepoint,\n\t$D50 => D50_whitepoint,\n\t$A => A_whitepoint,\n\t$B => B_whitepoint,\n\t$C => C_whitepoint,\n\t$E => E_whitepoint,\n\t$D3250 => D3250_whitepoint\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* The vips8 scRGB functions.\n */\n\nim_sRGB2scRGB in\n\t= out\n{\n\t[out] = vips_call \"sRGB2scRGB\" [in] [];\n}\n\nim_scRGB2sRGB in\n\t= out\n{\n\t[out] = vips_call \"scRGB2sRGB\" [in] [];\n}\n\nim_scRGB2XYZ in\n\t= out\n{\n\t[out] = vips_call \"scRGB2XYZ\" [in] [];\n}\n\nim_XYZ2scRGB in\n\t= out\n{\n\t[out] = vips_call \"XYZ2scRGB\" [in] [];\n}\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, scRGB, im_sRGB2scRGB @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, image_set_type GREY16 @ im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, scRGB, im_XYZ2scRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, scRGB, im_XYZ2scRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, scRGB, im_XYZ2scRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, scRGB, im_sRGB2scRGB @ im_clip],\n\t[sRGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_Lab2LabS @ im_sRGB2Lab @ im_clip],\n\n\t[scRGB, B_W, im_sRGB2mono @ im_scRGB2sRGB],\n\t[scRGB, XYZ, im_scRGB2XYZ],\n\t[scRGB, YXY, im_XYZ2Yxy @ im_scRGB2XYZ],\n\t[scRGB, LAB, im_XYZ2Lab @ im_scRGB2XYZ],\n\t[scRGB, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_scRGB2XYZ],\n\t[scRGB, UCS, im_XYZ2UCS @ im_scRGB2XYZ],\n\t[scRGB, RGB, im_XYZ2disp @ im_scRGB2XYZ],\n\t[scRGB, sRGB, im_scRGB2sRGB],\n\t[scRGB, scRGB, image_set_type scRGB],\n\t[scRGB, RGB16, image_set_type RGB16 @ im_8216 @ im_scRGB2sRGB],\n\t[scRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono @ \n\t\tim_scRGB2sRGB],\n\t[scRGB, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_scRGB2XYZ],\n\t[scRGB, LABS, im_Lab2LabS @ im_XYZ2Lab @ im_scRGB2XYZ],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, scRGB, im_sRGB2scRGB],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\t[RGB16, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, scRGB, im_sRGB2scRGB @ im_mono2sRGB],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabS2Lab @ im_clip2s],\n\t[LABS, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_LabS2Lab @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tscRGB = 28;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l = join_sep path_separator l;\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 > 1 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n/* Return $PATH, reformatted as [[\"comp1\", \"comp2\"], [\"comp1\", \"comp2\"] ..]\n */\nsystem_search_path\n\t= [vipsbin] ++\n\t\tmap path_parse (split (equal path_sep) (expand \"$PATH\"))\n{\n\t/* On some platforms we ship vips with a few extra progs. Search\n \t * $VIPSHOME/bin first.\n\t */\n\tvipsbin = path_parse (expand \"$VIPSHOME\") ++ [\"bin\"];\n\n\tpath_sep\n\t\t= ':', expand \"$SEP\" == \"/\"\n\t\t= ';';\n}\n\n/* Search $PATH for the first occurence of name, or \"\". \n */\nsearch_for name\n\t= hits?0, hits != []\n\t= \"\"\n{\n\texe_name = name ++ expand \"$EXEEXT\";\n\tform_path p = path_absolute (p ++ [exe_name]);\n\tpaths = map form_path system_search_path;\n\thits = dropwhile (equal []) (map search paths);\n}\n\n/* Search $PATH for the first occurence of name, error on failure. \n */\nsearch_for_error name\n\t= path, path != \"\"\n\t= error (exe_name ++ \" not found on your search path. \" ++\n\t\t\"Check you have installed the program and it is on your PATH.\")\n{\n\texe_name = name ++ expand \"$EXEEXT\";\n\tpath = search_for name;\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.6/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= embed 1 0 0 w h im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black 1 1 (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\nmkim options x y b\n    = Image (image_new x y b\n        (opt $format) (opt $coding) (opt $type)\n        (opt $pixel)\n        (opt $xoffset) (opt $yoffset))\n{\n    opt = get_option options [\n        $format => Image_format.UCHAR,\n        $coding => Image_coding.NOCODING,\n        $type => Image_type.sRGB,\n        $pixel => 0,\n        $xoffset => 0,\n        $yoffset => 0\n    ];\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = im_gauss_imask_sep (radius / 3) 0.2;\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n/* Make a colour from a temperature.\n */\ncolour_from_temp T\n\t= error (_ \"T out of range\"), T < 1667 || T > 25000\n\t= Colour \"Yxy\" [50, x, y]\n{\n\t// Kim et all approximation\n\t// see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation\n\tx\n\t\t= -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 +\n\t\t\t0.8776956 * 10 ** 3 / T + 0.179910, T < 4000\n\t\t= -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 +\n\t\t\t0.2226347 * 10 ** 3 / T + 0.240390;\n\n\ty \n\t\t= -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + \n\t\t\t2.18555832 * x - 0.20219638, T < 2222\n\t\t= -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + \n\t\t\t2.09137015 * x - 0.16748867, T < 4000\n\t\t=  3.0817580 * x ** 3 - 5.87338670 * x ** 2 +\n\t\t\t3.75112997 * x - 0.37001483;\n}\n\ntemp_from_colour z\n\t= T\n{\n\tc = colour_transform_to Image_type.YXY (to_colour z);\n\tx = c.value?1;\n\ty = c.value?2;\n\n\t// McCamy's approximation, see eg. \n\t// http://en.wikipedia.org/wiki/Color_temperature#Approximation\n\n\txe = 0.332;\n\tye = 0.1858;\n\tn = (x - xe) / (y - ye);\n\tT = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33;\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.6/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 1;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" \n\t] 4;\n\n\tcontrol_selection mask im no\n\t\t= [\n\t\t\tif mask then im * 1.2 else im * 1,\n\t\t\tif mask then im * 0.8 else im * 1,\n\t\t\tif mask then 0 else im,\n\t\t\tif mask then 255 else im,\n\t\t\tif mask then im else 0,\n\t\t\tif mask then im else 255,\n\t\t\tmask\n\t\t]?no;\n\n\tRectangle = class\n        Menuaction \"_Rectangle\"\n            \"use an Arrow or Region x to define a rectangle\"\n        {\n        action x = class\n            _result {\n            _vislevel = 3;\n\n            control = _control;   \n\n            _result = control_selection mask im control\n                  {\n                \tim = x.image;\n                \tmask = Image m\n                    {\n\t\t\t\t\t\trx     \n\t\t\t\t\t\t\t= x.region_rect, is_Region x\n\t\t\t\t\t\t\t= x;\n\t\t\t\t\t\tb     = image_new im.width im.height 1 0 0 1 0 0 0;\n\t\t\t\t\t\tw     = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0;\n\t\t\t\t\t\tm     = insert_noexpand rx.nleft rx.ntop w b; \n                     }\n                   }\n            }\n        }\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = get_image a;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = get_image ((pt_list.value)?0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tSegment_item = class\n\t\tMenuaction \"_Segment\" \"break image into disjoint regions\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsegments\n\t\t\t\t= Expression \"Number of disjoint regions\" \n\t\t\t\t\t(map_unary (get_header \"n-segments\") _result);\n\n\t\t\t_result = map_unary segment x;\n\t\t}\n\t}\n\n\tFill_item = class\n\t\tMenuaction \"_Fill\" \"fill zero pixels with the nearest non-zero\" {\n\t\taction x = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdistance = Image _distance;\n\n\t\t\t[_result, _distance] = vips_call \"fill_nearest\" [x.value] [\n\t\t\t\t\"distance\" => true\n\t\t\t];\n\t\t}\n\t}\n\nfill_nearest x \n\t= oo_unary_function nearest_op x, is_class x\n\t= near x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fill_nearest\")\n{\n\tnearest_op = Operator \"fill_nearest\" \n\t\tfill_nearest Operator_type.COMPOUND_REWRAP false;\n\n\tnear x\n\t\t= [out, distance]\n\t{\n\t\t[out, distance] = vips_call \"fill_nearest\" [x] [\n\t\t\t\"distance\" => true\n\t\t];\n\t}\n}\n\n\n\n\n\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize Kernel_linear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize Kernel_linear f1 1 b1\n\t\t\t\t\t{b1 = resize Kernel_linear 1 f2 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/compat/8.6/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = Image (get_image line);\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = Image (get_image (pt_l?0));\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t};\n\nMount_options _ctype _ppcm = class \n  {\n  _vislevel = 3;\n  apply = Toggle \"Apply mount options\" false;\n  ls = Expression \"Lower mount section bigger by (cm)\" 0;\n  mount_colour = Colour _ctype [0, 0, 0];\n  _los = ls.expr * _ppcm;\n  };\n\nFrame_variables comp = class\n  {\n  _vislevel = 3;\n\n  scale_factor = Expression \"scale the size of the frame by\" 1;\n\n  /* These sliders define the fraction of the frames width or height is extracted\n   * to produce each of the particular regions.\n   */\n  corner_section = Scale \"Corner section\" 0.1 1 0.5;\n  edge_section = Scale \"Edge section\" 0.1 1 0.2, comp > 0\n\t\t\t\t  = \"Only required for complex frames\";\n  middle_section = Scale \"Middle section\" 0.1 1 0.2;\n  blend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n  option = Toggle \"Use mirror of left-side to make right\" true;\n  };\n\n"
  },
  {
    "path": "share/nip2/compat/8.6/_list.def",
    "content": "/* any l: or all the elements of list l together\n *\n * any (map (equal 0) list) == true, if any element of list is zero.\n * any :: [bool] -> bool\n */\nany = foldr logical_or false;\n\n/* all l: and all the elements of list l together\n *\n * all (map (==0) list) == true, if every element of list is zero.\n * all :: [bool] -> bool\n */\nall = foldr logical_and true;\n\n/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* delete eq x l: delete the first x from l\n *\n * delete equal 'b' \"abcdb\" == \"acdb\"\n * delete :: (* -> bool) -> * -> [*] -> [*]\n */\ndelete eq a l\n\t= [], l == []\n\t= y, eq a b\n\t= b : delete eq a y\n{\n\tb:y = l;\n}\n\n/* difference eq a b: delete b from a\n *\n * difference equal \"asdf\" \"ad\" == \"sf\"\n * difference :: (* -> bool) -> [*] -> [*] -> [*]\n */\ndifference = foldl @ converse @ delete;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn x, fn a\n\t= l\n{\n\ta:x = l;\n}\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* flatten x: flatten a list of lists of things into a simple list\n *\n * flatten :: [[*]] -> [*]\n */\nflatten x\n\t= foldr flat [] x, is_list x\n\t= x\n{\n\tflat x sofar\n\t\t= foldr flat sofar x, is_list x\n\t\t= x : sofar;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st x) xs\n{\n\tx:xs = l;\n}\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn x xs\n{\n\tx:xs = l;\n}\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn x (foldr fn st xs)\n{\n\tx:xs = l;\n}\n\n/* foldr1 fn l: like foldr, but use the last element as the start value\n *\n * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= x, xs == []\n\t= fn x (foldr1 fn xs)\n{\n\tx:xs = l;\n}\n\n/* Search a list for an element, returning its index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn x\n\t\t= search xs (n + 1)\n\t\t{\n\t\t\tx:xs = l;\n\t\t}\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= x : init xs\n{\n\tx:xs = l;\n}\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* join_sep sep l: join a list with a separator\n *\n * join_sep \", \" (map print [1 .. 4]) == \"1, 2, 3, 4\"\n * join_sep :: [*] -> [[*]] -> [*]\n */\njoin_sep sep l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ sep ++ b;\n}\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= x, xs == []\n\t= last xs\n{\n\tx:xs = l;\n}\n\n/* len l: length of list l\n * (see also is_list_len and friends in predicate.def)\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta:b:x = l;\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = any (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge p l r\n\t= [], p == [] || l == [] || r == []\n\t= a : merge z x y, c\n\t= b : merge z x y\n{\n\ta:x = l;\n\tb:y = r;\n\tc:z = p;\n}\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta:x = l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scanl fn st l: apply (foldl fn r) to every initial segment of a list\n *\n * scanl add 0 [1,2,3] == [1,3,6]\n * scanl :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscanl fn st l\n\t= st, l == []\n\t= st' : scanl fn st' xs\n{\n\tx:xs = l;\n\tst' = fn st x;\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta:x = l1;\n\t\tb:y = l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/compat/8.6/_magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate _magick.def\n\t Add 0-ary and 2-ary system\n\t Put utility funcs into a Magick class\n   11-Apr-2014 snibgo\n     Added VirtualPixelBack for cases where background is only relevant when VP=Background\n   17-Apr-2014 snibgo\n     Many small changes.\n   2-May-2014 jcupitt\n     Added Magick.version\n   30-June-2014\n   \t Put single-quotes around command exe to help win\n   1-July-2014\n     Automatically fall back to gm if we can't find convert\n   17-July-2014\n     better GM support\n\n\n   Last update: 17-July-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n\n*/\n\n/* Put these in a class to avoid filling the main namespace with IM stuff.\n */\n\nMagick = class {\n\n\t// first gm on path, or \"\"\n\tgm_path = search_for \"gm\";\n\n\t// first convert on $PATH, or \"\"\n\t// we check for the convert we ship first\n\tconvert_path \n\t\t= vips_convert, vips_convert != \"\"\n\t\t= search_for \"convert\"\n\t{\n\t\t// the convert we ship with the vips binary on some platforms, or \"\"\n\t\tvips_convert \n\t\t\t= search (path_absolute convert)\n\t\t{\n\t\t\tvipshome = path_parse (expand \"$VIPSHOME\");\n\t\t\tconvert = vipshome ++ [\"bin\", \"convert\" ++ expand \"$EXEEXT\"];\n\t\t}\n\t}\n\n\tuse_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK;\n\n\t// Are we in GM or IM mode? \n\tuse_gm \n\t\t= true, use_gm_pref && gm_path != \"\"\n\t\t= false, !use_gm_pref && convert_path != \"\"\n\t\t= false, convert_path != \"\"\n\t\t= true, gm_path != \"\"\n\t\t= error \"neither IM nor GM executable found\";\n\n\tcommand_path\n\t\t= gm_path, use_gm\n\t\t= convert_path;\n\n\t// try to get the version as eg. [6, 7, 7, 10]\n\t// GM versions are smaller, typically [1, 3, 18]\n\tversion\n\t\t= map parse_int (split (member \".-\") version_string)\n\t{\n\t\t[output] = vips_call \"system\" \n\t\t\t[\"'\" ++ command_path ++ \"' -version\"] [$log=>true];\n\t\tversion_string \n\t\t\t= (split (equal ' ') output)?1, use_gm\n\t\t\t= (split (equal ' ') output)?2;\n\t}\n\n\t// make a command-line ... args is a [str] we join with spaces\n\tcommand args \n\t\t= \"'\" ++ command_path ++ \"' \" ++ join_sep \" \" args'\n\t{\n\t\targs'\n\t\t\t= [\"convert\"] ++ args, use_gm\n\t\t\t= args;\n\t}\n\n\t// capabilities ... different versions support different features, we \n\t// turn features on and off based on these\n\n\t// would probably be better to test for caps somehow\n\thas_intensity\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\thas_channel\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\n\tsystem0 cmd = system_image0 cmd;\n\tsystem cmd x = map_unary (system_image cmd) x;\n\tsystem2 cmd x y = map_binary (system_image2 cmd) x y;\n\tsystem3 cmd x y z = map_trinary (system_image3 cmd) x y z;\n\n\tradius_widget = Scale \"Radius\" 0 100 10;\n\tsigma_widget = Scale \"Sigma\" 0.1 10 1;\n\tangle_widget = Scale \"Angle (degrees)\" (-360) 360 0;\n\ttext_widget = String \"Text to draw\" \"AaBbCcDdEe\";\n\n\tgamma_widget = Scale \"Gamma\" 0 10 1;\n\tcolors_widget = Scale \"Colors\" 1 10 3;\n\tresize_widget = Scale \"Resize (percent)\" 0 500 100;\n\tfuzz_widget = Scale \"Fuzz (percent)\" 0 100 0;\n\tblur_rad_widget = Scale \"Radius (0=auto)\" 0 100 0;\n\n\t// a colour with no enclosing quotes ... use this if we know there are\n\t// some quotes at an outer level\n\tprint_colour_nq triple\n\t\t= concat [\"#\", concat (map fmt triple)]\n\t{\n\t\tfmt x = reverse (take 2 (reverse (print_base 16 (x + 256))));\n\t}\n\n\t// we need the quotes because # is the comment character in *nix\n\tprint_colour triple = \"\\\"\" ++ print_colour_nq triple ++ \"\\\"\";\n\n\tForeground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-fill \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Foreground triple;\n\t}\n\tforeground_widget = Foreground [0, 0, 0];\n\n\tGeneralCol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = print_colour_nq triple;\n\n\t\tColour_edit space triple = this.GeneralCol triple;\n\t}\n\tgeneralcol_widget = GeneralCol [0, 0, 0];\n\n\tBackground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" false;\n\n\t\t_flag = \"-background \" ++ if isNone then \"None\" else print_colour triple;\n\n\t\tColour_edit space triple = this.Background triple;\n\t}\n\tbackground_widget = Background [255, 255, 255];\n\n\tBordercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-bordercolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Bordercol triple;\n\t}\n\tbordercol_widget = Bordercol [0, 0, 0];\n\n\tMattecol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-mattecolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Mattecol triple;\n\t}\n\tmattecol_widget = Mattecol [189, 189, 189];\n\n\t// FIXME: Undercolour, like many others, can have alpha channel.\n\t// How does user input this? With a slider?\n\tUndercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" true;\n\n\t\t_flag = if isNone then \"\" else (\"-undercolor \" ++ print_colour triple);\n\n\t\tColour_edit space triple = this.Undercol triple;\n\t}\n\tundercol_widget = Undercol [0, 0, 0];\n\n\tchangeCol_widget = class {\n\t\t_vislevel = 3;\n\n\t\tcolour = GeneralCol [0, 0, 0];\n\t\tfuzz = fuzz_widget;\n\t\tnonMatch = Toggle \"change non-matching colours\" false;\n\t}\n\n\tAlpha alpha = class\n\t\tOption_string \"Alpha\" [\n\t\t\t\"On\", \n\t\t\t\"Off\", \n\t\t\t\"Set\", \n\t\t\t\"Opaque\", \n\t\t\t\"Transparent\", \n\t\t\t\"Extract\", \n\t\t\t\"Copy\", \n\t\t\t\"Shape\", \n\t\t\t\"Remove\", \n\t\t\t\"Background\"\n\t\t] alpha {\n\n\t\t_flag = \"-alpha \" ++ alpha;\n\n\t\tOption_edit caption labels value = this.Alpha labels?value;\n\t}\n\talpha_widget = Alpha \"On\";\n\n\tAntialias value = class\n\t\tToggle \"Antialias\" value {\n\n\t\t_flag\n\t\t\t= \"-antialias\", value\n\t\t\t= \"+antialias\";\n\n\t\tToggle_edit caption value = this.Antialias value;\n\t}\n\tantialias_widget = Antialias true;\n\n\tBuiltin builtin = class\n\t\tOption_string \"Builtin\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"rose:\",\n\t\t\t\"logo:\",\n\t\t\t\"wizard:\",\n\t\t\t\"granite:\",\n\t\t\t\"netscape:\"\n\t\t] builtin {\n\n\t\t_flag = builtin;\n\n\t\tOption_edit caption labels value = this.Builtin labels?value;\n\t}\n\tbuiltin_widget = Builtin \"rose:\";\n\n\n\tchannels_widget = class {\n\t\t// FIXME? Can we grey-out alpha when we have no alpha channel,\n\t\t//        show CMY(K) instead of RGB(K) etc?\n\t\t// Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA.\n\t\tChanR valueR = class\n\t\t\tToggle \"Red\" valueR {\n\n\t\t\t_flag\n\t\t\t\t= \"R\", valueR\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueR = this.ChanR valueR;\n\t\t}\n\t\tchannelR = ChanR true;\n\n\t\tChanG valueG = class\n\t\t\tToggle \"Green\" valueG {\n\n\t\t\t_flag\n\t\t\t\t= \"G\", valueG\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueG = this.ChanG valueG;\n\t\t}\n\t\tchannelG = ChanG true;\n\n\t\tChanB valueB = class\n\t\t\tToggle \"Blue\" valueB {\n\n\t\t\t_flag\n\t\t\t\t= \"B\", valueB\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueB = this.ChanB valueB;\n\t\t}\n\t\tchannelB = ChanB true;\n\n\t\tChanK valueK = class\n\t\t\tToggle \"Black\" valueK {\n\n\t\t\t_flag\n\t\t\t\t= \"K\", valueK\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueK = this.ChanK valueK;\n\t\t}\n\t\tchannelK = ChanK true;\n\n\t\tChanA valueA = class\n\t\t\tToggle \"Alpha\" valueA {\n\n\t\t\t_flag\n\t\t\t\t= \"A\", valueA\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueA = this.ChanA valueA;\n\t\t}\n\t\tchannelA = ChanA false;\n\n\t\tChanSy valueSy = class\n\t\t\tToggle \"Sync\" valueSy {\n\n\t\t\t_flag\n\t\t\t\t= \",sync\", valueSy\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueSy = this.ChanSy valueSy;\n\t\t}\n\t\tchannelSy = ChanSy true;\n\n\t\t_rgbka = concat [channelR._flag,\n\t\t\t\tchannelG._flag,\n\t\t\t\tchannelB._flag,\n\t\t\t\tchannelK._flag,\n\t\t\t\tchannelA._flag\n\t\t\t];\n\n\t\t_flag\n\t\t\t= \"\", _rgbka == \"\" || !has_channel\n\t\t\t= concat [ \"-channel \",\n\t\t\t\t_rgbka,\n\t\t\t\tchannelSy._flag \n\t\t\t\t];\n\t}\n\n\tch_widget = channels_widget;\n\n\tColorspace colsp = class\n\t\tOption_string \"Colorspace\" [\n\t\t\t\"CIELab\",\n\t\t\t\"CMY\",\n\t\t\t\"CMYK\",\n\t\t\t\"Gray\",\n\t\t\t\"HCL\",\n\t\t\t\"HCLp\",\n\t\t\t\"HSB\",\n\t\t\t\"HSI\",\n\t\t\t\"HSL\",\n\t\t\t\"HSV\",\n\t\t\t\"HWB\",\n\t\t\t\"Lab\",\n\t\t\t\"LCH\",\n\t\t\t\"LCHab\",\n\t\t\t\"LCHuv\",\n\t\t\t\"LMS\",\n\t\t\t\"Log\",\n\t\t\t\"Luv\",\n\t\t\t\"OHTA\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601YCbCr\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709YCbCr\",\n\t\t\t\"RGB\",\n\t\t\t\"scRGB\",\n\t\t\t\"sRGB\",\n\t\t\t\"Transparent\",\n\t\t\t\"XYZ\",\n\t\t\t\"YCbCr\",\n\t\t\t\"YDbDr\",\n\t\t\t\"YCC\",\n\t\t\t\"YIQ\",\n\t\t\t\"YPbPr\",\n\t\t\t\"YUV\"\n\t\t] colsp {\n\n\t\t_flag = colsp;\n\n\t\tOption_edit caption labels value = this.Colorspace labels?value;\n\t}\n\tcolorspace_widget = Colorspace \"sRGB\";\n\n\tCompose comp = class\n\t\tOption_string \"Compose method\" [\n\t\t\t\"Atop\", \n\t\t\t\"Blend\", \n\t\t\t\"Blur\", \n\t\t\t\"Bumpmap\", \n\t\t\t\"ChangeMask\", \n\t\t\t\"Clear\", \n\t\t\t\"ColorBurn\", \n\t\t\t\"ColorDodge\", \n\t\t\t\"Colorize\", \n\t\t\t\"CopyBlack\", \n\t\t\t\"CopyBlue\", \n\t\t\t\"CopyCyan\", \n\t\t\t\"CopyGreen\", \n\t\t\t\"Copy\", \n\t\t\t\"CopyMagenta\", \n\t\t\t\"CopyOpacity\", \n\t\t\t\"CopyRed\", \n\t\t\t\"CopyYellow\", \n\t\t\t\"Darken\", \n\t\t\t\"DarkenIntensity\", \n\t\t\t\"DivideDst\", \n\t\t\t\"DivideSrc\", \n\t\t\t\"Dst\", \n\t\t\t\"Difference\", \n\t\t\t\"Displace\", \n\t\t\t\"Dissolve\", \n\t\t\t\"Distort\", \n\t\t\t\"DstAtop\", \n\t\t\t\"DstIn\", \n\t\t\t\"DstOut\", \n\t\t\t\"DstOver\", \n\t\t\t\"Exclusion\", \n\t\t\t\"HardLight\", \n\t\t\t\"Hue\", \n\t\t\t\"In\", \n\t\t\t\"Lighten\", \n\t\t\t\"LightenIntensity\", \n\t\t\t\"LinearBurn\", \n\t\t\t\"LinearDodge\", \n\t\t\t\"LinearLight\", \n\t\t\t\"Luminize\", \n\t\t\t\"Mathematics\", \n\t\t\t\"MinusDst\", \n\t\t\t\"MinusSrc\", \n\t\t\t\"Modulate\", \n\t\t\t\"ModulusAdd\", \n\t\t\t\"ModulusSubtract\", \n\t\t\t\"Multiply\", \n\t\t\t\"None\", \n\t\t\t\"Out\", \n\t\t\t\"Overlay\", \n\t\t\t\"Over\", \n\t\t\t\"PegtopLight\", \n\t\t\t\"PinLight\", \n\t\t\t\"Plus\", \n\t\t\t\"Replace\", \n\t\t\t\"Saturate\", \n\t\t\t\"Screen\", \n\t\t\t\"SoftLight\", \n\t\t\t\"Src\", \n\t\t\t\"SrcAtop\", \n\t\t\t\"SrcIn\", \n\t\t\t\"SrcOut\", \n\t\t\t\"SrcOver\", \n\t\t\t\"VividLight\", \n\t\t\t\"Xor\"\n\t\t] comp {\n\n\t\t_flag = \"-compose \" ++ comp;\n\n\t\tOption_edit caption labels value = this.Compose labels?value;\n\t}\n\tcompose_widget = Compose \"Over\";\n\t// FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string.\n\n\t// FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack\n\n\tcoordinate_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\n\t\t_flag = concat [print x.expr, \",\", print y.expr];\n\t};\n\n\tDistort distort = class\n\t\tOption_string \"Distort\" [\n\t\t\t\"Affine\",\n\t\t\t\"AffineProjection\",\n\t\t\t\"ScaleRotateTranslate\",\n\t\t\t\"SRT\",\n\t\t\t\"Perspective\",\n\t\t\t\"PerspectiveProjection\",\n\t\t\t\"BilinearForward\",\n\t\t\t\"BilinearReverse\",\n\t\t\t\"Polynomial\",\n\t\t\t\"Arc\",\n\t\t\t\"Polar\",\n\t\t\t\"DePolar\",\n\t\t\t\"Barrel\",\n\t\t\t\"BarrelInverse\",\n\t\t\t\"Shepards\",\n\t\t\t\"Resize\"\n\t\t] distort {\n\n\t\t_flag = distort;\n\n\t\tOption_edit caption labels value = this.Distort labels?value;\n\t}\n\tdistort_widget = Distort \"SRT\";\n\n\tDither dither = class\n\t\tOption_string \"Dither\" [\n\t\t\t\"None\",\n\t\t\t\"FloydSteinberg\",\n\t\t\t\"Riemersma\"\n\t\t] dither {\n\n\t\t_flag = \"-dither \" ++ dither;\n\n\t\tOption_edit caption labels value = this.Dither labels?value;\n\t}\n\tdither_widget = Dither \"FloydSteinberg\";\n\n\tEvaluate eval = class\n\t\tOption_string \"Evaluate operation\" [\n\t\t\t\"Abs\",\n\t\t\t\"Add\",\n\t\t\t\"AddModulus\",\n\t\t\t\"And\",\n\t\t\t\"Cos\",\n\t\t\t\"Cosine\",\n\t\t\t\"Divide\",\n\t\t\t\"Exp\",\n\t\t\t\"Exponential\",\n\t\t\t\"GaussianNoise\",\n\t\t\t\"ImpulseNoise\",\n\t\t\t\"LaplacianNoise\",\n\t\t\t\"LeftShift\",\n\t\t\t\"Log\",\n\t\t\t\"Max\",\n\t\t\t\"Mean\",\n\t\t\t\"Median\",\n\t\t\t\"Min\",\n\t\t\t\"MultiplicativeNoise\",\n\t\t\t\"Multiply\",\n\t\t\t\"Or\",\n\t\t\t\"PoissonNoise\",\n\t\t\t\"Pow\",\n\t\t\t\"RightShift\",\n\t\t\t\"Set\",\n\t\t\t\"Sin\",\n\t\t\t\"Sine\",\n\t\t\t\"Subtract\",\n\t\t\t\"Sum\",\n\t\t\t\"Threshold\",\n\t\t\t\"ThresholdBlack\",\n\t\t\t\"ThresholdWhite\",\n\t\t\t\"UniformNoise\",\n\t\t\t\"Xor\"\n\t\t] eval {\n\n\t\t_flag = \"-evaluate \" ++ eval;\n\n\t\tOption_edit caption labels value = this.Evaluate labels?value;\n\t}\n\tevaluate_widget = Evaluate \"Add\";\n\n\tFilter filt = class\n\t\tOption_string \"Filter\" [\n\t\t\t\"default\",\n\t\t\t\"Bartlett\",\n\t\t\t\"Blackman\",\n\t\t\t\"Bohman\",\n\t\t\t\"Box\",\n\t\t\t\"Catrom\",\n\t\t\t\"Cosine\",\n\t\t\t\"Cubic\",\n\t\t\t\"Gaussian\",\n\t\t\t\"Hamming\",\n\t\t\t\"Hann\",\n\t\t\t\"Hermite\",\n\t\t\t\"Jinc\",\n\t\t\t\"Kaiser\",\n\t\t\t\"Lagrange\",\n\t\t\t\"Lanczos\",\n\t\t\t\"Lanczos2\",\n\t\t\t\"Lanczos2Sharp\",\n\t\t\t\"LanczosRadius\",\n\t\t\t\"LanczosSharp\",\n\t\t\t\"Mitchell\",\n\t\t\t\"Parzen\",\n\t\t\t\"Point\",\n\t\t\t\"Quadratic\",\n\t\t\t\"Robidoux\",\n\t\t\t\"RobidouxSharp\",\n\t\t\t\"Sinc\",\n\t\t\t\"SincFast\",\n\t\t\t\"Spline\",\n\t\t\t\"Triangle\",\n\t\t\t\"Welch\"\n\t\t] filt {\n\n\t\t_flag = if filt == \"default\" then \"\" else \"-filter \" ++ filt;\n\n\t\tOption_edit caption labels value = this.Filter labels?value;\n\t}\n\tfilter_widget = Filter \"default\";\n\n\tFunction func = class\n\t\tOption_string \"Function\" [\n\t\t\t\"Polynomial\",\n\t\t\t\"Sinusoid\",\n\t\t\t\"Arcsin\",\n\t\t\t\"Arctan\"\n\t\t] func {\n\n\t\t_flag = func;\n\n\t\tOption_edit caption labels value = this.Function labels?value;\n\t}\n\tfunction_widget = Function \"Polynomial\";\n\n//  \"Polynomial (a[n], a[n-1], ... a[1], a[0])\",\n//  \"Sinusoid (freq, phase, amp, bias)\",\n//  \"Arcsin (width, centre, range, bias)\",\n//  \"Arctan (slope, centre, range, bias)\"\n\n\tGravity gravity = class\n\t\tOption_string \"Gravity\" [\n\t\t\t\"None\",\n\t\t\t\"Center\",\n\t\t\t\"East\",\n\t\t\t\"Forget\",\n\t\t\t\"NorthEast\",\n\t\t\t\"North\",\n\t\t\t\"NorthWest\",\n\t\t\t\"SouthEast\",\n\t\t\t\"South\",\n\t\t\t\"SouthWest\",\n\t\t\t\"West\",\n\t\t\t\"Static\"\n\t\t] gravity {\n\n\t\t_flag = \"-gravity \" ++ gravity;\n\n\t\tOption_edit caption labels value = this.Gravity labels?value;\n\t}\n\tgravity_widget = Gravity \"Center\";\n\n\tImageType imagetype = class\n\t\tOption_string \"Image type\" [\n\t\t\t\"Bilevel\",\n\t\t\t\"ColorSeparation\",\n\t\t\t\"ColorSeparationAlpha\",\n\t\t\t\"ColorSeparationMatte\",\n\t\t\t\"Grayscale\",\n\t\t\t\"GrayscaleAlpha\",\n\t\t\t\"GrayscaleMatte\",\n\t\t\t\"Optimize\",\n\t\t\t\"Palette\",\n\t\t\t\"PaletteBilevelAlpha\",\n\t\t\t\"PaletteBilevelMatte\",\n\t\t\t\"PaletteAlpha\",\n\t\t\t\"PaletteMatte\",\n\t\t\t\"TrueColorAlpha\",\n\t\t\t\"TrueColorMatte\",\n\t\t\t\"TrueColor\"\n\t\t] imagetype {\n\n\t\t_flag = \"-type \" ++ imagetype;\n\n\t\tOption_edit caption labels value = this.ImageType labels?value;\n\t}\n\timagetype_widget = ImageType \"TrueColor\";\n\n\tIntensity intensity = class\n\t\tOption_string \"Intensity (gray conversion)\" [\n\t\t\t\"Average\",\n\t\t\t\"Brightness\",\n\t\t\t\"Lightness\",\n\t\t\t\"MS\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601Luminance\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709Luminance\",\n\t\t\t\"RMS\"\n\t\t] intensity {\n\n\t\t_flag \n\t\t\t= \"-intensity \" ++ intensity, has_intensity\n\t\t\t= \"\";\n\n\t\tOption_edit caption labels value = this.Intensity labels?value;\n\t}\n\tintensity_widget = Intensity \"Rec709Luminance\";\n\n\tInterpolate interp = class\n\t\tOption_string \"Interpolate\" [\n\t\t\t\"default\",\n\t\t\t\"Average\",\n\t\t\t\"Average4\",\n\t\t\t\"Average9\",\n\t\t\t\"Average16\",\n\t\t\t\"Background\",\n\t\t\t\"Bilinear\",\n\t\t\t\"Blend\",\n\t\t\t\"Integer\",\n\t\t\t\"Mesh\",\n\t\t\t\"Nearest\",\n\t\t\t\"NearestNeighbor\",\n\t\t\t\"Spline\"\n\t\t] interp {\n\n\t\t_flag = if interp == \"default\" then \"\" else \"-interpolate \" ++ interp;\n\n\t\tOption_edit caption labels value = this.Interpolate labels?value;\n\t}\n\tinterpolate_widget = Interpolate \"default\";\n\n\tKernel kernel = class\n\t\tOption_string \"Kernel\" [\n\t\t\t\"Unity\",\n\t\t\t\"Gaussian\",\n\t\t\t\"DoG\",\n\t\t\t\"LoG\",\n\t\t\t\"Blur\",\n\t\t\t\"Comet\",\n\t\t\t\"Binomial\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Sobel\",\n\t\t\t\"FreiChen\",\n\t\t\t\"Roberts\",\n\t\t\t\"Prewitt\",\n\t\t\t\"Compass\",\n\t\t\t\"Kirsch\",\n\t\t\t\"Diamond\",\n\t\t\t\"Square\",\n\t\t\t\"Rectangle\",\n\t\t\t\"Disk\",\n\t\t\t\"Octagon\",\n\t\t\t\"Plus\",\n\t\t\t\"Cross\",\n\t\t\t\"Ring\",\n\t\t\t\"Peaks\",\n\t\t\t\"Edges\",\n\t\t\t\"Corners\",\n\t\t\t\"Diagonals\",\n\t\t\t\"LineEnds\",\n\t\t\t\"LineJunctions\",\n\t\t\t\"Ridges\",\n\t\t\t\"ConvexHull\",\n\t\t\t\"ThinSe\",\n\t\t\t\"Skeleton\",\n\t\t\t\"Chebyshev\",\n\t\t\t\"Manhattan\",\n\t\t\t\"Octagonal\",\n\t\t\t\"Euclidean\"\n\t\t\t// FIXME: custom kernel\n\t\t] kernel {\n\n\t\t_flag = kernel;\n\n\t\tOption_edit caption labels value = this.Kernel labels?value;\n\t}\n\tkernel_widget = Kernel \"Unity\";\n\n\tModColSp msp = class\n\t\tOption_string \"modulate colorspace\" [\n\t\t\t\"HCL\", \n\t\t\t\"HCLp\", \n\t\t\t\"HSB\", \n\t\t\t\"HSI\", \n\t\t\t\"HSL\", \n\t\t\t\"HSV\", \n\t\t\t\"HWB\", \n\t\t\t\"LCH\"\n\t\t] msp {\n\n\t\t_flag = \"-set option:modulate:colorspace \" ++ msp;\n\n\t\tOption_edit caption labels value = this.ModColSp labels?value;\n\t}\n\tModColSp_widget = ModColSp \"HSL\";\n\n\tMorphMeth morph = class\n\t\tOption_string \"Method\" [\n\t\t\t\"Correlate\",\n\t\t\t\"Convolve\",\n\t\t\t\"Dilate\",\n\t\t\t\"Erode\",\n\t\t\t\"Close\",\n\t\t\t\"Open\",\n\t\t\t\"DilateIntensity\",\n\t\t\t\"ErodeIntensity\",\n\t\t\t\"CloseIntensity\",\n\t\t\t\"OpenIntensity\",\n\t\t\t\"Smooth\",\n\t\t\t\"EdgeOut\",\n\t\t\t\"EdgeIn\",\n\t\t\t\"Edge\",\n\t\t\t\"TopHat\",\n\t\t\t\"BottomHat\",\n\t\t\t\"HitAndMiss\",\n\t\t\t\"Thinning\",\n\t\t\t\"Thicken\",\n\t\t\t\"Distance\",\n\t\t\t\"IterativeDistance\"\n\t\t] morph {\n\n\t\t_flag = morph;\n\n\t\tOption_edit caption labels value = this.MorphMeth labels?value;\n\t}\n\tmorphmeth_widget = MorphMeth \"Dilate\";\n\n\tNoise noise = class\n\t\tOption_string \"Noise\" [\n\t\t\t\"Gaussian\",\n\t\t\t\"Impulse\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Multiplicative\",\n\t\t\t\"Poisson\",\n\t\t\t\"Random\",\n\t\t\t\"Uniform\"\n\t\t] noise {\n\n\t\t_flag = \"+noise \" ++ noise;\n\n\t\tOption_edit caption labels value = this.Noise labels?value;\n\t}\n\tnoise_widget = Noise \"Gaussian\";\n\n\tPattern pattern = class\n\t\tOption_string \"Noise\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"bricks\",\n\t\t\t\"checkerboard\",\n\t\t\t\"circles\",\n\t\t\t\"crosshatch\",\n\t\t\t\"crosshatch30\",\n\t\t\t\"crosshatch45\",\n\t\t\t\"gray0\",\n\t\t\t\"gray5\",\n\t\t\t\"gray10\",\n\t\t\t\"gray15\",\n\t\t\t\"gray20\",\n\t\t\t\"gray25\",\n\t\t\t\"gray30\",\n\t\t\t\"gray35\",\n\t\t\t\"gray40\",\n\t\t\t\"gray45\",\n\t\t\t\"gray50\",\n\t\t\t\"gray55\",\n\t\t\t\"gray60\",\n\t\t\t\"gray65\",\n\t\t\t\"gray70\",\n\t\t\t\"gray75\",\n\t\t\t\"gray80\",\n\t\t\t\"gray85\",\n\t\t\t\"gray90\",\n\t\t\t\"gray95\",\n\t\t\t\"gray100\",\n\t\t\t\"hexagons\",\n\t\t\t\"horizontal\",\n\t\t\t\"horizontal2\",\n\t\t\t\"horizontal3\",\n\t\t\t\"horizontalsaw\",\n\t\t\t\"hs_bdiagonal\",\n\t\t\t\"hs_cross\",\n\t\t\t\"hs_diagcross\",\n\t\t\t\"hs_fdiagonal\",\n\t\t\t\"hs_horizontal\",\n\t\t\t\"hs_vertical\",\n\t\t\t\"left30\",\n\t\t\t\"left45\",\n\t\t\t\"leftshingle\",\n\t\t\t\"octagons\",\n\t\t\t\"right30\",\n\t\t\t\"right45\",\n\t\t\t\"rightshingle\",\n\t\t\t\"smallfishscales\",\n\t\t\t\"vertical\",\n\t\t\t\"vertical2\",\n\t\t\t\"vertical3\",\n\t\t\t\"verticalbricks\",\n\t\t\t\"verticalleftshingle\",\n\t\t\t\"verticalrightshingle\",\n\t\t\t\"verticalsaw\"\n\t\t] pattern {\n\n\t\t_flag = \"pattern:\" ++ pattern;\n\n\t\tOption_edit caption labels value = this.Pattern labels?value;\n\t}\n\tpattern_widget = Pattern \"bricks\";\n\n\tResizeType resizet = class\n\t\tOption_string \"Resize type\" [\n\t\t\t\"resize\", \n\t\t\t\"scale\",\n\t\t\t\"sample\",\n\t\t\t\"adaptive-resize\"\n\t\t] resizet {\n\n\t\t_flag = resizet;\n\n\t\tOption_edit caption labels value = this.ResizeType labels?value;\n\t}\n\tResizeType_widget = ResizeType \"resize\";\n\n\tSize_widget = class {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width (pixels)\" 64;\n\t\theight = Expression \"Height (pixels)\" 64;\n\n\t\t_flag = \"-size \" ++\n\t\t\tprint width.expr ++ \"x\" ++ print height.expr;\n\n\t};\n\n\tStatType statt = class\n\t\tOption_string \"Statistic type\" [\n\t\t\t\"Gradient\", \n\t\t\t\"Maximum\", \n\t\t\t\"Mean\", \n\t\t\t\"Median\", \n\t\t\t\"Minimum\", \n\t\t\t\"Mode\", \n\t\t\t\"Nonpeak\", \n\t\t\t\"StandardDeviation\"\n\t\t] statt {\n\n\t\t_flag = statt;\n\n\t\tOption_edit caption labels value = this.StatType labels?value;\n\t}\n\tStatType_widget = StatType \"Mean\";\n\n\tVirtualPixel vp = class\n\t\tOption_string \"Virtual pixel\" [\n\t\t\t\"Background\", \n\t\t\t\"Black\", \n\t\t\t\"CheckerTile\", \n\t\t\t\"Dither\", \n\t\t\t\"Edge\", \n\t\t\t\"Gray\", \n\t\t\t\"HorizontalTile\", \n\t\t\t\"HorizontalTileEdge\", \n\t\t\t\"Mirror\", \n\t\t\t\"None\",\n\t\t\t\"Random\",\n\t\t\t\"Tile\",\n\t\t\t\"Transparent\",\n\t\t\t\"VerticalTile\",\n\t\t\t\"VerticalTileEdge\",\n\t\t\t\"White\"\n\t\t] vp {\n\n\t\t_flag = \"-virtual-pixel \" ++ vp;\n\n\t\t_isBackground = (vp == \"Background\");\n\n\t\tOption_edit caption labels value = this.VirtualPixel labels?value;\n\t}\n\tVirtualPixel_widget = VirtualPixel \"Edge\";\n\n\tVirtualPixelBack_widget = class {\n\t\tvirtpix = Magick.VirtualPixel_widget;\n\t\tbackground = Magick.background_widget;\n\t\t_flag = (if virtpix._isBackground then (background._flag ++ \" \") else \"\")\n\t\t\t++ virtpix._flag;\n\t}\n\n\tGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tAnnotGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print shearX.expr, \"x\", print shearY.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tOffsetGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag = concat [format hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tWhxyGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFrameGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\toutbev = Expression \"Outer bevel thickness\" 0;\n\t\tinbev = Expression \"Inner bevel thickness\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat outbev, format inbev]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFont_widget = class {\n\t\t_vislevel = 3;\n\n\t\tfamily = Option_string \"Family\" [\n\t\t\t\"Arial\",\n\t\t\t\"ArialBlack\",\n\t\t\t\"AvantGarde\",\n\t\t\t\"BitstreamCharter\",\n\t\t\t\"Bookman\",\n\t\t\t\"CenturySchoolbook\",\n\t\t\t\"ComicSansMS\",\n\t\t\t\"Courier\",\n\t\t\t\"CourierNew\",\n\t\t\t\"DejaVuSans\",\n\t\t\t\"DejaVuSansMono\",\n\t\t\t\"DejaVuSerif\",\n\t\t\t\"Dingbats\",\n\t\t\t\"FreeMono\",\n\t\t\t\"FreeSans\",\n\t\t\t\"FreeSerif\",\n\t\t\t\"Garuda\",\n\t\t\t\"Georgia\",\n\t\t\t\"Helvetica\",\n\t\t\t\"HelveticaNarrow\",\n\t\t\t\"Impact\",\n\t\t\t\"LiberationMono\",\n\t\t\t\"LiberationSans\",\n\t\t\t\"LiberationSerif\",\n\t\t\t\"NewCenturySchlbk\",\n\t\t\t\"Palatino\",\n\t\t\t\"Purisa\",\n\t\t\t\"Symbol\",\n\t\t\t\"Times\",\n\t\t\t\"TimesNewRoman\",\n\t\t\t\"Ubuntu\",\n\t\t\t\"Verdana\",\n\t\t\t\"Webdings\"\n\t\t] \"Arial\";\n\t\tstyle = Option_string \"Style\" [\n\t\t\t\"Any\", \"Italic\", \"Normal\", \"Oblique\"\n\t\t] \"Normal\";\n\t\tweight = Scale \"Weight\" 1 800 400;\n\t\tsize = Scale \"Point size\" 1 100 12;\n\t\tstretch = Option_string \"Stretch\" [\n\t\t\t\"Any\", \"Condensed\", \"Expanded\", \"ExtraCondensed\", \"ExtraExpanded\", \n\t\t\t\"Normal\", \"SemiCondensed\", \"SemiExpanded\", \"UltraCondensed\", \n\t\t\t\"UltraExpanded\"\n\t\t] \"Normal\";\n\n\t\t_flag = join_sep \" \" [\n\t\t\t\t\"-family\", family.item,\n\t\t\t\t\"-weight\", print weight.value,\n\t\t\t\t\"-pointsize\", print size.value,\n\t\t\t\t\"-style\", style.item,\n\t\t\t\t\"-stretch\", stretch.item];\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/compat/8.6/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = any (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && all (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* Test list length ... quicker than len x == n for large lists.\n */\nis_list_len n x\n\t= true, x == [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len (n - 1) (tl x);\n\nis_list_len_more n x\n\t= true, x != [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len_more (n - 1) (tl x);\n\nis_list_len_more_equal n x\n\t= true, n == 0\n\t= false, x == [] \n\t= is_list_len_more_equal (n - 1) (tl x);\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, all (map is_obj l)\n\t= true, all (map is_list l) &&\n\t\tall (map (not @ is_obj) l) &&\n\t\tall (map is_rectangular l) &&\n\t\tis_list_len_more 0 l &&\n\t\tall (map (is_list_len (len (hd l))) (tl l))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && is_list_len (len (hd l)) l;\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_NULL x = is_instanceof \"NULL\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Plot x = is_instanceof \"Plot\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && all (map xy l)\n{\n\txy l = is_real_list l && is_list_len 2 l;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && any (map is_Group l)\n\t= any (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= oo_unary_function get_type_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_type\")\n{\n\tget_type_op = Operator \"get_type\" get_type \n\t\tOperator_type.COMPOUND false;\n\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\t// can have alpha, hence we let bands be one more than you might think\n\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.scRGB, coding == Image_coding.RAD\n\t\t= Image_type.GREY16, type == Image_type.GREY16 && is_bands 1\n\t\t= Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && \n\t\t\t(width == 1 || height == 1)\n\t\t= Image_type.B_W, is_bands 1 \n\t\t= Image_type.CMYK, type == Image_type.CMYK && is_bands 4\n\t\t= type, is_colorimetric && is_bands 3\n\t\t= Image_type.sRGB, !is_colorimetric && is_bands 3\n\t\t= Image_type.MULTIBAND, !is_colorimetric && !is_bands 3\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.scRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\n\t\t// is bands n, with an optional alpha (ie. can be n + 1 too)\n\t\tis_bands n = bands == n || bands == n + 1;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= oo_unary_function get_format_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_format\")\n{\n\tget_format_op = Operator \"get_format\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= oo_unary_function get_bits_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bits\")\n{\n\tget_bits_op = Operator \"get_bits\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= oo_unary_function get_bands_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bands\")\n{\n\tget_bands_op = Operator \"get_bands\" get_bands \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= oo_unary_function get_coding_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_coding\")\n{\n\tget_coding_op = Operator \"get_coding\" get_coding \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= oo_unary_function get_xres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xres\")\n{\n\tget_xres_op = Operator \"get_xres\" get_xres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= oo_unary_function get_yres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yres\")\n{\n\tget_yres_op = Operator \"get_yres\" get_yres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= oo_unary_function get_xoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xoffset\")\n{\n\tget_xoffset_op = Operator \"get_xoffset\" get_xoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= oo_unary_function get_yoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yoffset\")\n{\n\tget_yoffset_op = Operator \"get_yoffset\" get_yoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= oo_unary_function get_image_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_image\")\n{\n\tget_image_op = Operator \"get_image\" get_image \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= oo_unary_function get_number_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_number\")\n{\n\tget_number_op = Operator \"get_number\" get_number \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= oo_unary_function get_real_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_real\")\n{\n\tget_real_op = Operator \"get_real\" get_real \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= oo_unary_function get_width_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_width\")\n{\n\tget_width_op = Operator \"get_width\" get_width \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= oo_unary_function get_height_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_height\")\n{\n\tget_height_op = Operator \"get_height\" get_height \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= oo_unary_function get_left_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_left\")\n{\n\tget_left_op = Operator \"get_left\" get_left \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= oo_unary_function get_top_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_top\")\n{\n\tget_top_op = Operator \"get_top\" get_top \n\t\tOperator_type.COMPOUND false;\n}\n\n// like has/get member, but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/compat/8.6/_stdenv.def",
    "content": "/* optional args to functions\n */\n\nget_option options defaults f\n\t= error (_ \"unknown parameter \" ++ f), hits == []\n\t= hits?0\n{\n\thits = [v :: [n, v] <- options ++ defaults; n == f];\n}\n\n/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\nidivide a b = (int) ((int) a / (int) b);\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\n// 'difference' is defined in _list\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the function we call for \"a -> v\" expressions\nmksvpair s v\n\t= [s, v], is_string s\n\t= error \"not str on lhs of ->\";\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error (\"unimplemented vector operation: \" ++ op_name)\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n// make a name value pair\nmknvpair n v\n\t= [n, v], is_string n\n\t= error \"not [char] on LHS of =>\";\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined, has_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nbandand x\n\t= oo_unary_function bandand_op x, is_class x\n\t= foldr1 bitwise_and (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandand\")\n{\n\tbandand_op = Operator \"bandand\" bandand Operator_type.COMPOUND_REWRAP false;\n}\n\nbandor x\n\t= oo_unary_function bandor_op x, is_class x\n\t= foldr1 bitwise_or (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandor\")\n{\n\tbandor_op = Operator \"bandor\" bandor Operator_type.COMPOUND_REWRAP false;\n}\n\nsum x\n\t= oo_unary_function sum_op x, is_class x\n\t= im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x\n\t= sum_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"sum\")\n{\n\tsum_op = Operator \"sum\" sum Operator_type.COMPOUND false;\n\n\t// add elements in a nested-list thing\n\tsum_list l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nproduct x\n\t= oo_unary_function product_op x, is_class x\n\t= product_list x, is_list x \n\t// (product image) doesn't make much sense :(\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"product\")\n{\n\tproduct_op = Operator \"product\" product Operator_type.COMPOUND false;\n\n\tproduct_list l\n\t\t= foldr prod 1 l\n\t{\n\t\tprod x total\n\t\t\t= total * product x, is_list x\n\t\t\t= total * x;\n\t}\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\nskew x\n\t= oo_unary_function skew_op x, is_class x\n\t= sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x \n\t= sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"skew\")\n{\n\tskew_op = Operator \"skew\" skew Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN \n\t\t= w * h * b, is_image x'\n\t\t= len x';\n}\n\nkurtosis x\n\t= oo_unary_function kurtosis_op x, is_class x\n\t= sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x \n\t= sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"kurtosis\")\n{\n\tkurtosis_op = Operator \"kurtosis\" kurtosis Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN\n\t\t= len x', is_list x';\n\t\t= w * h * b;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image_hist x, is_image x && \n\t\t(fmt == Image_format.UCHAR || fmt == Image_format.USHORT)\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tfmt = get_format x;\n\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean, for any image type\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n\n\t// image mean for 8 and 16-bit unsigned images\n\t// we can use a histogram, yay, and save a pass through the image\n\tmeanze_image_hist i\n\t\t= sum / N\n\t{\n\t\t// histogram, knock out zeros\n\t\thist = hist_find i;\n\t\tblack = image_new 1 1 (get_bands hist) \n\t\t\t(get_format hist) (get_coding hist) (get_type hist) 0 0 0;\n\t\thistze = insert 0 0 black hist;\n\n\t\t// matching identity\n\t\tiden\n\t\t\t= im_identity_ushort (get_bands hist) (get_width hist),\n\t\t\t\t(get_width hist) > 256\n\t\t\t= im_identity (get_bands hist);\n\n\t\t// number of non-zero pixels\n\t\tN = mean histze * 256;\n\n\t\t// sum of pixels\n\t\tsum = mean (hist * iden) * 256;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_tile_cache_random x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (\\row [row?x']) obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\" ++ \": \" ++\n\t\tjoin_sep \", \" (map print [cond, in1, in2]))\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x \n\t\t\t= to_image_size target_width target_height \n\t\t\t\ttarget_bands target_format x;\n\n\t\t[then_image, else_image] = map to_image [then_part, else_part];\n\n\t\tblend_result_image = image_set_type target_type \n\t\t\t(im_blend cond then_image else_image);\n\t}\n}\n\n// do big first: we want to keep big's class, if possible\n// eg. big is a Plot, small is a 1x1 Image\ninsert x y small big\n\t= oo_binary'_function insert_op small big, is_class big\n\t= oo_binary_function insert_op small big, is_class small\n\t= im_insert big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ndecode im\n\t= oo_unary_function decode_op im, is_class im\n\t= decode_im im, is_image im\n\t= error (_ \"bad arguments to \" ++ \"decode\")\n{\n\tdecode_op = Operator \"decode\" \n\t\tdecode Operator_type.COMPOUND_REWRAP false;\n\n\tdecode_im im\n\t\t= im_LabQ2Lab im, get_coding im == Image_coding.LABPACK\n\t\t= im_rad2float im, get_coding im == Image_coding.RAD\n\t\t= im;\n}\n\nmeasure_draw across down measure image\n    = mark\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n\n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::  \n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n    x = map (extract 0) cods;\n    y = map (extract 1) cods;\n\n    outer = mkim [$pixel => 255] sample_width sample_height 1;\n    inner = mkim [] (sample_width - 4) (sample_height - 4) 1;\n    patch = insert 2 2 inner outer;\n\n    bg = mkim [] image.width image.height 1;\n\n    mask = Image (im_insertset bg.value patch.value x y);\n\n    image' = colour_transform_to Image_type.sRGB image;\n\n    mark = if mask then Vector [0, 255, 0] else image';\n}\n\nmeasure_sample across down measure image\n    = measures\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n                \n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::\n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n\n\timage' = decode image;\n    patches = map (\\p extract_area p?0 p?1 sample_width sample_height image') \n\t\tcods;\n    measures = Matrix (map (map mean) (map bandsplit patches));\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ninvert x\n\t= oo_unary_function invert_op x, is_class x\n\t= im_invert x, is_image x\n\t= 255 - x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"invert\")\n{\n\tinvert_op = Operator \"invert\" invert Operator_type.COMPOUND false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate interp angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_affinei_all image interp.value a (-b) b a 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\t(rotate interp) Operator_type.COMPOUND_REWRAP false;\n\ta = cos angle;\n\tb = sin angle;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_lr\")\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin_lr Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert (get_width a) 0 b a;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_tb\")\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin_tb Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert 0 (get_height a) b a;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\t// The [[real]] can contain 128 values ... squeeze them out!\n\timage = im_mask2vips (Matrix m2) == 255;\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\" ++ \": \" ++ \n\t\t\"conv (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvf mask image\n\t= oo_unary_function convf_op image, is_class image\n\t= im_conv_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convf\" ++ \": \" ++ \n\t\t\"convf (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconvf_op = Operator \"convf\" \n\t\t(convf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\naconvsep layers mask image \n\t= oo_unary_function aconvsep_op image, is_class image\n\t= im_aconvsep image (to_matrix mask) (to_real layers), is_image image\n\t= error (_ \"bad arguments to \" ++ \"aconvsep\")\n{\n\taconvsep_op = Operator \"aconvsep\" \n\t\t(aconvsep layers mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsep_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_indexed mode index value\n\t= oo_binary_function hist_find_indexed_op index value, is_class index\n\t= oo_binary'_function hist_find_indexed_op index value, is_class value\n\t= indexed index value, is_image index && is_image value\n\t= error (_ \"bad arguments to \" ++ \"hist_find_indexed\")\n{\n\thist_find_indexed_op = Operator \"hist_find_indexed\" \n\t\t(compose (compose Plot_histogram) (hist_find_indexed mode)) \n\t\t\tOperator_type.COMPOUND false;\n\n\tindexed index value\n\t\t= out\n\t{\n\t\t[out] = vips_call \"hist_find_indexed\" [value, index] [\n\t\t\t\"combine\" => mode\n\t\t];\n\t}\n}\n\nhist_entropy x \n\t= oo_unary_function hist_entropy_op x, is_class x\n\t= entropy x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hist_entropy\")\n{\n\thist_entropy_op = Operator \"hist_entropy\" \n\t\thist_entropy Operator_type.COMPOUND_REWRAP false;\n\n\tentropy x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"hist_entropy\" [x] [\n\t\t];\n\t}\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h \n\t\t= (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h\n\t{\n\t\t// up the format so it can represent the whole range of\n\t\t// possible values from this mask\n\t\tfmt x\n\t\t\t= Image_format.SHORT, \n\t\t\t\tx == Image_format.UCHAR || x == Image_format.CHAR\n\t\t\t= Image_format.INT, \n\t\t\t\tx == Image_format.USHORT || x == Image_format.SHORT ||\n\t\t\t\tx == Image_format.UINT \n\t\t\t= x;\n\t}\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_inv hist \n\t= oo_unary_function hist_inv_op hist, is_class hist\n\t= inv hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_inv\")\n{\n\thist_inv_op = Operator \"hist_inv\" \n\t\thist_inv Operator_type.COMPOUND_REWRAP false;\n\n\tinv im\n\t\t= im_invertlut (to_matrix im''') len\n\t{\n\t\t// need a vertical doublemask\n\t\tim' \n\t\t\t= rot90 im, get_width im > 1 && get_height im == 1 \n\t\t\t= im, get_width im == 1 && get_height im > 1\n\t\t\t= error (_ \"not a hist\");\n\t\tlen = get_height im';\n\n\t\t// values must be scaled to 0 - 1\n\t\tim'' = im' / (max im');\n\t\t\n\t\t// add an index column on the left\n\t\t// again, must be in 0-1\n\t\ty = ((make_xy 1 len)?1) / len;\n\t\tim''' = y ++ im'';\n\t}\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h l image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= out, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h l) Operator_type.COMPOUND_REWRAP false;\n\n\t[out] = vips_call \"hist_local\" \n\t\t[image, to_real w, to_real h] [$max_slope => to_real l];\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nreduce kernel xshr yshr image\n\t= oo_unary_function reduce_op image, is_class image\n\t= reduce_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"reduce\")\n{\n\treduce_op = Operator \"reduce\" \n\t\treduce_im Operator_type.COMPOUND_REWRAP false;\n\n\treduce_im im \n\t\t= out\n\t{\n\t\t[out] = vips_call \"reduce\" [im, xshr, yshr] [$kernel => kernel.value];\n\t}\n}\n\nsimilarity interpolate scale angle image\n\t= oo_unary_function similarity_op image, is_class image\n\t= similarity_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"similarity\")\n{\n\tsimilarity_op = Operator \"similarity\" \n\t\tsimilarity_im Operator_type.COMPOUND_REWRAP false;\n\n\tsimilarity_im im \n\t\t= out\n\t{\n\t\t[out] = vips_call \"similarity\" [im] [\n\t\t\t$interpolate => interpolate.value,\n\t\t\t$scale => scale,\n\t\t\t$angle => angle\n\t\t];\n\t}\n}\n\nresize kernel xfac yfac image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\tis_nn = kernel.type == Kernel_type.NEAREST_NEIGHBOUR;\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn \n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn \n\n\t\t// everything else ... we just pass on to vips_resize()\n\t\t= vips_resize kernel xfac' yfac' im\n\t{\n\t\tvips_resize kernel hscale vscale im \n\t\t\t= out\n\t\t{\n\t\t\t[out] = vips_call \"resize\" [im, hscale] \n\t\t\t\t[$vscale => vscale, $kernel => kernel.value];\n\t\t}\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\n\n// Given a xywh rect, flip it around so wh are always positive\nrect_normalise x y w h \n\t= [x', y', w', h']\n{\n\tx'\n\t\t= x + w, w < 0\n\t\t= x;\n\ty'\n\t\t= y + h, h < 0\n\t\t= y;\n\tw' = abs w;\n\th' = abs h;\n}\n\ndraw_flood_blob x y ink image\n\t= oo_unary_function draw_flood_blob_op image, is_class image\n\t= im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood_blob\")\n{\n\tdraw_flood_blob_op = Operator \"draw_flood_blob\" \n\t\t(draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_flood x y ink image\n\t= oo_unary_function draw_flood_op image, is_class image\n\t= im_draw_flood image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood\")\n{\n\tdraw_flood_op = Operator \"draw_flood\" \n\t\t(draw_flood x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* This version of draw_rect uses insert_noexpand and will be fast, even for\n * huge images.\n */\ndraw_rect_width x y w h f t ink image\n\t= oo_unary_function draw_rect_width_op image, is_class image\n\t= my_draw_rect_width image (to_int x) (to_int y) \n\t\t(to_int w) (to_int h) (to_int f) (to_int t) ink, \n\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_width\")\n{\n\tdraw_rect_width_op = Operator \"draw_rect_width\" \n\t\t(draw_rect_width x y w h f t ink) \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\tmy_draw_rect_width image x y w h f t ink\n\t\t= insert x' y' (block w' h') image, f == 1\n\t\t= (insert x' y' (block w' t) @ \n\t\t\tinsert (x' + w' - t) y' (block t h') @ \n\t\t\tinsert x' (y' + h' - t) (block w' t) @ \n\t\t\tinsert x' y' (block t h')) image\n\t{\n\t\tinsert = insert_noexpand;\n\t\tblock w h = image_new w h (get_bands image) (get_format image)\n\t\t\t(get_coding image) (get_type image) ink' 0 0;\n\t\tink' \n\t\t\t= Vector ink, is_list ink\n\t\t\t= ink;\n\t\t[x', y', w', h'] = rect_normalise x y w h;\n\t}\n}\n\n/* Default to 1 pixel wide edges.\n */\ndraw_rect x y w h f ink image\n\t= draw_rect_width x y w h f 1 ink image;\n\n/* This version of draw_rect uses the paintbox rect draw operation. It is an\n * inplace operation and will use bucketloads of memory.\n */\ndraw_rect_paintbox x y w h f ink image\n\t= oo_unary_function draw_rect_op image, is_class image\n\t= im_draw_rect image (to_real x) (to_real y) \n\t\t(to_real w) (to_real h) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_paintbox\")\n{\n\tdraw_rect_op = Operator \"draw_rect\" \n\t\t(draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_circle x y r f ink image\n\t= oo_unary_function draw_circle_op image, is_class image\n\t= im_draw_circle image (to_real x) (to_real y) \n\t\t(to_real r) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_circle\")\n{\n\tdraw_circle_op = Operator \"draw_circle\" \n\t\t(draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_line x1 y1 x2 y2 ink image\n\t= oo_unary_function draw_line_op image, is_class image\n\t= im_draw_line image (to_real x1) (to_real y1) \n\t\t(to_real x2) (to_real y2) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_line\")\n{\n\tdraw_line_op = Operator \"draw_line\" \n\t\t(draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (\\x x % base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (\\x idivide x base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= NULL, any (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n/* Linear regression. Return a class with the stuff we need in.\n * from s15.2, p 665 NR in C\n * \n * Also calculate R2, see eg.:\n * https://en.wikipedia.org/wiki/Coefficient_of_determination \n */\nlinreg xes yes\n    = obj\n{\n    obj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [t * y :: [t, y] <- zip2 tes yes] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes];\n\n\t\tsiga = (chi2 / (ss - 2)) ** 0.5 *\n\t\t\t((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5;\n\n\t\t// for compat with linregw, see below\n\t\tq = 1.0;\n\n\t\tR2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes];\n\t}\n\n\tss = len xes;\n\tsx = sum xes;\n\tsy = sum yes;\n\tmy = sy / ss;\n\tsxoss = sx / ss;\n\n\ttes = [x - sxoss :: x <- xes];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Weighted linear regression. Xes, yes and a list of deviations.\n */\nlinregw xes yes devs \n\t= obj\n{\n\tobj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: \n\t\t\t[x, y, sd] <- zip3 xes yes devs];\n\n\t\tsiga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (1 / st2) ** 0.5;\n\n\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\n\t\tR2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes];\n\t}\n\n\twt = [sd ** -0.5 :: sd <- devs];\n\n\tss = sum wt;\n\tsx = sum [x * w :: [x, w] <- zip2 xes wt];\n\tsy = sum [y * w :: [y, w] <- zip2 yes wt];\n\tmy = sy / len xes;\n\tsxoss = sx / ss;\n\n\ttes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Clustering: pass in a list of points, repeatedly merge the\n * closest two points until no two points are closer than the threshold.\n * Return [merged-points, corresponding-weights]. A weight is a list of the\n * indexes we merged to make that point, ie. len weight == how significant\n * this point is.\n *\n * eg. \n *\tcluster 12 [152,154,155,42,159] == \n *\t\t[[155,42],[[1,2,0,4],[3]]]\n */\ncluster thresh points\n\t= oo_unary_function cluster_op points, is_class points\n\t// can't use [0..len points - 1], in case len points == 0\n\t= merge [points, map (converse cons []) (take (len points) [0 ..])],\n\t\tis_list points\n\t= error (_ \"bad arguments to \" ++ \"cluster\")\n{\n\tcluster_op = Operator \"cluster\" \n\t\t(cluster thresh) Operator_type.COMPOUND false;\n\n\tmerge x\n\t\t= x, m < 2 || d > thresh\n\t\t= merge [points', weights']\n\t{\n\t\t[points, weights] = x;\n\t\tm = len points;\n\n\t\t// generate indexes of all possible pairs, avoiding comparing a thing \n\t\t// to itself, and assuming that dist is reflexive\n\t\t// first index is always less than 2nd index\n\t\t// the +1,+2 makes sure we have an increasing generator, otherwise we\n\t\t// can get [3 .. 4] (for example), which will make a decreasing\n\t\t// sequence\n\t\tpairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]];\n\n\t\t// distance function\n\t\t// arg is eg. [3,1], meaning get distance from point 3 to point 1\n\t\tdist x \n\t\t\t= abs (points?i - points?j)\n\t\t{\n\t\t\t[i, j] = x;\n\t\t}\n\n\t\t// smallest distance, then the two points we merge\n\t\tp = minpos (map dist pairs);\n\t\td = dist pairs?p;\n\t\t[i, j] = pairs?p;\n\n\t\t// new point and new weight\n\t\tnw = weights?i ++ weights?j;\n\t\tnp = (points?i * len weights?i + points?j * len weights?j) / len nw;\n\n\t\t// remove element i from a list\n\t\tremove i l = take i l ++ drop (i + 1) l;\n\n\t\t// remove two old points, add the new merged one\n\t\t// i < j (see \"pairs\", above)\n\t\tpoints' = np : remove i (remove j points);\n\t\tweights' = nw : remove i (remove j weights);\n\t}\n}\n\n/* Extract the area of an image around an arrow.\n * Transform the image to make the arrow horizontal, then displace by hd and\n * vd pxels, then cut out a bit h pixels high centered on the arrow.\n */\nextract_arrow hd vd h arrow\n\t= extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im'\n{\n\t// the line as a polar vector\n\tpv = polar (arrow.width, arrow.height);\n\ta = im pv;\n\n\t// smallest rotation that will make the line horizontal\n\ta'\n\t\t= 360 - a, a > 270\n\t\t= 180 - a, a > 90\n\t\t= -a;\n\n\tim' = rotate Interpolate_bilinear a' arrow.image;\n\n\t// look at the start and end of the arrow, pick the leftmost\n\tp\n\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t= (arrow.right, arrow.bottom);\n\n\t// transform that point to im' space\n\tp' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset);\n}\n\n/* You'd think these would go in _convert, but they are not really colour ops,\n * so put them here.\n */\nrad2float image\n\t= oo_unary_function rad2float_op image, is_class image\n\t= im_rad2float image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"rad2float\")\n{\n\trad2float_op = Operator \"rad2float\" \n\t\trad2float Operator_type.COMPOUND_REWRAP false;\n}\n\nfloat2rad image\n\t= oo_unary_function float2rad_op image, is_class image\n\t= im_float2rad image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"float2rad\")\n{\n\tfloat2rad_op = Operator \"float2rad\" \n\t\tfloat2rad Operator_type.COMPOUND_REWRAP false;\n}\n\nsegment x\n\t= oo_unary_function segment_op x, is_class x\n\t= image', is_image x \n\t= error (_ \"bad arguments to \" ++ \"segment\")\n{\n\tsegment_op = Operator \"segment\" \n\t\tsegment Operator_type.COMPOUND_REWRAP false;\n\n\t[image, nsegs] = im_segment x;\n\timage' = im_copy_set_meta image \"n-segments\" nsegs;\n}\n\npoint a b\n\t= oo_binary_function point_op a b, is_class a\n\t= oo_binary'_function point_op a b, is_class b\n\t= im_read_point b x y, is_image b\n\t= [b?x?y], is_matrix b\n\t= [b?x], is_real_list b && y == 0\n\t= [b?y], is_real_list b && x == 0\n\t= error (_ \"bad arguments to \" ++ \"point\")\n{\n\tpoint_op = Operator \"point\" \n\t\t(\\a\\b Vector (point a b)) Operator_type.COMPOUND false;\n\n\t(x, y) \n\t\t= a, is_complex a;\n\t\t= (a?0, a?1), is_real_list a && is_list_len 2 a\n\t\t= error \"bad position format\";\n}\n\n/* One image in, one out. \n */\nsystem_image command x\n\t= oo_unary_function system_image_op x, is_class x\n\t= system x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"system_image\")\n{\n\tsystem_image_op = Operator \"system_image\" \n\t\t(system_image command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem im\n\t\t= image_out\n\t{\n\t\t[image_out, log] = \n\t\t\tim_system_image (get_image im) \"%s.tif\" \"%s.tif\" command;\n\t}\n}\n\n/* Two images in, one out. \n */\nsystem_image2 command x1 x2\n\t= oo_binary_function system_image2_op x1 x2, is_class x1\n\t= oo_binary'_function system_image2_op x1 x2, is_class x2\n\t= system x1 x2, is_image x1 && is_image x2\n\t= error (_ \"bad arguments to \" ++ \"system_image2\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image2 command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Three images in, one out. \n */\nsystem_image3 command x1 x2 x3\n\t= oo_binary_function system_image2_op x2 x3, is_class x2\n\t= oo_binary'_function system_image2_op x2 x3, is_class x3\n\t= system x1 x2 x3, is_image x1 && is_image x2 && is_image x3\n\t= error (_ \"bad arguments to \" ++ \"system_image3\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image3 command x1) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2 x3\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2, x3], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Zero images in, one out. \n */\nsystem_image0 command \n\t= Image image_out\n{\n\t[image_out] = vips_call \"system\" [command] [\n\t\t$out => true,\n\t\t$out_format => \"%s.tif\" \n\t];\n}\n\nhough_line w h x \n\t= oo_unary_function hough_line_op x, is_class x\n\t= hline (to_real w) (to_real h) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_line\")\n{\n\though_line_op = Operator \"hough_line\" \n\t\t(hough_line w h) Operator_type.COMPOUND_REWRAP false;\n\n\thline w h x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_line\" [x] [\n\t\t\t$width => w, \n\t\t\t$height => h\n\t\t];\n\t}\n}\n\nhough_circle s mn mx x \n\t= oo_unary_function hough_circle_op x, is_class x\n\t= hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_circle\")\n{\n\though_circle_op = Operator \"hough_circle\" \n\t\t(hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false;\n\n\thcircle s mn mx x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_circle\" [x] [\n\t\t\t$scale => s, \n\t\t\t$min_radius => mn, \n\t\t\t$max_radius => mx\n\t\t];\n\t}\n}\n\nmapim interp ind in\n\t= oo_binary_function mapim_op ind in, is_class ind\n\t= oo_binary'_function mapim_op ind in, is_class in\n\t= mapim_fn ind in, is_image ind && is_image in\n\t= error (_ \"bad arguments to \" ++ \"mapim\")\n{\n\tmapim_op = Operator \"mapim\" \n\t\t(mapim interp) Operator_type.COMPOUND_REWRAP false;\n\n\tmapim_fn ind im\n\t\t= out\n\t{\n\t\t[out] = vips_call \"mapim\" [im, ind] [$interpolate => interp];\n\t}\n}\n\nperlin cell width height\n\t= Image im\n{\n\t[im] = vips_call \"perlin\" [to_real width, to_real height] [\n\t\t$cell_size => to_real cell \n\t];\n}\n\nworley cell width height\n\t= Image im\n{\n\t[im] = vips_call \"worley\" [to_real width, to_real height] [\n\t\t$cell_size => to_real cell \n\t];\n}\n\ngaussnoise width height mean sigma\n\t= im\n{\n\t[im] = vips_call \"gaussnoise\" [to_real width, to_real height] [\n\t\t$mean => to_real mean,\n\t\t$sigma => to_real sigma\n\t];\n}\n\nflattenimage bg x \n\t= oo_unary_function flatten_op x, is_class x\n\t= flt (to_vector bg) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"flattenimage\")\n{\n\tflatten_op = Operator \"flatten\" \n\t\t(flattenimage bg) Operator_type.COMPOUND_REWRAP false;\n\n\tflt bg x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"flatten\" [x] [\n\t\t\t$background => bg.value \n\t\t];\n\t}\n}\n\npremultiply x \n\t= oo_unary_function premultiply_op x, is_class x\n\t= prem x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"premultiply\")\n{\n\tpremultiply_op = Operator \"premultiply\" \n\t\tpremultiply Operator_type.COMPOUND_REWRAP false;\n\n\tprem x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"premultiply\" [x] [\n\t\t];\n\t}\n}\n\nunpremultiply x \n\t= oo_unary_function unpremultiply_op x, is_class x\n\t= unprem x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"unpremultiply\")\n{\n\tunpremultiply_op = Operator \"unpremultiply\" \n\t\tunpremultiply Operator_type.COMPOUND_REWRAP false;\n\n\tunprem x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"unpremultiply\" [x] [\n\t\t];\n\t}\n}\n\nhist_entropy x \n\t= oo_unary_function hist_entropy_op x, is_class x\n\t= entropy x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hist_entropy\")\n{\n\thist_entropy_op = Operator \"hist_entropy\" \n\t\thist_entropy Operator_type.COMPOUND_REWRAP false;\n\n\tentropy x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"hist_entropy\" [x] [\n\t\t];\n\t}\n}\n"
  },
  {
    "path": "share/nip2/compat/8.6/_types.def",
    "content": "/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary (\\a op.fn a x) this,\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// we can't call map_trinary directly, since it uses Group and we\n\t// don't support mutually recursive top-level functions :-(\n\t// copy-paste it here, keep in sync with the version in _stdenv\n\tmap_nary fn args\n\t\t= fn args, groups == []\n\t\t= Group (map process [0, 1 .. shortest - 1])\n\t{\n\t\tgroups = filter is_Group args;\n\t\n\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\tprocess n\n\t\t\t= NULL, any (map (is_noval n) args)\n\t\t\t= map_nary fn (map (extract n) args)\n\t\t{\n\t\t\textract n arg\n\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t= arg;\n\t\n\t\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t\t}\n\t}\n\n\t// need ite as a true trinary\n\tite a b c = if a then b else c;\n\n\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t];\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\n\t\t[op.fn this.value x,\n\t\t\top.type == Operator_type.COMPOUND]\n\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[is_list_len 3 value, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.item colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum \"Colour space\" Image_type.colour_spaces default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\n/* An option whose value is a string rather than a number.\n */\nOption_string caption labels item = class\n\tOption caption labels (index (equal item) labels) {\n\tOption_edit caption labels value \n\t\t= this.Option_string caption labels (labels?value);\n}\n\n/* Make an option from an enum.\n */\nOption_enum caption enum item = class\n\tOption_string caption enum.names item {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing item;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum caption enum (enum.names?value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNONE = 0;\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNONE = 0;\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n\tRAD = 6;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* Extract a column.\n\t */\n\tcolumn n = map (extract n) value;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (column col) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (column from);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = this.column 0; \n\tthings = this.column 1; \n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tHISTOGRAM = 10;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tARRAY = 27;\n\tscRGB = 28;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t$MULTIBAND => MULTIBAND,\n\t\t$B_W => B_W,\n\t\t$HISTOGRAM => HISTOGRAM,\n\t\t$XYZ => XYZ,\n\t\t$LAB => LAB,\n\t\t$CMYK => CMYK,\n\t\t$LABQ => LABQ,\n\t\t$RGB => RGB,\n\t\t$UCS => UCS,\n\t\t$LCH => LCH,\n\t\t$LABS => LABS,\n\t\t$sRGB => sRGB,\n\t\t$YXY => YXY,\n\t\t$FOURIER => FOURIER,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$ARRAY => ARRAY,\n\t\t$scRGB => scRGB\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options are generated from this, so match the order to the order in \n\t * the Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t$sRGB => sRGB,\n\t\t$scRGB => scRGB,\n\t\t$Lab => LAB,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t$Mono => B_W,\n\t\t$sRGB => sRGB,\n\t\t$scRGB => scRGB,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$Lab => LAB,\n\t\t$LabQ => LABQ,\n\t\t$LabS => LABS,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \n\t\t// \"Image v == 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\t// if one of then/else is an image, get the target format from that\n\t\t// otherwise, let the non-image objects set the target\n\t\ttarget_format \n\t\t\t= get_member_list has_format get_format x, \n\t\t\t\thas_member_list has_format x\n\t\t\t= NULL;\n\n\t\tto_image x = to_image_size width height target_bands target_format x;\n\n\t\t[then', else'] = map to_image x;\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if value then then' else else');\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nKernel_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tLINEAR = 1;\n\tCUBIC = 2;\n\tLANCZOS2 = 3;\n\tLANCZOS3 = 4;\n\n\t// Should introspect to get the list of interpolators :-(\n\t// We can \"dir\" on VipsInterpolate to get a list of them, but we\n\t// can't get i18n'd descriptions until we have more\n\t// introspection stuff in nip2.\n\n\t/* Table to map kernel numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Linear\", \n\t\t_ \"Cubic\",\n\t\t_ \"Lanczos, two lobes\",\n\t\t_ \"Lanczos, three lobes\"\n\t];\n\n\t/* And to vips enum nicknames.\n\t */\n\ttypes = [\n\t\t\"nearest\", \n\t\t\"linear\", \n\t\t\"cubic\", \n\t\t\"lanczos2\", \n\t\t\"lanczos3\"\n\t];\n}\n\nKernel type = class {\n\tvalue = Kernel_type.types?type;\n}\n\nKernel_linear = Kernel Kernel_type.LINEAR;\n\nKernel_picker default = class \n\tKernel kernel.value {\n\t_vislevel = 2;\n\n\tkernel = Option \"Kernel\" Kernel_type.descriptions default;\n}\n\nInterpolate_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\tLBB = 3;\n\tNOHALO = 4;\n\tVSQBS = 5;\n\n\t// Should introspect to get the list of interpolators :-(\n\t// We can \"dir\" on VipsInterpolate to get a list of them, but we\n\t// can't get i18n'd descriptions until we have more\n\t// introspection stuff in nip2.\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Bilinear\", \n\t\t_ \"Bicubic\",\n\t\t_ \"Upsize: reduced halo bicubic (LBB)\",\n\t\t_ \"Upsharp: reduced halo bicubic with edge sharpening (Nohalo)\",\n\t\t_ \"Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)\"\n\t];\n\n\t/* And to vips type names.\n\t */\n\ttypes = [\n\t\t\"VipsInterpolateNearest\",\n\t\t\"VipsInterpolateBilinear\",\n\t\t\"VipsInterpolateBicubic\",\n\t\t\"VipsInterpolateLbb\",\n\t\t\"VipsInterpolateNohalo\",\n\t\t\"VipsInterpolateVsqbs\"\n\t];\n}\n\nInterpolate type options = class {\n\tvalue = vips_object_new Interpolate_type.types?type [] options;\n}\n\nInterpolate_bilinear = Interpolate Interpolate_type.BILINEAR [];\n\nInterpolate_picker default = class \n\tInterpolate interp.value [] {\n\t_vislevel = 2;\n\n\tinterp = Option \"Interpolation\" Interpolate_type.descriptions default;\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t_ \"Perceptual\" => PERCEPTUAL,\n\t\t_ \"Relative\" => RELATIVE,\n\t\t_ \"Saturation\" => SATURATION,\n\t\t_ \"Absolute\" => ABSOLUTE\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t_ \"Point\" => POINT,\n\t\t_ \"Line\" => LINE,\n\t\t_ \"Spline\" => SPLINE,\n\t\t_ \"Bar\" => BAR\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t_ \"YYYY\" => YYYY,\n\t\t_ \"XYYY\" => XYXY,\n\t\t_ \"XYXY\" => XYXY\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n\tto_image dpi = extract_bands 0 3 \n\t\t(graph_export_image (to_real dpi) this);\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [$format => Plot_format.XYYY] value {\n}\n\n/* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate\n * empty slots, for example.\n */\nNULL = class \n\t_Object {\n\too_binary_table op x = [\n\t\t// the only operation we allow is equality .. use pointer equality,\n\t\t// this lets us test a == NULL and a != NULL\n\t\t[this === x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"equal\"],\n\t\t[this !== x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"not_equal\"]\n\t] ++ super.oo_binary_table op x;\n}\n\nBlend_type = class {\n\tCLEAR = 0;\n\tSOURCE = 1;\n\tOVER = 2;\n\tIN = 3;\n\tOUT = 4;\n\tATOP = 5;\n\tDEST = 6;\n\tDEST_OVER = 7;\n\tDEST_IN = 8;\n\tDEST_OUT = 9;\n\tDEST_ATOP = 10;\n\tXOR = 11;\n\tADD = 12;\n\tSATURATE = 13;\n\tMULTIPLY = 14;\n\tSCREEN = 15;\n\tOVERLAY = 16;\n\tDARKEN = 17;\n\tLIGHTEN = 18;\n\tCOLOUR_DODGE = 19;\n\tCOLOUR_BURN = 20;\n\tHARD_LIGHT = 21;\n\tSOFT_LIGHT = 22;\n\tDIFFERENCE = 23;\n\tEXCLUSION = 24;\n\n\t/* Table to map blend numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Clear\",\n\t\t_ \"Source\",\n\t\t_ \"Over\",\n\t\t_ \"In\",\n\t\t_ \"Out\",\n\t\t_ \"Atop\",\n\t\t_ \"Dest\",\n\t\t_ \"Dest over\",\n\t\t_ \"Dest in\",\n\t\t_ \"Dest out\",\n\t\t_ \"Dest atop\",\n\t\t_ \"Xor\",\n\t\t_ \"Add\",\n\t\t_ \"Saturate\",\n\t\t_ \"Multiply\",\n\t\t_ \"Screen\",\n\t\t_ \"Overlay\",\n\t\t_ \"Darken\",\n\t\t_ \"Lighten\",\n\t\t_ \"Colour dodge\",\n\t\t_ \"Colour burn\",\n\t\t_ \"Hard light\",\n\t\t_ \"Soft light\",\n\t\t_ \"Difference\",\n\t\t_ \"Exclusion\"\n\t];\n\n\t/* And to vips enum nicknames.\n\t */\n\ttypes = Enum [\n\t\t$clear => \"clear\",\n\t\t$source => \"source\",\n\t\t$over => \"over\",\n\t\t$in => \"in\",\n\t\t$out => \"out\",\n\t\t$atop => \"atop\",\n\t\t$dest => \"dest\",\n\t\t$dest_over => \"dest_over\",\n\t\t$dest_in => \"dest_in\",\n\t\t$dest_out => \"dest_out\",\n\t\t$dest_atop => \"dest_atop\",\n\t\t$xor => \"xor\",\n\t\t$add => \"add\",\n\t\t$saturate => \"saturate\",\n\t\t$multiply => \"multiply\",\n\t\t$screen => \"screen\",\n\t\t$overlay => \"overlay\",\n\t\t$darken => \"darken\",\n\t\t$lighten => \"lighten\",\n\t\t$colour_dodge => \"colour_dodge\",\n\t\t$colour_burn => \"colour_burn\",\n\t\t$hard_light => \"hard_light\",\n\t\t$soft_light => \"soft_light\",\n\t\t$difference => \"difference\",\n\t\t$exclusion => \"exclusion\"\n\t];\n}\n\nBlend type = class {\n\tvalue = Blend_type.types?type;\n}\n\nBlend_over = Blend Blend_type.OVER;\n\nBlend_picker default = class \n\tBlend blend.value {\n\t_vislevel = 2;\n\n\tblend = Option \"Blend\" Blend_type.descriptions default;\n}\n\nCombine_type = class {\n\tMAX = 0;\n\tSUM = 1;\n\tMIN = 2;\n\n\tenum = Enum [\n\t\t_ \"Maximum\" => MAX,\n\t\t_ \"Sum\" => SUM,\n\t\t_ \"Minimum\" => MIN\n\t];\n}\n\nCombine type = class {\n\tvalue = Combine_type.enum.names?type;\n}\n\nCombine_sum = Combine Combine_type.SUM;\n\nCombine_picker default = Option \"Combine\" Combine_type.enum.names default;\n"
  },
  {
    "path": "share/nip2/compat/Makefile.am",
    "content": "SUBDIRS = 7.8 7.9 7.10 7.12 7.14 7.16 7.24 7.26 7.28 7.38 7.40 8.2 8.3 \\\n\t  8.4 8.5 8.6\n"
  },
  {
    "path": "share/nip2/compat/_compat.def",
    "content": "// compatibility with nip-7.8\n\n_colour_conv2 from to = _colour_conv to @ _colour_set from;\n\nMono_to = class {\n\tMono x = _colour_conv2 Image_type.B_W Image_type.B_W x;\n\tXYZ x = _colour_conv2 Image_type.B_W Image_type.XYZ x;\n\tYxy x = _colour_conv2 Image_type.B_W Image_type.YXY x;\n\tLab x = _colour_conv2 Image_type.B_W Image_type.LAB x;\n\tLCh x = _colour_conv2 Image_type.B_W Image_type.LCH x;\n\tUCS x = _colour_conv2 Image_type.B_W Image_type.UCS x;\n\tRGB x = _colour_conv2 Image_type.B_W Image_type.RGB x;\n\tsRGB x = _colour_conv2 Image_type.B_W Image_type.sRGB x;\n\tLabQ x = _colour_conv2 Image_type.B_W Image_type.LABQ x;\n\tLabS x = _colour_conv2 Image_type.B_W Image_type.LABS x;\n}\n\nXYZ_to = class {\n\tMono x = _colour_conv2 Image_type.XYZ Image_type.B_W x;\n\tXYZ x = _colour_conv2 Image_type.XYZ Image_type.XYZ x;\n\tYxy x = _colour_conv2 Image_type.XYZ Image_type.YXY x;\n\tLab x = _colour_conv2 Image_type.XYZ Image_type.LAB x;\n\tLCh x = _colour_conv2 Image_type.XYZ Image_type.LCH x;\n\tUCS x = _colour_conv2 Image_type.XYZ Image_type.UCS x;\n\tRGB x = _colour_conv2 Image_type.XYZ Image_type.RGB x;\n\tsRGB x = _colour_conv2 Image_type.XYZ Image_type.sRGB x;\n\tLabQ x = _colour_conv2 Image_type.XYZ Image_type.LABQ x;\n\tLabS x = _colour_conv2 Image_type.XYZ Image_type.LABS x;\n}\n\nYxy_to = class {\n\tMono x = _colour_conv2 Image_type.YXY Image_type.B_W x;\n\tXYZ x = _colour_conv2 Image_type.YXY Image_type.XYZ x;\n\tYxy x = _colour_conv2 Image_type.YXY Image_type.YXY x;\n\tLab x = _colour_conv2 Image_type.YXY Image_type.LAB x;\n\tLCh x = _colour_conv2 Image_type.YXY Image_type.LCH x;\n\tUCS x = _colour_conv2 Image_type.YXY Image_type.UCS x;\n\tRGB x = _colour_conv2 Image_type.YXY Image_type.RGB x;\n\tsRGB x = _colour_conv2 Image_type.YXY Image_type.sRGB x;\n\tLabQ x = _colour_conv2 Image_type.YXY Image_type.LABQ x;\n\tLabS x = _colour_conv2 Image_type.YXY Image_type.LABS x;\n}\n\nLab_to = class {\n\tMono x = _colour_conv2 Image_type.LAB Image_type.B_W x;\n\tXYZ x = _colour_conv2 Image_type.LAB Image_type.XYZ x;\n\tYxy x = _colour_conv2 Image_type.LAB Image_type.YXY x;\n\tLab x = _colour_conv2 Image_type.LAB Image_type.LAB x;\n\tLCh x = _colour_conv2 Image_type.LAB Image_type.LCH x;\n\tUCS x = _colour_conv2 Image_type.LAB Image_type.UCS x;\n\tRGB x = _colour_conv2 Image_type.LAB Image_type.RGB x;\n\tsRGB x = _colour_conv2 Image_type.LAB Image_type.sRGB x;\n\tLabQ x = _colour_conv2 Image_type.LAB Image_type.LABQ x;\n\tLabS x = _colour_conv2 Image_type.LAB Image_type.LABS x;\n}\n\nLCh_to = class {\n\tMono x = _colour_conv2 Image_type.LCH Image_type.B_W x;\n\tXYZ x = _colour_conv2 Image_type.LCH Image_type.XYZ x;\n\tYxy x = _colour_conv2 Image_type.LCH Image_type.YXY x;\n\tLab x = _colour_conv2 Image_type.LCH Image_type.LAB x;\n\tLCh x = _colour_conv2 Image_type.LCH Image_type.LCH x;\n\tUCS x = _colour_conv2 Image_type.LCH Image_type.UCS x;\n\tRGB x = _colour_conv2 Image_type.LCH Image_type.RGB x;\n\tsRGB x = _colour_conv2 Image_type.LCH Image_type.sRGB x;\n\tLabQ x = _colour_conv2 Image_type.LCH Image_type.LABQ x;\n\tLabS x = _colour_conv2 Image_type.LCH Image_type.LABS x;\n}\n\nUCS_to = class {\n\tMono x = _colour_conv2 Image_type.UCS Image_type.B_W x;\n\tXYZ x = _colour_conv2 Image_type.UCS Image_type.XYZ x;\n\tYxy x = _colour_conv2 Image_type.UCS Image_type.YXY x;\n\tLab x = _colour_conv2 Image_type.UCS Image_type.LAB x;\n\tLCh x = _colour_conv2 Image_type.UCS Image_type.LCH x;\n\tUCS x = _colour_conv2 Image_type.UCS Image_type.UCS x;\n\tRGB x = _colour_conv2 Image_type.UCS Image_type.RGB x;\n\tsRGB x = _colour_conv2 Image_type.UCS Image_type.sRGB x;\n\tLabQ x = _colour_conv2 Image_type.UCS Image_type.LABQ x;\n\tLabS x = _colour_conv2 Image_type.UCS Image_type.LABS x;\n}\n\nRGB_to = class {\n\tMono x = _colour_conv2 Image_type.RGB Image_type.B_W x;\n\tXYZ x = _colour_conv2 Image_type.RGB Image_type.XYZ x;\n\tYxy x = _colour_conv2 Image_type.RGB Image_type.YXY x;\n\tLab x = _colour_conv2 Image_type.RGB Image_type.LAB x;\n\tLCh x = _colour_conv2 Image_type.RGB Image_type.LCH x;\n\tUCS x = _colour_conv2 Image_type.RGB Image_type.UCS x;\n\tRGB x = _colour_conv2 Image_type.RGB Image_type.RGB x;\n\tsRGB x = _colour_conv2 Image_type.RGB Image_type.sRGB x;\n\tLabQ x = _colour_conv2 Image_type.RGB Image_type.LABQ x;\n\tLabS x = _colour_conv2 Image_type.RGB Image_type.LABS x;\n}\n\nsRGB_to = class {\n\tMono x = _colour_conv2 Image_type.sRGB Image_type.B_W x;\n\tXYZ x = _colour_conv2 Image_type.sRGB Image_type.XYZ x;\n\tYxy x = _colour_conv2 Image_type.sRGB Image_type.YXY x;\n\tLab x = _colour_conv2 Image_type.sRGB Image_type.LAB x;\n\tLCh x = _colour_conv2 Image_type.sRGB Image_type.LCH x;\n\tUCS x = _colour_conv2 Image_type.sRGB Image_type.UCS x;\n\tRGB x = _colour_conv2 Image_type.sRGB Image_type.RGB x;\n\tsRGB x = _colour_conv2 Image_type.sRGB Image_type.sRGB x;\n\tLabQ x = _colour_conv2 Image_type.sRGB Image_type.LABQ x;\n\tLabS x = _colour_conv2 Image_type.sRGB Image_type.LABS x;\n}\n\nLabQ_to = class {\n\tMono x = _colour_conv2 Image_type.LABQ Image_type.B_W x;\n\tXYZ x = _colour_conv2 Image_type.LABQ Image_type.XYZ x;\n\tYxy x = _colour_conv2 Image_type.LABQ Image_type.YXY x;\n\tLab x = _colour_conv2 Image_type.LABQ Image_type.LAB x;\n\tLCh x = _colour_conv2 Image_type.LABQ Image_type.LCH x;\n\tUCS x = _colour_conv2 Image_type.LABQ Image_type.UCS x;\n\tRGB x = _colour_conv2 Image_type.LABQ Image_type.RGB x;\n\tsRGB x = _colour_conv2 Image_type.LABQ Image_type.sRGB x;\n\tLabQ x = _colour_conv2 Image_type.LABQ Image_type.LABQ x;\n\tLabS x = _colour_conv2 Image_type.LABQ Image_type.LABS x;\n}\n\nLabS_to = class {\n\tMono x = _colour_conv2 Image_type.LABS Image_type.B_W x;\n\tXYZ x = _colour_conv2 Image_type.LABS Image_type.XYZ x;\n\tYxy x = _colour_conv2 Image_type.LABS Image_type.YXY x;\n\tLab x = _colour_conv2 Image_type.LABS Image_type.LAB x;\n\tLCh x = _colour_conv2 Image_type.LABS Image_type.LCH x;\n\tUCS x = _colour_conv2 Image_type.LABS Image_type.UCS x;\n\tRGB x = _colour_conv2 Image_type.LABS Image_type.RGB x;\n\tsRGB x = _colour_conv2 Image_type.LABS Image_type.sRGB x;\n\tLabQ x = _colour_conv2 Image_type.LABS Image_type.LABQ x;\n\tLabS x = _colour_conv2 Image_type.LABS Image_type.LABS x;\n}\n\n// various renames\nTint_mono_image = Tint_image;\nMatrix_from_colour_chart = Colour_chart_to_matrix;\nColour_chart_from_matrix = Matrix_to_colour_chart;\nColour_from_image = Image_to_colour;\nImage_from_colour = Colour_to_image;\nConvert_format_to = Convert_numeric_format_to;\n\nInsert a b = Insert_image b a;\n\n/* make a colour overlay of two mono images\n */\nOverlay a b = class \n\tImage value {\n\t_check_args = [\n\t\t[a, \"a\", check_Image],\n\t\t[b, \"b\", check_Image]\n\t];\n\t_check_all = [\n\t\t[a.bands == 1 && b.bands == 1,\n\t\t\t\"a.bands == 1 && b.bands == 1\"]\n\t];\n\t_vislevel = 3;\n\n\tap1 = Point_relative a 0.5 0.25;\n\tbp1 = Point_relative b 0.5 0.25;\n\tap2 = Point_relative a 0.5 0.75;\n\tbp2 = Point_relative b 0.5 0.75;\n\n\trefine = Toggle \"Refine selected tie-points\" false;\n\tlock = Toggle \"No resize\" false;\n\tcolour = Option \"Colour overlay as\" [\n\t\t\"Green over Red\",\n\t\t\"Blue over Red\",\n\t\t\"Red over Green\",\n\t\t\"Red over Blue\",\n\t\t\"Blue over Green\",\n\t\t\"Green over Blue\"\n\t] 0;\n\n\tvalue\n\t\t= [(a' ++ b''' ++ black), \n\t\t\t(a' ++ black ++ b'''), \n\t\t\t(b''' ++ a' ++ black), \n\t\t\t(b''' ++ black ++ a'), \n\t\t\t(black ++ a' ++ b'''), \n\t\t\t(black ++ b''' ++ a')]?colour\n\t{\n\t\t_prefs = Workspaces.Preferences;\n\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\ta' = a.value;\n\t\tb' = b.value;\n\n\t\tb'' = clip2fmt a.format b';\n\n\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t// distance along the vector joining p1 and p2\n\t\tnorm p1 p2\n\t\t\t= Rect left' top' 0 0, lock\n\t\t\t= p2\n\t\t{\n\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t// 100000 to give precision since we pass points as\n\t\t\t// ints to match\n\t\t\tn = 100000 * sign v;\n\t\t\tleft' = p1.left + re n;\n\t\t\ttop' = p1.top + im n;\n\t\t}\n\n\t\tap2'' = norm ap1 ap2;\n\t\tbp2'' = norm bp1 bp2;\n\n\t\tb''' \n\t\t\t= im_match_linear_search a' b''\n\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\tobject window,\n\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\trefine && !lock\n\t\t\t= im_match_linear a' b''\n\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\n\t\tblack = image_new a.width a.height \n\t\t\ta.bands a.format a.coding a.type \n\t\t\t0 0 0;\n\t}\n}\n\n\n/* apply a colour to an image\n */\nTint_image in = class \n\t_result {\n\t_vislevel = 3;\n\n\ttint = Colour \"Lab\" [50, 0, 0];\n\ttype = Option \"Tint type\" [\"Colour filter\", \"Colour replacement\"] 1;\n\n\t_result \n\t\t= map_unary apply_tint in\n\t{\n\t\tapply_tint in\n\t\t\t= result, type == 0\n\t\t\t= fancy_result\n\t\t{\n\t\t\t// input image ... to L only\n\t\t\tin_lab = colour_transform_to Image_type.LAB in;\n\t\t\tin_l = in_lab?0;\n\n\t\t\t// make sure tint is LAB (might have been edited)\n\t\t\ttint_lab = colour_transform_to Image_type.LAB tint;\n\n\t\t\t// selected lab\n\t\t\ttint_l = tint_lab.value?0;\n\t\t\ttint_a = tint_lab.value?1;\n\t\t\ttint_b = tint_lab.value?2;\n\n\t\t\t// how much tint to apply .. maximum tint where image\n\t\t\t// L is equal to tint L, angle towards 0 tint up to\n\t\t\t// white and down to black\n\t\t\tmod \n\t\t\t\t= (100 - in_l) / (100 - tint_l), in_l > tint_l\n\t\t\t\t= in_l / tint_l;\n\n\t\t\t// tag as lab (we've probably lost the tag in all that\n\t\t\t// fiddling)\n\t\t\tlab = image_set_type Image_type.LAB \n\t\t\t\t(in_l ++ (mod * tint_a) ++ (mod * tint_b));\n\n\t\t\t// don't convert back to the input colourspace if it's\n\t\t\t// mono .. converting back to mono will lose all\n\t\t\t// our colour\n\t\t\tfancy_result\n\t\t\t\t= lab, in.bands == 1\n\t\t\t\t= colour_transform_to (get_type in) lab;\n\n\t\t\t// again, but just do a simple colour filter\n\t\t\tin_xyz = colour_transform_to Image_type.XYZ in;\n\t\t\ttint_xyz = colour_transform_to Image_type.XYZ tint;\n\t\t\tresult_xyz = in_xyz * (tint_xyz / 100);\n\t\t\tresult\n\t\t\t\t= result_xyz, in.bands == 1\n\t\t\t\t= colour_transform_to (get_type in) result_xyz;\n\t\t}\n\t}\n}\n\n/* add an editable drop shadow to an image \n */\nDrop_shadow x\n\t= map_unary shadow x\n{\n\tshadow image = class \n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[image, \"image\", check_Image]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tshadow_width = Slider 0 50 5;\n\t\tshadow_height = Slider 0 50 5;\n\t\tshadow_softness = Slider 0 20 5;\n\t\tuse_mask = Toggle \"Use mask to make shadow\" false;\n\t\tmask_image = foldr1 bitwise_and (bandsplit (image > 128));\n\t\tbackground_colour = 255;\n\t\tshadow_colour = 128;\n\n\t\tvalue \n\t\t\t = final\n\t\t{\n\t\t\tblur_size = shadow_softness.value * 2 + 1;\n\n\t\t\t// matrix we blur with to soften shadows\n\t\t\tmask_g = im_gauss_imask (blur_size / 3) 0.2;\n\t\t\tmask_g_line = mask_g.value?(mask_g.height / 2);\n\t\t\tmask_g_sum = foldr1 add mask_g_line;\n\t\t\tblur_matrix = Matrix_con mask_g_sum 0 [mask_g_line];\n\t\t\tmask_size = mask_g.width;\n\n\t\t\t// size of final image we build\n\t\t\tfinal_width = image.width + 2 * mask_size + \n\t\t\t\tshadow_width.value;\n\t\t\tfinal_height = image.height + 2 * mask_size + \n\t\t\t\tshadow_height.value;\n\n\t\t\t// make a plain image \n\t\t\tmk_background colour = image_new \n\t\t\t\tfinal_width final_height\n\t\t\t\timage.bands image.format \n\t\t\t\tImage_coding.NOCODING image.type\n\t\t\t\tcolour\n\t\t\t\t0 0;\n\n\t\t\t// make a mask image ... place at (x,y) in the final\n\t\t\t// image\n\t\t\tmk_mask x y \n\t\t\t\t= im_insert black mask_image.value x y,\n\t\t\t\t\tuse_mask\n\t\t\t\t= im_insert black white x y\n\t\t\t{\n\t\t\t\tblack = image_new \n\t\t\t\t\tfinal_width final_height\n\t\t\t\t\t1 Image_format.UCHAR\n\t\t\t\t\tImage_coding.NOCODING Image_type.B_W\n\t\t\t\t\t0\n\t\t\t\t\t0 0;\n\t\t\t\twhite = image_new \n\t\t\t\t\timage.width image.height\n\t\t\t\t\t1 Image_format.UCHAR\n\t\t\t\t\tImage_coding.NOCODING Image_type.B_W\n\t\t\t\t\t255\n\t\t\t\t\t0 0;\n\t\t\t}\n\n\t\t\t// make the shadow mask image ... offset mask and\n\t\t\t// soften\n\t\t\tshadow_mask = mk_mask  \n\t\t\t\t(mask_size + shadow_width.value)\n\t\t\t\t(mask_size + shadow_height.value);\n\t\t\tshadow_mask' = im_convsep shadow_mask blur_matrix;\n\n\t\t\t// make underlay ... use shadow mask to blend between\n\t\t\t// background colour and shadow colour\n\t\t\tbackground = mk_background background_colour;\n\t\t\tshadow = mk_background shadow_colour;\n\t\t\tunderlay = im_blend shadow_mask' shadow background;\n\n\t\t\t// overlay ... place image at final position\n\t\t\toverlay = mk_background 0;\n\t\t\toverlay' = im_insert overlay image.value\n\t\t\t\tmask_size mask_size;\n\n\t\t\t// overlay mask\n\t\t\toverlay_mask = mk_mask mask_size mask_size;\n\n\t\t\tfinal = if overlay_mask then overlay' else underlay;\n\t\t}\n\t}\n}\n\n// renamed these\n\nMosaic_translate = Mosaic_1point;\n\nMosaic_force = class {\n\tLeft_right = Mosaic_1point.Left_right_manual;\n\tTop_bottom = Mosaic_1point.Top_bottom_manual;\n}\n\nMosaic_affine = Mosaic_2point;\n\n// Mark used to be called Point, and was relative to xoffset/yoffset\n// need to keep this so we can still edit old image mosaic workspaces\n\nis_Point x = is_instanceof \"Point\" x;\ncheck_Point = check_instance \"Point\";\n\nPoint image l t = class \n\troot.Mark image (l + image.xoffset) (t + image.yoffset) {\n\tMark image l t \n\t\t= this.Point image (l - image.xoffset) (t - image.xoffset);\n}\n\nPoint_relative image u v\n\t= Point image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\n/* morph image colours in LAB space ... useful for tweaking colour for print\n */\nMorph_for_print in\n\t= map_unary widget in\n{\n\twidget in = class\n\t\tImage value {\n\t\t_check_args = [\n\t\t\t[in, \"in\", check_Image]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tL_scale = 1.15;\n\t\tL_offset = -4.2;\n\t\tab_scale = Slider 1 1.5 1.15;\n\t\ta_offset = Slider (-10) 10 0;\n\t\tb_offset = Slider (-10) 10 5;\n\t\tgrey_correction = Matrix_con 1 0 [\n\t\t\t[5, 5, -1 ],\n\t\t\t[10, 4, -1 ],\n\t\t\t[15, 2, -1 ],\n\t\t\t[20, 1, 1 ],\n\t\t\t[25, 1, 2 ],\n\t\t\t[30, 0, 1 ],\n\t\t\t[35, 0, 1 ],\n\t\t\t[40, 0, 1 ],\n\t\t\t[45, 0, 1 ],\n\t\t\t[50, 0, 1 ],\n\t\t\t[55, 0, 0 ],\n\t\t\t[99, 0, 0 ]\n\t\t];\n\n\t\tvalue = im_lab_morph in.value \n\t\t\t(Vector [0, a_offset.value, b_offset.value] +\n\t\t\t\tgrey_correction)\n\t\t\tL_offset L_scale ab_scale.value ab_scale.value;\n\t}\n}\n\nNew_filename = New_pathname;\nFilename = Pathname \"Pick a file\";\n\nNew_colour\n\t= widget \"Lab\" [50,0,0]\n{\n\twidget default_colour value = class\n\t\tColour colour_space value {\n\t\t_colourspaces = [\n\t\t\t\"XYZ\",         \n\t\t\t\"Yxy\",         \n\t\t\t\"Lab\",         \n\t\t\t\"LCh\",         \n\t\t\t\"UCS\",        \n\t\t\t\"RGB\",       \n\t\t\t\"sRGB\"      \n\t\t];\n\n\t\tcolour_space_option = Option \"Colour space\" _colourspaces\n\t\t\t(index (equal default_colour) _colourspaces);\n\n\t\tcolour_space = colour_space_option.labels?\n\t\t\tcolour_space_option.value;\n\n\t\tColour_edit colour_space value = widget colour_space value;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/data/Makefile.am",
    "content": "nipdatadir = $(pkgdatadir)/data\n\nnipdata_DATA = \\\n\trachel.con \\\n\tAdobeRGB1998.icc \\\n\tsRGB.icm \\\n\tmacbeth_lab_d65.mat \\\n\tmacbeth_lab_d50.mat \\\n\tvips-128.png \\\n\tnip2-icon.ico \\\n\tcmyk.icm \\\n\tstock-tool-ink-22.png \\\n\tstock-tool-path-22.png \\\n\tstock-tool-text-22.png \\\n\tstock-tool-smudge-22.png \\\n\tstock-tool-bucket-fill-22.png \\\n\tstock-tool-rect-select-22.png \\\n\tstock-tool-select-22.png \\\n\tstock-padlock-closed-22.png \\\n\tstock-alert-22.png \\\n\tnip-slider-16.png \\\n\tstock-tool-move-22.png \\\n\tstock-led-red-18.png \\\n\tstock-led-green-18.png \\\n\tstock-led-blue-18.png \\\n\tstock-led-cyan-18.png \\\n\tstock-led-yellow-18.png \\\n\tstock-led-off-18.png\n\nEXTRA_DIST = \\\n\t$(nipdata_DATA) \\\n\texamples\n\ninstall-exec-hook:\n\trm -rf $(DESTDIR)$(nipdatadir)/examples\n\t$(mkinstalldirs) $(DESTDIR)$(nipdatadir)/examples\n\tcp -r ${top_srcdir}/share/nip2/data/examples/* $(DESTDIR)$(nipdatadir)/examples\n\nuninstall-hook:\n# make sure we have write permission for 'rm'\n\tchmod -R u+w ${DESTDIR}$(nipdatadir)/examples\n\t${RM} -rf ${DESTDIR}$(nipdatadir)/examples\n\n"
  },
  {
    "path": "share/nip2/data/examples/1_point_mosaic/1pt_mosaic.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.4.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"1046\" window_height=\"748\" filename=\"$HOME/GIT/nip2/share/nip2/data/examples/1_point_mosaic/1pt_mosaic.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"pt_mosaic\" caption=\"\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"A\" caption=\"source images\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"6\" window_width=\"547\" window_height=\"416\" image_left=\"273\" image_top=\"193\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/1_point_mosaic/cd1.1.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"6\" window_width=\"547\" window_height=\"416\" image_left=\"266\" image_top=\"188\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/1_point_mosaic/cd1.2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"1\" window_y=\"10\" window_width=\"547\" window_height=\"416\" image_left=\"266\" image_top=\"188\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/1_point_mosaic/cd2.1.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"585\" window_y=\"6\" window_width=\"547\" window_height=\"416\" image_left=\"266\" image_top=\"188\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/1_point_mosaic/cd2.2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"6\" window_width=\"547\" window_height=\"416\" image_left=\"266\" image_top=\"188\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/1_point_mosaic/cd3.1.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"568\" window_y=\"6\" window_width=\"547\" window_height=\"416\" image_left=\"266\" image_top=\"188\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/1_point_mosaic/cd3.2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"6\" window_width=\"547\" window_height=\"416\" image_left=\"266\" image_top=\"188\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/1_point_mosaic/cd4.1.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"557\" window_y=\"6\" window_width=\"547\" window_height=\"416\" image_left=\"266\" image_top=\"188\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/1_point_mosaic/cd4.2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"381\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"23\" name=\"B\" caption=\"assemble tiles, fix brick walling\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A1 489 140\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A2 66 141\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"6\" window_width=\"750\" window_height=\"416\" image_left=\"359\" image_top=\"179\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_1point_item.Left_right_item.action B1 B2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A3 453 40\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A4 15 43\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"15\" window_y=\"455\" window_width=\"750\" window_height=\"416\" image_left=\"359\" image_top=\"179\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_1point_item.Left_right_item.action B4 B5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A5 500 122\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A6 65 121\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"6\" window_y=\"749\" window_width=\"750\" window_height=\"416\" image_left=\"359\" image_top=\"179\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_1point_item.Left_right_item.action B7 B8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A7 495 58\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A8 40 57\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B12\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"48\" window_y=\"804\" window_width=\"750\" window_height=\"416\" image_left=\"359\" image_top=\"179\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_1point_item.Left_right_item.action B10 B11\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B6 388 44\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B3 364 346\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B15\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"6\" window_width=\"750\" window_height=\"715\" image_left=\"359\" image_top=\"343\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_1point_item.Top_bottom_item.action B13 B14\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B9 384 17\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B17\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B15 385 629\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"6\" window_width=\"750\" window_height=\"750\" image_left=\"359\" image_top=\"631\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_1point_item.Top_bottom_item.action B16 B17\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B19\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B12 527 42\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B18 503 959\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_1point_item.Top_bottom_item.action B19 B20\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B22\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"6\" window_width=\"750\" window_height=\"750\" image_left=\"646\" image_top=\"646\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Balance_item.action B21\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1008\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"7\" name=\"C\" caption=\"correct lighting, sharpen\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B22\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"tilt\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Left-right tilt\" from=\"-1\" to=\"1\" value=\"0.22\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_mosaic_item.Tilt_item.Left_right_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"715\" window_y=\"277\" window_width=\"750\" window_height=\"750\" image_left=\"359\" image_top=\"346\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"tilt\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Top-bottom tilt\" from=\"-1\" to=\"1\" value=\"0.26000000000000001\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_mosaic_item.Tilt_item.Top_bottom_item.action C2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"878\" window_y=\"105\" window_width=\"689\" window_height=\"732\" image_left=\"328\" image_top=\"337\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Type\" labelsn=\"2\" labels0=\"Blur\" labels1=\"Sharpen\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"r\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Radius\" from=\"1\" to=\"100\" value=\"8.5508474576271194\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fac\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Amount\" from=\"0\" to=\"1\" value=\"0.70000000000000007\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shape\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Mask shape\" labelsn=\"2\" labels0=\"Square\" labels1=\"Gaussian\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"prec\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"layers\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_conv_item.Custom_blur_item.action C3\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/data/examples/2_point_mosaic/2pts_mosaic.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.4.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"793\" window_height=\"671\" filename=\"$HOME/GIT/nip2/share/nip2/data/examples/2_point_mosaic/2pts_mosaic.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"pts_mosaic\" caption=\"\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"7\" name=\"A\" caption=\"untitled\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"49\" window_y=\"31\" window_width=\"454\" window_height=\"528\" image_left=\"220\" image_top=\"244\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/2_point_mosaic/example_im_01.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"521\" window_y=\"27\" window_width=\"477\" window_height=\"551\" image_left=\"231\" image_top=\"256\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/2_point_mosaic/example_im_02.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"10\" window_y=\"22\" window_width=\"464\" window_height=\"539\" image_left=\"225\" image_top=\"250\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/2_point_mosaic/example_im_03.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"500\" window_y=\"18\" window_width=\"474\" window_height=\"550\" image_left=\"230\" image_top=\"255\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/2_point_mosaic/example_im_04.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"18\" window_y=\"6\" window_width=\"473\" window_height=\"547\" image_left=\"229\" image_top=\"254\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/2_point_mosaic/example_im_05.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"536\" window_y=\"9\" window_width=\"464\" window_height=\"539\" image_left=\"225\" image_top=\"250\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/2_point_mosaic/example_im_06.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"437\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"27\" name=\"B\" caption=\"\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A1 417 225\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A2 102 220\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A2 53 480\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A1 375 481\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"6\" window_width=\"750\" window_height=\"552\" image_left=\"359\" image_top=\"247\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_2point_item.Left_right_item.action B1 B2 B3 B4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A3 372 182\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A4 17 211\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A3 409 453\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A4 58 492\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"597\" window_width=\"750\" window_height=\"568\" image_left=\"359\" image_top=\"255\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_2point_item.Left_right_item.action B6 B7 B8 B9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A5 401 38\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B12\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A6 59 60\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A5 385 398\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark A6 32 416\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B15\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"2\" window_y=\"779\" window_width=\"750\" window_height=\"575\" image_left=\"359\" image_top=\"259\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_2point_item.Left_right_item.action B11 B12 B13 B14\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B10 111 44\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B17\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B5 104 402\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B10 655 37\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B19\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B5 632 403\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"6\" window_width=\"750\" window_height=\"750\" image_left=\"359\" image_top=\"532\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_2point_item.Top_bottom_item.action B16 B17 B18 B19\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B15 129 39\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B22\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B20 129 824\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B20 644 836\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark B15 655 42\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"6\" window_width=\"750\" window_height=\"750\" image_left=\"436\" image_top=\"625\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_2point_item.Top_bottom_item.action B21 B22 B23 B24\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"867\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"3\" name=\"C\" caption=\"untitled\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B25\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Balance_item.action C1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/data/examples/businesscard/businesscard.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.4.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"948\" window_height=\"694\" filename=\"$HOME/GIT/nip2/share/nip2/data/examples/businesscard/businesscard.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"businesscard\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"3\" name=\"A\" caption=\"source images\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"1323\" window_y=\"513\" window_width=\"590\" window_height=\"650\" image_left=\"574\" image_top=\"570\" image_mag=\"-2\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/businesscard/slanted_oval_vase2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\" left=\"52\" top=\"74\" width=\"406\" height=\"614\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region A1 36 74 422 614\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"460\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"B\" caption=\"text\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"174\" window_y=\"155\" window_width=\"1240\" window_height=\"824\" image_left=\"516\" image_top=\"196\" image_mag=\"8\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"text\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <String caption=\"Text to paint\" value=\"&lt;span size=&quot;xx-large&quot;&gt;Susan Green&lt;/span&gt;&#10;&#10;&lt;span size=&quot;large&quot;&gt;Stoneware Pottery&lt;/span&gt;&#10;&lt;i&gt;Commissions undertaken&lt;/i&gt;&#10;&#10;69 Tynestone Road, Cambridge&#10;01223 356051&#10;susangreen@waitrose.com&#10;http://susangreen.co.uk\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"font\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Fontname/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"wrap\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"1000\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                  <Expression caption=\"Wrap text at\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"align\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Alignment\" labelsn=\"3\" labels0=\"Right\" labels1=\"Centre\" labels2=\"Left\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"dpi\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                  <Expression caption=\"DPI\"/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Text_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B5\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;text colour&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Colour colour_space=\"sRGB\" value0=\"86\" value1=\"86\" value2=\"86\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"default_colour\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"default_value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Colour/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"space\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Colour space\" labelsn=\"6\" labels0=\"sRGB\" labels1=\"Lab\" labels2=\"LCh\" labels3=\"XYZ\" labels4=\"Yxy\" labels5=\"UCS\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Colour value\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_new_item.Widget_colour_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;paper colour&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Colour colour_space=\"sRGB\" value0=\"255\" value1=\"255\" value2=\"255\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"default_colour\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"default_value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Colour/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"space\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Colour space\" labelsn=\"6\" labels0=\"sRGB\" labels1=\"Lab\" labels2=\"LCh\" labels3=\"XYZ\" labels4=\"Yxy\" labels5=\"UCS\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Colour value\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_new_item.Widget_colour_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"925\" window_y=\"84\" window_width=\"923\" window_height=\"920\" image_left=\"453\" image_top=\"420\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_blend_item.Image_blend_item.action B1 B7 B8\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"899\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"7\" name=\"C\" caption=\"make card\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;Margin:&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C3\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"40\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shim\">\n                <Rhs vislevel=\"4\" flags=\"7\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"2\">\n                    <Row name=\"from\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"to\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"value\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"C3\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                        <Real/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"align\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bg_colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Background colour\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"B8\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                        <Colour/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_join_item.Left_right_item.action C1 C2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"position\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"New width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"C4.width + C3 * 2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"New height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"C4.height+ C3 * 2 \"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bgcolour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Background colour\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"B8\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"left\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixels from left\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"top\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixels from top\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Resize_item.Resize_item.Resize_item.Resize_canvas_item.action C4\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1595\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"D\" caption=\"make page of cards\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"C5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"650\" window_height=\"650\" image_left=\"909\" image_top=\"294\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"default_type\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"across\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Tiles across\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"down\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Tiles down\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"5\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"repeat\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Tile type\" labelsn=\"2\" labels0=\"Replicate\" labels1=\"Four-way mirror\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_tile_item.Replicate_item.action D1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"6\" window_width=\"650\" window_height=\"650\" image_left=\"309\" image_top=\"2393\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"l\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Crop left\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"C3\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"t\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Crop top\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"C3\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"w\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Crop width\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"D4.width - C3 * 2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"h\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Crop height\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"D4.height - C3 * 2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_crop_item.action D4\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/data/examples/clone/clone.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.4.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"1019\" window_height=\"625\" filename=\"$HOME/GIT/nip2/share/nip2/data/examples/clone/clone.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"clone\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"A\" caption=\"Images\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"225\" window_y=\"466\" window_width=\"1108\" window_height=\"532\" image_left=\"305\" image_top=\"70\" image_mag=\"4\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/clone/example_im_01.png&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"478\" window_height=\"526\" image_left=\"58\" image_top=\"57\" image_mag=\"4\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/clone/example_im_02.png&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"441\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"2\" name=\"B\" caption=\"Clone process\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"639\" window_height=\"532\" image_left=\"364\" image_top=\"90\" image_mag=\"4\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"im1\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"im2\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"r1\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iRegion image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\" left=\"406\" top=\"49\" width=\"28\" height=\"37\">\n                    <iRegiongroup/>\n                  </iRegion>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"p2\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"86\" top=\"23\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"mask\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"Options\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\">\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"pause\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Toggle caption=\"Pause process\" value=\"true\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"replace\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Option/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"balance\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Toggle/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"process\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Toggle caption=\"Replace area with Gaussian noise.\" value=\"false\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"sc\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Slider/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_mosaic_item.Clone_area_item.action A2 A3\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/data/examples/framing/framing.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.4.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"970\" window_height=\"633\" filename=\"$HOME/GIT/nip2/share/nip2/data/examples/framing/framing.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"framing\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"A\" caption=\"untitled\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/framing/framing_picture.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/framing/framing_complex.png&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/framing/framing_corner.png&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"2172\" window_y=\"197\" window_width=\"664\" window_height=\"802\" image_left=\"39\" image_top=\"446\" image_mag=\"8\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/framing/framing_distorted_frame.png&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"382\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"B\" caption=\"Staighten Frame\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"717\" window_y=\"150\" window_width=\"710\" window_height=\"794\" image_left=\"348\" image_top=\"359\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"dir\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap1\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"23\" top=\"43\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap2\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"369\" top=\"8\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap3\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"388\" top=\"468\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap4\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"9\" top=\"485\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_frame_item.Straighten_frame_item.action A4\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"494\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"C\" caption=\"Painting with Simple Frame\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1708\" window_y=\"57\" window_width=\"521\" window_height=\"430\" image_left=\"252\" image_top=\"176\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ppcm\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Number of pixels per cm\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"5\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"overlap\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Size of frame overlap in cm\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"variables\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"mount_options\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"frame\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_frame_item.Build_frame_item.Simple_frame_item.action B1 A1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"494\" y=\"389\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"D\" caption=\"Painting with Complex Frame, with adjusted variables\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1673\" window_y=\"48\" window_width=\"548\" window_height=\"445\" image_left=\"266\" image_top=\"183\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ppcm\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Number of pixels per cm\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"5\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"overlap\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Size of frame overlap in cm\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"variables\">\n                <Rhs vislevel=\"2\" flags=\"6\">\n                  <Subcolumn vislevel=\"1\">\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"scale_factor\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Expression caption=\"scale the size of the frame by\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"corner_section\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Slider caption=\"Corner section\" from=\"0.10000000000000001\" to=\"1\" value=\"0.5\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"edge_section\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Slider/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"middle_section\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Slider/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"blend_fraction\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Slider caption=\"Blend fraction\" from=\"0.10000000000000001\" to=\"0.90000000000000002\" value=\"0.10000000000000001\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"option\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Toggle/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"comp\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"mount_options\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"frame\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_frame_item.Build_frame_item.Complex_frame_item.action A2 A1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1203\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"2\" name=\"E\" caption=\"Painting with frame corner, and coloured mount\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"E1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1669\" window_y=\"53\" window_width=\"640\" window_height=\"566\" image_left=\"312\" image_top=\"244\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ppcm\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Number of pixels per cm\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"5\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"overlap\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Size of frame overlap in cm\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"-10\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"variables\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"mount_options\">\n                <Rhs vislevel=\"2\" flags=\"6\">\n                  <Subcolumn vislevel=\"1\">\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"apply\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Toggle caption=\"Apply mount options\" value=\"false\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"ls\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Expression caption=\"Lower mount section bigger by (cm)\"/>\n                        <Subcolumn vislevel=\"0\">\n                          <Row name=\"caption\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"expr\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText formula=\"5\"/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"super\">\n                            <Rhs vislevel=\"1\" flags=\"4\">\n                              <Subcolumn vislevel=\"0\"/>\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                        </Subcolumn>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"mount_colour\">\n                      <Rhs vislevel=\"3\" flags=\"7\">\n                        <Colour colour_space=\"sRGB\" value0=\"0\" value1=\"0\" value2=\"0\"/>\n                        <Subcolumn vislevel=\"1\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"frame\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_frame_item.Build_frame_item.Frame_corner_item.action A3 A1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/data/examples/logo/logo2.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.4.0\">\n  <Workspace window_x=\"50\" window_y=\"80\" window_width=\"1261\" window_height=\"842\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" locked=\"false\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"logo5\" caption=\"Default empty workspace\" filename=\"$HOME/GIT/nip2/share/nip2/data/examples/logo/logo2.ws\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"A\" caption=\"render text\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"979\" window_y=\"86\" window_width=\"799\" window_height=\"438\" image_left=\"391\" image_top=\"179\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"text\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <String caption=\"Text to paint\" value=\"VIPS\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"font\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Fontname caption=\"Use font\" value=\"Tintin Majuscules Bold 12\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"wrap\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                  <Expression caption=\"Wrap text at\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"align\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"dpi\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"1000\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                  <Expression caption=\"DPI\"/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Text_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"662\" window_y=\"411\" window_width=\"684\" window_height=\"469\" image_left=\"334\" image_top=\"178\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"5.3033999999999999\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"r\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Radius\" from=\"1\" to=\"100\" value=\"22\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shape\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Mask shape\" labelsn=\"2\" labels0=\"Square\" labels1=\"Gaussian\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fac\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Amount\" from=\"0\" to=\"1\" value=\"0.95999999999999996\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"prec\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"layers\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_conv_item.Custom_blur_item.action A1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"431\" window_y=\"362\" window_width=\"963\" window_height=\"641\" image_left=\"473\" image_top=\"264\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1.59815\" offset=\"-21.802199999999999\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A1 - A2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.U8_item.action A4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_convert_item.sRGB_item.action A6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A11\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"632\" window_y=\"366\" window_width=\"915\" window_height=\"592\" image_left=\"449\" image_top=\"256\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"r\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Radius\" from=\"0\" to=\"50\" value=\"14\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"highlights\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Highlights\" from=\"0\" to=\"100\" value=\"83\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"glow\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Glow\" from=\"0\" to=\"1\" value=\"0.90000000000000002\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour\">\n                <Rhs vislevel=\"3\" flags=\"7\">\n                  <Colour colour_space=\"Lab\" value0=\"78.429710388183594\" value1=\"10.576605796813965\" value2=\"74.185394287109375\"/>\n                  <Subcolumn vislevel=\"1\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_diffuse_glow_item.action A8\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"563\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"B\" caption=\"add texture\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A11\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"746\" window_y=\"0\" window_width=\"613\" window_height=\"171\" image_left=\"289\" image_top=\"46\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"dimension\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Dimension\" from=\"2.0009999999999999\" to=\"2.9990000000000001\" value=\"2.6000000000000001\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nsize\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image size (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"256\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Noise_item.Fractal_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B12\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_levels_item.Scale_item.action B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_enhance_item.Falsecolour_item.action B12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B13\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"439\" window_width=\"876\" window_height=\"724\" image_left=\"430\" image_top=\"340\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"default_type\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"across\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Tiles across\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"1 + B11.width / B1.width\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"down\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Tiles down\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"1 + B11.height / B1.height\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"repeat\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_tile_item.Replicate_item.action B2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"799\" window_y=\"649\" window_width=\"529\" window_height=\"299\" image_left=\"256\" image_top=\"110\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"p\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Blend position\" from=\"0\" to=\"1\" value=\"0.29999999999999999\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_blend_item.Scale_blend_item.action B13 B11\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B14\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"l\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Crop left\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"0\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"t\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Crop top\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"0\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"w\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Crop width\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"B11.width\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"h\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Crop height\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"B11.height\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"geo\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_crop_item.action B3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"746\" window_y=\"0\" window_width=\"492\" window_height=\"185\" image_left=\"228\" image_top=\"53\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.U8_item.action B14\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1048\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"27\" name=\"C\" caption=\"make shadow\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C7\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider caption=\"shadow fuzziness\" from=\"0\" to=\"100\" value=\"38.3459\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"caption\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText formula=\"&quot;shadow fuzziness&quot;\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"from\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"to\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Real/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Widget_slider_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C15\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider caption=\"shadow scale\" from=\"1\" to=\"2\" value=\"1.1014999999999999\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"caption\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText formula=\"&quot;shadow scale&quot;\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"from\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"to\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Real/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Widget_slider_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C19\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;shadow colour&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C14\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Colour colour_space=\"sRGB\" value0=\"148\" value1=\"112\" value2=\"94\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"default_colour\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"default_value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Colour/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"space\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Colour space\" labelsn=\"6\" labels0=\"sRGB\" labels1=\"Lab\" labels2=\"LCh\" labels3=\"XYZ\" labels4=\"Yxy\" labels5=\"UCS\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Colour value\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_new_item.Widget_colour_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C25\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;background colour&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C17\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iText formula=\"Colour_new_item.Widget_colour_item.action\"/>\n            <Colour colour_space=\"sRGB\" value0=\"255\" value1=\"255\" value2=\"255\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"default_colour\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"default_value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Colour/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"space\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Colour space\" labelsn=\"6\" labels0=\"sRGB\" labels1=\"Lab\" labels2=\"LCh\" labels3=\"XYZ\" labels4=\"Yxy\" labels5=\"UCS\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Colour value\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;offset shadow vertically by&quot; (-25)\"/>\n            <Expression caption=\"offset shadow vertically by\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C20\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot; &quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C22\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"New width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"C7.width + 2 * C9.value\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"New height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"C7.height + 2 * C9.value\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bgcolour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Background colour\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"position\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"left\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixels from left\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"top\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixels from top\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Resize_item.Resize_item.Resize_item.Resize_canvas_item.action C7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C26\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"r\">\n                <Rhs vislevel=\"2\" flags=\"5\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText formula=\"C9\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"shape\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Mask shape\" labelsn=\"2\" labels0=\"Square\" labels1=\"Gaussian\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fac\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"prec\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"layers\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_conv_item.Custom_blur_item.action C22\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C23\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"xfactor\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Horizontal scale factor\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"C15.value\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"yfactor\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Vertical scale factor\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"C15.value\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"kernel\">\n                <Rhs vislevel=\"2\" flags=\"6\">\n                  <Subcolumn vislevel=\"1\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Resize_item.Scale_item.action C26\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_blend_item.Image_blend_item.action C23 C14 C17\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C24\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"New width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"New height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"C18.height + C11.expr\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bgcolour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Background colour\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"C17\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"position\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Position\" labelsn=\"10\" labels0=\"North-west\" labels1=\"North\" labels2=\"North-east\" labels3=\"West\" labels4=\"Centre\" labels5=\"East\" labels6=\"South-west\" labels7=\"South\" labels8=\"South-east\" labels9=\"Specify in pixels\" value=\"7\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"left\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixels from left\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"top\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixels from top\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Resize_item.Resize_item.Resize_item.Resize_canvas_item.action C18\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1729\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"19\" name=\"D\" caption=\"position and blend layers\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D10\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D9\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D8\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"C24\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot; &quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D14\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"New width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"D8.width\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"New height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"D8.height\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bgcolour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Background colour\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"position\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Position\" labelsn=\"10\" labels0=\"North-west\" labels1=\"North\" labels2=\"North-east\" labels3=\"West\" labels4=\"Centre\" labels5=\"East\" labels6=\"South-west\" labels7=\"South\" labels8=\"South-east\" labels9=\"Specify in pixels\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"left\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixels from left\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"top\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixels from top\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Resize_item.Resize_item.Resize_item.Resize_canvas_item.action D10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D15\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"New width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"D8.width\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"New height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"D8.height\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bgcolour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Background colour\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"position\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Position\" labelsn=\"10\" labels0=\"North-west\" labels1=\"North\" labels2=\"North-east\" labels3=\"West\" labels4=\"Centre\" labels5=\"East\" labels6=\"South-west\" labels7=\"South\" labels8=\"South-east\" labels9=\"Specify in pixels\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"left\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixels from left\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"top\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixels from top\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Resize_item.Resize_item.Resize_item.Resize_canvas_item.action D9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"602\" window_y=\"662\" window_width=\"985\" window_height=\"382\" image_left=\"486\" image_top=\"151\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1.44462\" offset=\"-128\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_blend_item.Image_blend_item.action D14 D15 D8\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n"
  },
  {
    "path": "share/nip2/data/examples/manual_balance/manual_balance.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.4.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"1193\" window_height=\"683\" filename=\"$HOME/GIT/nip2/share/nip2/data/examples/manual_balance/manual_balance.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"manual_balance\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"8\" name=\"A\" caption=\"Images\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"602\" window_y=\"480\" window_width=\"745\" window_height=\"689\" image_left=\"364\" image_top=\"276\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/manual_balance/simp_base.png&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/manual_balance/mask_control.png&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/manual_balance/mask_01.png&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/manual_balance/mask_02.png&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/manual_balance/mask_03.png&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Group/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Group [A3,A4,A5]\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"781\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"B\" caption=\"Process\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Manual_balance_item.Balance_find_item.action A1 A2 A6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"im_in\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"m_matrix\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"m_group\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"blur\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"adjust\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Matrix/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"Build\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle caption=\"Build Scale and Offset Correction Images\" value=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"Output\">\n                <Rhs vislevel=\"2\" flags=\"6\">\n                  <Subcolumn vislevel=\"1\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"value\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_mosaic_item.Manual_balance_item.Balance_check_item.action A1 B1 A6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"2997\" window_y=\"620\" window_width=\"516\" window_height=\"543\" image_left=\"240\" image_top=\"240\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Manual_balance_item.Balance_apply_item.action A1 B2.Output.scale_im B2.Output.offset_im\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/data/examples/overlays_and_blending/overlay_blend.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.4.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"1115\" window_height=\"800\" filename=\"$HOME/GIT/nip2/share/nip2/data/examples/overlays_and_blending/overlay_blend.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"overlay_blend\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"A\" caption=\"Images\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/overlays_and_blending/blend_example_ir.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/overlays_and_blending/blend_example_vis.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/overlays_and_blending/blend_example_xray.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"466\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"B\" caption=\"Complete Transparency\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iText formula=\"Filter_blend_item.Scale_blend_item.action A2 A1\"/>\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"466\" y=\"208\" open=\"true\" selected=\"true\" sform=\"false\" next=\"3\" name=\"C\" caption=\"Blending Between two, then three Images\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"orientation\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"blend_position\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Blend position\" from=\"0\" to=\"1\" value=\"0.28767123287671231\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"blend_width\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Blend width\" from=\"0\" to=\"1\" value=\"0.20547945205479454\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_blend_item.Line_blend_item.action A1 A2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1600\" window_y=\"652\" window_width=\"472\" window_height=\"511\" image_left=\"218\" image_top=\"207\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"orientation\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"blend_position\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Blend position\" from=\"0\" to=\"1\" value=\"0.71232876712328774\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"blend_width\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_blend_item.Line_blend_item.action C1 A3\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"945\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"D\" caption=\"Overlay\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"2554\" window_y=\"136\" window_width=\"619\" window_height=\"590\" image_left=\"301\" image_top=\"256\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Colour overlay as\" labelsn=\"6\" labels0=\"Green over Red\" labels1=\"Blue over Red\" labels2=\"Red over Green\" labels3=\"Red over Blue\" labels4=\"Blue over Green\" labels5=\"Green over Blue\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_overlay_header_item.action A2 A1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/data/examples/registering/registering.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.4.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"722\" filename=\"$HOME/GIT/nip2/share/nip2/data/examples/registering/registering.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"registering\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"A\" caption=\"Original Images\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"2063\" window_y=\"600\" window_width=\"513\" window_height=\"435\" image_left=\"206\" image_top=\"190\" image_mag=\"8\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/registering/example_im_1.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"2464\" window_y=\"413\" window_width=\"676\" window_height=\"559\" image_left=\"165\" image_top=\"120\" image_mag=\"2\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/registering/example_im_2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"2428\" window_y=\"600\" window_width=\"663\" window_height=\"468\" image_left=\"171\" image_top=\"178\" image_mag=\"4\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/registering/example_im_3.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"1986\" window_y=\"381\" window_width=\"639\" window_height=\"614\" image_left=\"155\" image_top=\"134\" image_mag=\"2\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/registering/example_im_4.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"476\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"B\" caption=\"Images different size\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap1\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"56\" top=\"52\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bp1\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"45\" top=\"42\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap2\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"241\" top=\"179\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bp2\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"191\" top=\"143\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"refine\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"lock\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"y\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Match_item.action A1 A2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"476\" y=\"358\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"C\" caption=\"Correcting for slight rotation\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap1\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"56\" top=\"52\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bp1\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"60\" top=\"47\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap2\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"241\" top=\"179\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bp2\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"236\" top=\"187\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"refine\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"lock\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"y\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText formula=\"Image_file &quot;$HOME/GIT/nip2/share/nip2/data/examples/registering/example_im_3.jpg&quot;\"/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Match_item.action A1 A2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"476\" y=\"716\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"D\" caption=\"Correcting for perspective distortion\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap1\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"41\" top=\"120\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap2\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"195\" top=\"11\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap3\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"46\" top=\"188\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap4\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"200\" top=\"191\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bp1\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"45\" top=\"115\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bp2\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"183\" top=\"16\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bp3\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"50\" top=\"178\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bp4\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"194\" top=\"183\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"y\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Image_perspective_match_item.action A1 A4\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1014\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"4\" name=\"E\" caption=\"Comparisons after corrections\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"E1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1600\" window_y=\"0\" window_width=\"576\" window_height=\"622\" image_left=\"140\" image_top=\"136\" image_mag=\"2\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_blend_item.Line_blend_item.action A1 B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1600\" window_y=\"0\" window_width=\"566\" window_height=\"603\" image_left=\"137\" image_top=\"131\" image_mag=\"2\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_blend_item.Line_blend_item.action A1 C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1979\" window_y=\"209\" window_width=\"552\" window_height=\"600\" image_left=\"134\" image_top=\"130\" image_mag=\"2\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_blend_item.Line_blend_item.action A1 D1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"382\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"H\" caption=\"Comparisons before corrections\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1600\" window_y=\"0\" window_width=\"527\" window_height=\"600\" image_left=\"127\" image_top=\"130\" image_mag=\"2\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_blend_item.Line_blend_item.action A1 A2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"2039\" window_y=\"223\" window_width=\"545\" window_height=\"597\" image_left=\"132\" image_top=\"129\" image_mag=\"2\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_blend_item.Line_blend_item.action A1 A3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1979\" window_y=\"209\" window_width=\"558\" window_height=\"598\" image_left=\"135\" image_top=\"130\" image_mag=\"2\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_blend_item.Line_blend_item.action A1 A4\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/data/macbeth_lab_d50.mat",
    "content": "3 24\n38.82\t14.52\t14.86\n65.97\t16.84\t16.71\n50.25\t-4.56\t-21.94\n43.69\t-14.21\t19.17\n55.13\t9.02\t-24.66\n70.1\t-31.71\t-0.78\n64.17\t34.77\t62.36\n40.28\t10.55\t-44.65\n51.82\t47.11\t15.64\n31\t22.5\t-21.72\n72.3\t-23.44\t57.12\n72.4\t20.15\t68.15\n29.15\t20.65\t-55.37\n54.78\t-38.84\t31.54\n42.5\t55.62\t27.17\n82.4\t3.54\t79.73\n51.61\t48.8\t-14\n50.03\t-27.58\t-29.2\n94.27\t-0.25\t0.35\n80.3\t0.05\t-0.38\n65.41\t0.09\t-0.44\n50.82\t-0.37\t-0.59\n36.1\t0.09\t-0.49\n23.8\t0.54\t-0.18\n\n"
  },
  {
    "path": "share/nip2/data/macbeth_lab_d65.mat",
    "content": "3 24 1 0\n37.7758\t13.122\t13.2705\n65.0651\t13.6974\t16.1079\n51.125\t-3.3471\t-20.6654\n42.9236\t-12.4326\t19.1425\n56.0801\t7.2918\t-23.6413\n70.8371\t-30.663\t2.5131\n61.0209\t34.1118\t57.0494\n42.4442\t9.1559\t-40.9195\n50.2147\t41.9414\t12.8438\n31.1403\t21.5385\t-23.1365\n70.9067\t-20.5043\t57.9149\n69.6498\t20.8271\t64.4978\n32.4864\t15.9125\t-48.5415\n54.1624\t-34.1277\t32.8876\n40.4646\t48.7723\t24.0303\n80.0696\t4.3066\t79.2876\n50.847\t42.549\t-16.3102\n52.5361\t-28.7633\t-23.2291\n94.8303\t-0.536\t0.3512\n80.3002\t0.0736\t-0.3646\n65.3137\t0.2192\t-0.4743\n50.7737\t-0.2655\t-0.546\n36.005\t0.2655\t-0.5395\n22.1402\t0.6357\t-0.219\n"
  },
  {
    "path": "share/nip2/data/rachel.con",
    "content": "5 5 21 0\n1 -4 -4 -4 1 \n-4 6 8 6 -4 \n-4 8 9 8 -4 \n-4 6 8 6 -4 \n1 -4 -4 -4 1 \n"
  },
  {
    "path": "share/nip2/rc/Makefile.am",
    "content": "rcdir = $(pkgdatadir)/rc\n\nrc_DATA = ipgtkrc\n\nEXTRA_DIST = $(rc_DATA)\n"
  },
  {
    "path": "share/nip2/rc/ipgtkrc",
    "content": "\n# style for parent widgets\nstyle \"parent_style\" \n{\n\tbg[NORMAL] = \"#887FA3\"\n\tbg[PRELIGHT] = \"#ADA7C8\"\n\tbg[ACTIVE] = \"#887FA3\"\n\tbg[SELECTED] = \"#887FA3\"\n\tbg[INSENSITIVE] = \"#625B81\"\n}\n\n# style for child widgets\nstyle \"child_style\" \n{\n\tbg[NORMAL] = \"#7590AE\"\n\tbg[PRELIGHT] = \"#9DB8D2\"\n\tbg[ACTIVE] = \"#7590AE\"\n\tbg[SELECTED] = \"#7590AE\"\n\tbg[INSENSITIVE] = \"#4B6983\"\n}\n\n# style for selected widgets\nstyle \"selected_style\" \n{\n\tbg[NORMAL] = \"#83A67F\"\n\tbg[PRELIGHT] = \"#C5D2C8\"\n\tbg[ACTIVE] = \"#83A67F\"\n\tbg[SELECTED] = \"#83A67F\"\n\tbg[INSENSITIVE] = \"#5D7555\"\n}\n\n# style for unselected column headers\nstyle \"column_style\" \n{\n\tbg[NORMAL] = \"#C5D2C8\"\n\tbg[PRELIGHT] = \"#C5D2C8\"\n\tbg[ACTIVE] = \"#C5D2C8\"\n\tbg[SELECTED] = \"#C5D2C8\"\n\tbg[INSENSITIVE] = \"#C5D2C8\"\n}\n\n# style for widgets with errors in them\nstyle \"error_style\" \n{\n\tbg[NORMAL] = \"#C1665A\"\n\tbg[PRELIGHT] = \"#E0B6AF\"\n\tbg[ACTIVE] = \"#C1665A\"\n\tbg[SELECTED] = \"#C1665A\"\n\tbg[INSENSITIVE] = \"#884631\"\n}\n\n# style for dirty widgets (need recalculation)\nstyle \"dirty_style\" \n{\n\tbg[NORMAL] = \"#E0C39E\"\n\tbg[PRELIGHT] = \"#EFE0CD\"\n\tbg[ACTIVE] = \"#E0C39E\"\n\tbg[SELECTED] = \"#E0C39E\"\n\tbg[INSENSITIVE] = \"#B39169\"\n}\n\n# style for captions ... eg. the line of text under the image thumbnails\nstyle \"caption_style\" \n{\n\tbg[NORMAL] = \"#EED680\"\n}\n\nwidget \"*parent_widget*\" style \"parent_style\"\nwidget \"*child_widget*\" style \"child_style\"\nwidget \"*selected_widget*\" style \"selected_style\"\nwidget \"*column_widget*\" style \"column_style\"\nwidget \"*error_widget*\" style \"error_style\"\nwidget \"*dirty_widget*\" style \"dirty_style\"\nwidget \"*caption_widget*\" style \"caption_style\"\nwidget \"*centre_widget*\" style \"child_style\"\nwidget \"*shadow_widget*\" style \"column_style\"\n\n# turn this on here ... no one will find this useful thing unless we turn it\n# on by default\ngtk-can-change-accels = 1\n\n"
  },
  {
    "path": "share/nip2/start/Colour.def",
    "content": "\nColour_new_item = class \n\tMenupullright (_ \"_New\") (_ \"make a patch of colour\") {\n\tWidget_colour_item = class \n\t\tMenuaction (_ \"_Colour\") (_ \"make a patch of colour\") {\n\t\taction = Colour_picker \"Lab\" [50,0,0];\n\t}\n\n\tLAB_colour = class\n\t\tMenuaction (_ \"CIE Lab _Picker\") (_ \"pick colour in CIE Lab space\") {\n\t\taction = widget \"Lab\" [50, 0, 0];\n\n\t\t// ab_slice size\n\t\tsize = 512;\n\n\t\t// range of values ... +/- 128 for ab\n\t\trange = 256;\n\n\t\t// map xy in slice image to ab and back\n\t\txy2ab x = x / (size / range) - 128;\n\t\tab2xy a = (a + 128) * (size / range);\n\n\t\twidget space default_value = class\n\t\t\tColour space _result {\n\t\t\t_vislevel = 3;\n\n\t\t\t[_L, _a, _b] = default_value;\n\t\t\tL = Scale \"Lightness\" 0 100 _L;\n\t\t\tab_slice = Image (lab_slice size L.value);\n\t\t\tpoint = Mark ab_slice (ab2xy _a) (ab2xy _b);\n\n\t\t\t_result = [L.value, xy2ab point.left, xy2ab point.top];\n\n\t\t\tColour_edit colour_space value = widget colour_space value;\n\t\t}\n\t}\n\n\tCCT_colour = class\n\t\tMenuaction (_ \"Colour from CCT\") (_ \"pick colour by CCT\") {\n\t\taction = widget 6500;\n\n\t\twidget x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tT = Scale \"CCT\" 1800 25000 x;\n\n\t\t\t_result = colour_from_temp (to_real T);\n\n\t\t\tColour_edit space value \n\t\t\t\t= widget (temp_from_colour (Colour space value));\n\t\t}\n\t}\n}\n\nColour_to_colour_item = class\n\tMenuaction (_ \"Con_vert to Colour\") (_ \"convert anything to a colour\") {\n\taction x = to_colour x;\n}\n\n#separator\n\nColour_convert_item = class\n\tMenupullright (_ \"_Colourspace\") (_ \"convert to various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\tconv dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Convert to\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (colour_transform_to to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"convert to mono colourspace\") {\n\t\taction x = conv Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"convert to sRGB colourspace\") {\n\t\taction x = conv Image_type.sRGB x;\n\t}\n\n\tscRGB_item = class\n\t\tMenuaction (_ \"_scRGB\") (_ \"convert to scRGB colourspace\") {\n\t\taction x = conv Image_type.scRGB x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"convert to GREY16 colourspace\") {\n\t\taction x = conv Image_type.GREY16 x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"convert to RGB16 colourspace\") {\n\t\taction x = conv Image_type.RGB16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") (_ \"convert to Lab colourspace (float Lab)\") {\n\t\taction x = conv Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") (_ \"convert to LabQ colourspace (32-bit Lab)\") {\n\t\taction x = conv Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") (_ \"convert to LabS colourspace (48-bit Lab)\") {\n\t\taction x = conv Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"convert to LCh colourspace\") {\n\t\taction x = conv Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"convert to XYZ colourspace\") {\n\t\taction x = conv Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"convert to Yxy colourspace\") {\n\t\taction x = conv Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"convert to UCS colourspace\") {\n\t\taction x = conv Image_type.UCS x;\n\t}\n}\n\n/* mark objects as being in various colourspaces\n */\nColour_tag_item = class\n\tMenupullright (_ \"_Tag As\") \n\t\t(_ \"tag object as being in various colour spaces\") {\n\tspaces = Image_type.image_colour_spaces;\n\n\ttag dest x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tto = Option_enum (_ \"Tag as\") spaces (spaces.get_name dest);\n\n\t\t_result = map_unary (image_set_type to.value_thing) x;\n\t}\n\n\tMono_item = class\n\t\tMenuaction (_ \"_Monochrome\") (_ \"tag as being in mono colourspace\") {\n\t\taction x = tag Image_type.B_W x;\n\t}\n\n\tsRGB_item = class\n\t\tMenuaction (_ \"_sRGB\") (_ \"tag as being in sRGB colourspace\") {\n\t\taction x = tag Image_type.sRGB x;\n\t}\n\n\tscRGB_item = class\n\t\tMenuaction (_ \"_scRGB\") (_ \"tag as being in scRGB colourspace\") {\n\t\taction x = tag Image_type.scRGB x;\n\t}\n\n\tRGB16_item = class\n\t\tMenuaction (_ \"_RGB16\") (_ \"tag as being in RGB16 colourspace\") {\n\t\taction x = tag Image_type.RGB16 x;\n\t}\n\n\tGREY16_item = class\n\t\tMenuaction (_ \"_GREY16\") (_ \"tag as being in GREY16 colourspace\") {\n\t\taction x = tag Image_type.GREY16 x;\n\t}\n\n\tLab_item = class\n\t\tMenuaction (_ \"_Lab\") \n\t\t\t(_ \"tag as being in Lab colourspace (float Lab)\") {\n\t\taction x = tag Image_type.LAB x;\n\t}\n\n\tLabQ_item = class\n\t\tMenuaction (_ \"Lab_Q\") \n\t\t\t(_ \"tag as being in LabQ colourspace (32-bit Lab)\") {\n\t\taction x = tag Image_type.LABQ x;\n\t}\n\n\tLabS_item = class\n\t\tMenuaction (_ \"Lab_S\") \n\t\t\t(_ \"tag as being in LabS colourspace (48-bit Lab)\") {\n\t\taction x = tag Image_type.LABS x;\n\t}\n\n\tLCh_item = class\n\t\tMenuaction (_ \"L_Ch\") (_ \"tag as being in LCh colourspace\") {\n\t\taction x = tag Image_type.LCH x;\n\t}\n\n\tXYZ_item = class\n\t\tMenuaction (_ \"_XYZ\") (_ \"tag as being in XYZ colourspace\") {\n\t\taction x = tag Image_type.XYZ x;\n\t}\n\n\tYxy_item = class\n\t\tMenuaction (_ \"_Yxy\") (_ \"tag as being in Yxy colourspace\") {\n\t\taction x = tag Image_type.YXY x;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_UCS\") (_ \"tag as being in UCS colourspace\") {\n\t\taction x = tag Image_type.UCS x;\n\t}\n}\n\nColour_temperature_item = class\n\tMenupullright (_ \"Te_mperature\") \n\t\t(_ \"colour temperature conversions\") {\n\tWhitepoint_item = class\n\t\tMenuaction (_ \"_Move Whitepoint\") (_ \"change whitepoint\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\told_white = Option_enum (_ \"Old whitepoint\") Whitepoints \"D65\";\n\t\t\tnew_white = Option_enum (_ \"New whitepoint\") Whitepoints \"D50\";\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im' * \n\t\t\t\t\t\t(new_white.value_thing / old_white.value_thing);\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD65_to_D50_item = class \n\t\tMenupullright (_ \"D_65 to D50\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D65 to D50 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D652D50_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D65 to D50 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D652D50 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tD50_to_D65_item = class \n\t\tMenupullright (_ \"D_50 to D65\") (_ \"complex conversion\") {\n\t\tXYZ_minimal_item = class\n\t\t\tMenuaction (_ \"_Minimal\") \n\t\t\t\t(_ \"D50 to D65 using the minimal 3x3 matrix in XYZ\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = recomb D502D65_direct im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBradford_item = class\n\t\t\tMenuaction (_ \"_Bradford\") (_ \"D60 to D65 in Bradford cone space\") {\n\t\t\taction x \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= im'''\n\t\t\t\t{\n\t\t\t\t\tim' = colour_transform_to Image_type.XYZ im;\n\t\t\t\t\tim'' = im_D502D65 im';\n\t\t\t\t\tim''' = colour_transform_to (get_type im) im'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLab_to_D50XYZ_item = class\n\t\tMenuaction (_ \"_Lab to D50 XYZ\") \n\t\t\t(_ \"Lab to XYZ with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50Lab2XYZ) x;\n\t}\n\n\tD50XYZ_to_Lab_item = class\n\t\tMenuaction (_ \"D50 _XYZ to Lab\") \n\t\t\t(_ \"XYZ to Lab with a D50 whitepoint\") {\n\t\taction x = map_unary (colour_unary im_D50XYZ2Lab) x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCCT_item = class\n\t\tMenuaction (_ \"Calculate temperature\")\n\t\t\t(_ \"estimate CCT using the McCamy approximation\") {\n\t\taction z = map_unary temp_from_colour z;\n\t}\n\n\tColour_item = Colour_new_item.CCT_colour;\n}\n\nColour_icc_item = class\n\tMenupullright (_ \"_ICC\") (_ \"transform with ICC profiles\") {\n\tprint_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/cmyk.icm\";\n\tmonitor_profile = \n\t\t\"$VIPSHOME/share/$PACKAGE/data/sRGB.icm\";\n\tguess_profile image\n\t\t= print_profile, \n\t\t\thas_type image && \n\t\t\tget_type image == Image_type.CMYK &&\n\t\t\thas_bands image && \n\t\t\tget_bands image >= 4\n\t\t= monitor_profile;\n\trender_intents = Option_enum (_ \"Render intent\") Render_intent.names\n\t\t(_ \"Absolute\");\n\n\tExport_item = class\n\t\tMenuaction (_ \"_Export\") (_ \"export from PCS to device space\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\t\t\tdepth = Option (_ \"Output depth\") [_ \"8 bit\", _ \"16 bit\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_export [8, 16]?depth profile.value \n\t\t\t\t\t\tintent.value_thing lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LABQ image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImport_item = class\n\t\tMenuaction (_ \"_Import\") (_ \"import from device space to PCS\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tembedded = Toggle (_ \"Use embedded profile if possible\") false;\n\t\t\tprofile = Pathname (_ \"Default input profile\") (guess_profile x);\n\t\t\tintent = render_intents;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_import_embedded intent.value_thing image,\n\t\t\t\t\t\tget_header_type \"icc-profile-data\" image != 0 &&\n\t\t\t\t\t\tembedded\n\t\t\t\t\t= icc_import profile.value intent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tTransform_item = class\n\t\tMenuaction (_ \"_Transform\") (_ \"transform between two device spaces\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tin_profile = Pathname (_ \"Input profile\") (guess_profile x);\n\t\t\tout_profile = Pathname (_ \"Output profile\") print_profile;\n\t\t\tintent = render_intents;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_transform in_profile.value out_profile.value \n\t\t\t\t\t\tintent.value_thing image;\n\t\t\t}\n\t\t}\n\t}\n\n\tAC2RC_item = class\n\t\tMenuaction (_ \"_Absolute to Relative\") \n\t\t\t(_ \"absolute to relative colorimetry using device profile\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tprofile = Pathname (_ \"Pick a profile\") (guess_profile x);\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= icc_ac2rc profile.value lab\n\t\t\t\t{\n\t\t\t\t\tlab = colour_transform_to Image_type.LAB image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_rad_item = class\n\tMenupullright (_ \"_Radiance\") (_ \"convert to and from Radiance packed format\") {\n\tUnpack_item = class\n\t\tMenuaction (_ \"Unpack\") \n\t\t\t(_ \"unpack Radiance format to float\") {\n\t\taction x = map_unary rad2float x;\n\t}\n\n\tPack_item = class\n\t\tMenuaction (_ \"Pack\") \n\t\t\t(_ \"pack 3-band float to Radiance format\") {\n\t\taction x = map_unary float2rad x;\n\t}\n}\n\n#separator\n\nColour_dE_item = class\n\tMenupullright (_ \"_Difference\") (_ \"calculate colour difference\") {\n\t/* Apply a converter to an object ... convert image or colour (since\n\t * we can guess the colour space we're converting from), don't convert\n\t * matrix or vector (since we can't tell ... assume it's in the right\n\t * space already).\n\t */\n\tapply_cvt cvt x\n\t\t= cvt x, \n\t\t\tis_Image x || is_Colour x || is_image x\n\t\t= x;\n\n\tdiff cvt in1 in2 = abs_vec (apply_cvt cvt in1 - apply_cvt cvt in2);\n\n\t/* Converter to LAB.\n\t */\n\tlab_cvt = colour_transform_to Image_type.LAB;\n\n\t/* Converter to UCS ... plain UCS is Ch form, so we go LAB again after\n\t * to make sure we get a rectangular coord system.\n\t */\n\tucs_cvt = colour_transform Image_type.LCH Image_type.LAB @\n\t\tcolour_transform_to Image_type.UCS;\n\n\tCIEdE76_item = class\n\t\tMenuaction (_ \"CIE dE _76\") \n\t\t\t(_ \"calculate CIE dE 1976 for two objects\") {\n\t\taction a b = map_binary (diff lab_cvt) a b;\n\t}\n\n\tCIEdE00_item = class\n\t\tMenuaction (_ \"CIE dE _00\") \n\t\t\t(_ \"calculate CIE dE 2000 for two objects\") {\n\t\taction a b = map_binary \n\t\t\t(colour_binary (_ \"im_dE00_fromLab\") im_dE00_fromLab) a b;\n\t}\n\n\tUCS_item = class\n\t\tMenuaction (_ \"_CMC(l:l)\") (_ \"calculate CMC(l:l) for two objects\") {\n\t\taction a b = map_binary (diff ucs_cvt) a b;\n\t}\n}\n\nColour_adjust_item = class\n\tMenupullright (_ \"_Adjust\") (_ \"alter colours in various ways\") {\n\tRecombination_item = class\n\t\tMenuaction (_ \"_Recombination\") \n\t\t\t(_ \"recombine colour with an editable matrix\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix \n\t\t\t\t= Matrix_rec (identity_matrix (bands x))\n\t\t\t{\n\t\t\t\t// try to guess a sensible value for the size of the \n\t\t\t\t// matrix\n\t\t\t\tbands x\n\t\t\t\t\t= x.bands, is_Image x || is_Colour x\n\t\t\t\t\t= x.width, is_Matrix x \n\t\t\t\t\t= bands x.value?0, is_Group x\n\t\t\t\t\t= x.bands, has_member \"bands\" x\n\t\t\t\t\t= 3;\n\t\t\t}\n\n\t\t\t_result = map_unary (recomb matrix) x;\n\t\t}\n\t}\n\n\tCast_item = class\n\t\tMenuaction (_ \"_Cast\") (_ \"displace neutral axis in CIE Lab\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgr = Scale \"Green-red\" (-20) 20 0;\n\t\t\tby = Scale \"Blue-yellow\" (-20) 20 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_cast x\n\t\t\t{\n\t\t\t\tadjust_cast in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t\t\tin'' = in' + \n\t\t\t\t\t\tVector [0, gr.value, by.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHSB_item = class\n\t\tMenuaction (_ \"_HSB\") (_ \"adjust hue-saturation-brightness in LCh\") {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\th = Scale \"Hue\" 0 360 0;\n\t\t\ts = Scale \"Saturation\" 0.01 5 1;\n\t\t\tb = Scale \"Brightness\" 0.01 5 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary adjust_hsb x\n\t\t\t{\n\t\t\t\tadjust_hsb in\n\t\t\t\t\t= colour_transform_to (get_type in) in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LCH in;\n\t\t\t\t\tin'' = in' * Vector [b.value, s.value, 1] + \n\t\t\t\t\t\tVector [0, 0, h.value];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_similar_item = class\n\tMenuaction (_ \"_Similar Colour\") (_ \"find pixels with a similar colour\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttarget_colour = Colour_picker \"Lab\" [50, 0, 0];\n\t\tt = Scale \"dE threshold\" 0 100 10;\n\n\t\t_result\n\t\t\t= map_unary match x\n\t\t{\n\t\t\tmatch in \n\t\t\t\t= abs_vec (in' - target) < t\n\t\t\t{\n\t\t\t\ttarget = colour_transform_to Image_type.LAB target_colour;\n\t\t\t\tin' = colour_transform_to Image_type.LAB in;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nColour_chart_to_matrix_item = class\n\tMenuaction (_ \"_Measure Colour Chart\") \n\t\t(_ \"measure average pixel values for a colour chart image\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n        // get a representative image from an arg\n        get_image x\n            = get_image x.value?0, is_Group x\n            = x;\n\n        _im = get_image x; \n\t\tsample = measure_draw (to_real pacross) (to_real pdown) \n\t\t\t\t(to_real measure) _im;\n\n\t\t_result \n\t\t\t= map_unary chart x\n\t\t{\n\t\t\tchart in\n\t\t\t\t= measure_sample (to_real pacross) (to_real pdown) \n\t\t\t\t\t(to_real measure) in;\n\t\t}\n\t}\n}\n\nColour_matrix_to_chart_item = class\n\tMenuaction (_ \"Make Synth_etic Colour Chart\") \n\t\t(_ \"make a colour chart image from a matrix of measurements\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tpacross = Expression (_ \"Patches across chart\") 6;\n\t\tpdown = Expression (_ \"Patches down chart\") 4;\n\t\tpwidth = Expression (_ \"Patch width in pixels\") 50;\n\t\tpheight = Expression (_ \"Patch height in pixels\") 50;\n\t\tbwidth = Expression (_ \"Border between patches\") 0;\n\n\t\t_result \n\t\t\t= map_unary build_chart x\n\t\t{\n\t\t\tbuild_chart in\n\t\t\t\t= Image (imagearray_assemble \n\t\t\t\t\t(to_real bwidth) (to_real bwidth) patch_table)\n\t\t\t{\n\t\t\t\t// patch numbers for row starts\n\t\t\t\trowstart = map (multiply (to_real pacross)) \n\t\t\t\t\t[0 .. to_real pdown - 1];\n\n\t\t\t\t// assemble patches ... each one a pixel value\n\t\t\t\tpatches = map (take (to_real pacross)) \n\t\t\t\t\t(map (converse drop in.value) rowstart);\n\n\t\t\t\t// make an n-band constant image from eg. [1,2,3]\n\t\t\t\t// we don't know the format .. use sRGB (well, why not?)\n\t\t\t\tpatch v = image_new (to_real pwidth) (to_real pheight) (len v) \n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.sRGB (Vector v) 0 0;\n\n\t\t\t\t// make an image for each patch\n\t\t\t\tpatch_table = map (map patch) patches;\n\t\t\t}\n\t\t}\n\t}\n}\n\nColour_plot_ab_scatter_item = class\n\tMenuaction (_ \"_Plot ab Scatter\") (_ \"plot an ab scatter histogram\") {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbins = Expression (_ \"Number of bins on each axis\") 8;\n\n\t\t_result\n\t\t\t= map_unary plot_scatter x\n\t\t{\n\t\t\tplot_scatter in \n\t\t\t\t= Image (bg * (((90 / mx) * hist) ++ blk))\n\t\t\t{\n\t\t\t\tlab = colour_transform_to Image_type.LAB in.value;\n\t\t\t\tab = (unsigned char) ((lab?1 ++ lab?2) + 128);\n\t\t\t\thist = hist_find_nD bins.expr ab;\n\t\t\t\tmx = max hist;\n\t\t\t\tbg = lab_slice bins.expr 1;\n\t\t\t\tblk = 1 + im_black (to_real bins) (to_real bins) 2;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/start/Filter.def",
    "content": "Filter_conv_item = class\n\tMenupullright \"_Convolution\" \"various spatial convolution filters\" {\n\t/* Some useful masks.\n\t */\n\tfilter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];\n\tfilter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];\n\tfilter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];\n\tfilter_laplacian = Matrix_con 1 128 \n\t\t[[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];\n\tfilter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];\n\tfilter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];\n\n\tBlur_item = class\n\t\tMenuaction \"_Blur\" \"3x3 blur of image\" {\n\t\taction x = map_unary (conv filter_blur) x;\n\t}\n\n\tSharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"3x3 sharpen of image\" {\n\t\taction x = map_unary (conv filter_sharp) x;\n\t}\n\n\tUsharp_item = class\n\t\tMenuaction \"_Unsharp Mask\" \"cored sharpen of L only in LAB image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tsize = Option \"Radius\" [\n\t\t\t\t\"3 pixels\",\n\t\t\t\t\"5 pixels\",\n\t\t\t\t\"7 pixels\",\n\t\t\t\t\"9 pixels\",\n\t\t\t\t\"11 pixels\",\n\t\t\t\t\"51 pixels\"\n\t\t\t] 0;\n\t\n\t\t\tst = Scale \"Smoothness threshold\" 0 5 2;\n\t\t\tbm = Scale \"Brighten by at most\" 1 50 10;\n\t\t\tdm = Scale \"Darken by at most\" 1 50 20;\n\t\t\tfs = Scale \"Sharpen flat areas by\" 0 5 0.5;\n\t\t\tjs = Scale \"Sharpen jaggy areas by\" 0 5 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= Image in'''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.LABS in.value;\n\t\t\t\t\tin'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';\n\t\t\t\t\tin''' = colour_transform_to (get_type in) in'';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tEmboss_item = class\n\t\tMenuaction \"_Emboss\" \"1 pixel displace emboss\" {\n\t\taction x = map_unary (conv filter_emboss) x;\n\t}\n\n\tLaplacian_item = class\n\t\tMenuaction \"_Laplacian\" \"3x3 laplacian edge detect\" {\n\t\taction x = map_unary (conv filter_laplacian) x;\n\t}\n\n\tSobel_item = class\n\t\tMenuaction \"So_bel\" \"3x3 Sobel edge detect\" {\n\t\taction x = map_unary sobel x;\n\t}\n\n/* 3x3 line detect of image\ndiagonals should be scaled down by root(2) I guess\nKirk \n*/\n\tLinedet_item = class\n\t\tMenuaction \"Li_ne Detect\" \"3x3 line detect\" {\n\t\taction x \n\t\t\t= map_unary lindet x\n\t\t{\n\t\t\tlindet im\n\t\t\t\t= foldr1 max_pair images\n\t\t\t{\n\t\t\t\tmasks = take 4 (iterate rot45 filter_lindet);\n\t\t\t\timages = map (converse conv im) masks;\n\t\t\t}\n\t\t}\n\t}\n\n\tCanny_item = class\n\t\tMenuaction \"Canny\" \"Canny edge detector\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsigma = Scale \"Sigma\" 0.1 10 2;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\", \"Approximate\"] 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= canny sigma prec.value in;\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tCustom_blur_item = class\n\t\tMenuaction \"Custom B_lur / Sharpen\" \n\t\t\t\"blur or sharpen with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttype = Option \"Type\" [\"Blur\", \"Sharpen\"] 0;\n\t\t\tr = Scale \"Radius\" 1 100 1;\n\t\t\tfac = Scale \"Amount\" 0 1 1;\n\t\t\tlayers = Scale \"Layers\" 1 100 10;\n\t\t\tshape = Option \"Mask shape\" [\n\t\t\t\t\"Square\",\n\t\t\t\t\"Gaussian\"\n\t\t\t] 0;\n\t\t\tprec = Option \"Precision\" [\"Int\", \"Float\", \"Approximate\"] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= clip2fmt blur.format proc\n\t\t\t\t{\n\t\t\t\t\tmask\n\t\t\t\t\t\t= matrix_blur r.value, shape.value == 0\n\t\t\t\t\t\t= matrix_gaussian_blur r.value;\n\t\t\t\t\tblur = [convsep, convsepf, aconvsep layers]?prec mask in;\n\t\t\t\t\tproc\n\t\t\t\t\t\t= in + fac * (in - blur), type == 1\n\t\t\t\t\t\t= blur * fac + in * (1 - fac);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCustom_conv_item = class\n\t\tMenuaction \"Custom C_onvolution\" \n\t\t\t\"convolution filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmatrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t\t\tseparable \n\t\t\t\t= Toggle \"Seperable convolution\" false, \n\t\t\t\t\tmatrix.width == 1 || matrix.height == 1\n\t\t\t\t= false;\n\t\t\ttype = Option \"Convolution type\" [\"Int\", \"Float\"] 0;\n\t\t\trotate = Option \"Rotate\" [\n\t\t\t\t\"Don't rotate\", \n\t\t\t\t\"4 x 45 degrees\", \n\t\t\t\t\"8 x 45 degrees\", \n\t\t\t\t\"2 x 90 degrees\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= in.Image in'\n\t\t\t\t{\n\t\t\t\t\tconv_fn \n\t\t\t\t\t\t= im_lindetect, !separable && type == 0 && rotate == 1\n\t\t\t\t\t\t= im_compass, !separable && type == 0 && rotate == 2\n\t\t\t\t\t\t= im_gradient, !separable && type == 0 && rotate == 3\n\t\t\t\t\t\t= im_conv, !separable && type == 0\n\t\t\t\t\t\t= im_convsep, separable && type == 0\n\t\t\t\t\t\t= im_conv_f, !separable && type == 1\n\t\t\t\t\t\t= im_convsep_f, separable && type == 1\n\t\t\t\t\t\t= error \"boink!\";\n\t\t\t\t\tin' = conv_fn in.value matrix;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_rank_item = class\n\tMenupullright \"_Rank\" \"various rank filters\" {\n\tMedian_item = class\n\t\tMenuaction \"_Median\" \"3x3 median rank filter\" {\n\t\taction x = map_unary (rank 3 3 4) x;\n\t}\n\n\tImage_rank_item = class\n\t\tMenuaction \"_Image Rank\" \"pixelwise rank a list or group of images\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tselect \n\t\t\t\t= Expression \"Rank\" ((int) (guess_size / 2))\n\t\t\t{\n\t\t\t\tguess_size\n\t\t\t\t\t= len x, is_list x\n\t\t\t\t\t= len x.value, is_Group x\n\t\t\t\t\t= 0;\n\t\t\t}\n\n\t\t\t// can't really iterate over groups ... since we allow a group\n\t\t\t// argument\n\t\t\t_result = rank_image select x;\n\t\t}\n\t}\n\n\tCustom_rank_item = class\n\t\tMenuaction \"Custom _Rank\" \"rank filter with tuneable parameters\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twindow_width = Expression \"Window width\" 3;\n\t\t\twindow_height = Expression \"Window height\" 3;\n\t\t\tselect = Expression \"Rank\" \n\t\t\t\t((int) ((to_real window_width * to_real window_height) / 2));\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= rank window_width window_height select in;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_morphology_item = class\n\tMenupullright \"_Morphology\" \"various morphological filters\" {\n\t/* Some useful masks.\n\t */\n\tmask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];\n\tmask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];\n\tmask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\tthin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];\n\n\tThreshold_item = Select_item.Threshold_item;\n\n\tsep1 = Menuseparator;\n\n\tDilate_item = class\n\t\tMenupullright \"_Dilate\" \"morphological dilate\" {\n\t\tDilate8_item = class\n\t\t\tMenuaction \"_8-connected\" \"dilate with an 8-connected mask\" {\n\t\t\taction x = map_unary (dilate mask8) x;\n\t\t}\n\n\t\tDilate4_item = class\n\t\t\tMenuaction \"_4-connected\" \"dilate with a 4-connected mask\" {\n\t\t\taction x = map_unary (dilate mask4) x;\n\t\t}\n\t}\n\n\tErode_item = class\n\t\tMenupullright \"_Erode\" \"morphological erode\" {\n\t\tErode8_item = class\n\t\t\tMenuaction \"_8-connected\" \"erode with an 8-connected mask\" {\n\t\t\taction x = map_unary (erode mask8) x;\n\t\t}\n\n\t\tErode4_item = class\n\t\t\tMenuaction \"_4-connected\" \"erode with a 4-connected mask\" {\n\t\t\taction x = map_unary (erode mask4) x;\n\t\t}\n\t}\n\n\tCustom_morph_item = class\n\t\tMenuaction \"Custom _Morphology\" \n\t\t\t\"convolution morphological operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmask = mask4;\n\t\t\ttype = Option \"Operation\" [\"Erode\", \"Dilate\"] 1;\n\t\t\tapply = Expression \"Number of times to apply mask\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary morph x\n\t\t\t{\n\t\t\t\tmorph image\n\t\t\t\t\t= Image value'\n\t\t\t\t{\n\t\t\t\t\tfatmask = (iterate (dilate mask) mask)?(to_real apply - 1);\n\n\t\t\t\t\tvalue'\n\t\t\t\t\t\t= im_erode image.value fatmask, type.value == 0\n\t\t\t\t\t\t= im_dilate image.value fatmask;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tOpen_item = class\n\t\tMenuaction \"_Open\" \"open with an 8-connected mask\" {\n\t\taction x = map_unary (dilate mask8 @ erode mask8) x;\n\t}\n\n\tClose_item = class\n\t\tMenuaction \"_Close\" \"close with an 8-connected mask\" {\n\t\taction x = map_unary (erode mask8 @ dilate mask8) x;\n\t}\n\n\tClean_item = class\n\t\tMenuaction \"C_lean\" \"remove 8-connected isolated points\" {\n\t\taction x \n\t\t\t= map_unary clean x\n\t\t{\n\t\t\tclean x = x ^ erode mask1 x;\n\t\t}\n\t}\n\n\tThin_item = class\n\t\tMenuaction \"_Thin\" \"thin once\" {\n\t\taction x \n\t\t\t= map_unary thinall x\n\t\t{\n\t\t\tmasks = take 8 (iterate rot45 thin);\n\t\t\tthin1 m x = x ^ erode m x;\n\t\t\tthinall x = foldr thin1 x masks;\n\t\t}\n\t}\n\n}\n\nFilter_fourier_item = class\n\tMenupullright \"_Fourier\" \"various Fourier filters\" {\n\tpreview_size = 64;\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\t// make a visualisation image \n\tmake_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t(im_create_fmask preview_size preview_size);\n\n\t// make the process function\n\tprocess fn in\n\t\t= (Image @ fn) (im_flt_image_freq in.value);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal\" \"various ideal Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f sense.value fc.value 0 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 6) fc.value \n\t\t\t\t\trw.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject ideal Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\tr.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian\" \"various Gaussian Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 4) fc.value \n\t\t\t\t\tac.value 0 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 10) fc.value \n\t\t\t\t\trw.value ac.value 0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Gaussian Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 16) fcx.value fcy.value \n\t\t\t\t\tr.value ac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth\" \n\t\t\t\"various Butterworth Fourier filters\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t\"highpass/lowpass Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 2) o.value fc.value ac.value\n\t\t\t\t\t\t0 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t\"ring pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 8) o.value fc.value rw.value \n\t\t\t\t\tac.value 0;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t\"band pass/reject Butterworth Fourier filter\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\to = Scale \"Order\" 1 10 2;\n\n\t\t\t\t// call a freq func with our parameters\n\t\t\t\t_params f = f (sense.value + 14) o.value fcx.value fcy.value\n\t\t\t\t\t\tr.value ac.value;\n\n\t\t\t\tvisualize_mask = make_vis _params;\n\n\t\t\t\t_result = map_unary (process _params) x;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_enhance_item = class\n\tMenupullright \"_Enhance\" \"various enhancement filters\" {\n\tFalsecolour_item = class\n\t\tMenuaction \"_False Colour\" \"false colour a mono image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\to = Scale \"Offset\" (-255) 255 0;\n\t\t\tclip = Toggle \"Clip colour range\" false;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= falsecolour mono''\n\t\t\t\t{\n\t\t\t\t\tmono = colour_transform_to Image_type.B_W im;\n\t\t\t\t\tmono' = mono + o;\n\t\t\t\t\tmono'' \n\t\t\t\t\t\t= (unsigned char) mono', clip\n\t\t\t\t\t\t= (unsigned char) (mono' & 0xff);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tStatistical_diff_item = class\n\t\tMenuaction \"_Statistical Difference\" \n\t\t\t\"statistical difference of an image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\twsize = Expression \"Window size\" 11;\n\t\t\ttmean = Expression \"Target mean\" 128;\n\t\t\tmean_weight = Scale \"Mean weight\" 0 1 0.8;\n\t\t\ttdev = Expression \"Target deviation\" 50;\n\t\t\tdev_weight = Scale \"Deviation weight\" 0 1 0.8;\n\t\t\tborder = Toggle \"Output image matches input image in size\" true;\n\t\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in \n\t\t\t\t\t= Image in''\n\t\t\t\t{\n\t\t\t\t\tin' = colour_transform_to Image_type.B_W in.value;\n\t\t\t\t\tfn\n\t\t\t\t\t\t= im_stdif, border\n\t\t\t\t\t\t= im_stdif_raw;\n\t\t\t\t\tin'' = fn in'\n\t\t\t\t\t\tmean_weight.value tmean.expr\n\t\t\t\t\t\tdev_weight.value tdev.expr\n\t\t\t\t\t\twsize.expr wsize.expr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tHist_equal_item = class\n\t\tMenupullright \"_Equalise Histogram\" \"equalise contrast\" {\n\t\tGlobal_item = class\n\t\t\tMenuaction \"_Global\" \"equalise contrast globally\" {\n\t\t\taction x = map_unary hist_equalize x;\n\t\t}\n\n\t\tLocal_item = class\n\t\t\tMenuaction \"_Local\" \"equalise contrast within a roving window\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\twindow_width = Expression \"Window width\" 20;\n\t\t\t\twindow_height = Expression \"Window height\" 20;\n\t\t\t\tmax_slope = Scale \"Maxium slope\" 0 10 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess in \n\t\t\t\t\t\t= hist_equalize_local \n\t\t\t\t\t\t\twindow_width \n\t\t\t\t\t\t\twindow_height \n\t\t\t\t\t\t\tmax_slope in;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_correlate_item = class\n\tMenupullright \"Spatial _Correlation\" \"calculate correlation surfaces\" {\n\tCorrelate_item = class\n\t\tMenuaction \"_Correlate\" \"calculate correlation coefficient\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate b a;\n\t\t}\n\t}\n\n\tCorrelate_fast_item = class\n\t\tMenuaction \"_Simple Difference\" \n\t\t\t\"calculate sum of squares of differences\" {\n\t\taction a b \n\t\t\t= map_binary corr a b\n\t\t{\n\t\t\tcorr a b\n\t\t\t\t= correlate_fast a b, \n\t\t\t\t\ta.width <= b.width && a.height <= b.height\n\t\t\t\t= correlate_fast b a;\n\t\t}\n\t}\n}\n\nFilter_hough_item = class\n\tMenupullright \"_Hough Transform\" \"transform to parameter space\" {\n\tLine_item = class\n\t\tMenuaction \"_Line\" \"find straight line Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpspace_width = Expression \"Parameter space width\" 64;\n\t\t\tpspace_height = Expression \"Parameter space height\" 64;\n\n\t\t\t_result \n\t\t\t\t= map_unary line a \n\t\t\t{\n\t\t\t\tline a \n\t\t\t\t\t= hough_line \n\t\t\t\t\t\t(to_real pspace_width) (to_real pspace_height) a;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class\n\t\tMenuaction \"_Circle\" \"find circle Hough transform\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Expression \"Scale down parameter space by\" 10;\n\t\t\tmin_radius = Expression \"Minimum radius\" 10;\n\t\t\tmax_radius = Expression \"Maximum radius\" 30;\n\n\t\t\t_result \n\t\t\t\t= map_unary circle a \n\t\t\t{\n\t\t\t\tcircle a \n\t\t\t\t\t= hough_circle (to_real scale) (to_real min_radius)\n\t\t\t\t\t\t(to_real max_radius) a;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_coordinate_item = class\n\tMenupullright \"_Coordinate Transform\" \"various coordinate transforms\" {\n\t// run a function which wants a complex arg on a non-complex two-band\n\t// image\n\trun_cmplx fn x\n\t\t= re x' ++ im x'\n\t{\n\t\tx' = fn (x?0, x?1);\n\t}\n\n\tPolar_item = class\n\t\tMenuaction \"_Polar\" \"transform to polar coordinates\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result \n\t\t\t\t= map_unary to_polar a \n\t\t\t{\n\t\t\t\tto_polar im \n\t\t\t\t\t= mapim interp.value map' im\n\t\t\t\t{\n\t\t\t\t\t// xy image, origin in the centre, scaled to fit image to\n\t\t\t\t\t// a circle\n\t\t\t\t\txy = make_xy im.width im.height;\n\t\t\t\t\txy' = xy - Vector [im.width / 2, im.height / 2];\n\t\t\t\t\tscale = min [im.width, im.height] / im.width;\n\t\t\t\t\txy'' = 2 * xy' / scale;\n\n\t\t\t\t\t// to polar, scale vertical axis to 360 degrees\n\t\t\t\t\tmap = run_cmplx polar xy'';\n\t\t\t\t\tmap' = map * Vector [1, im.height / 360];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tRectangular_item = class\n\t\tMenuaction \"_Rectangular\" \"transform to rectangular coordinates\" {\n\t\taction a = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result \n\t\t\t\t= map_unary to_rect a \n\t\t\t{\n\t\t\t\tto_rect im \n\t\t\t\t\t= mapim interp.value map'' im\n\t\t\t\t{\n\t\t\t\t\t// xy image, vertical scaled to 360 degrees\n\t\t\t\t\txy = make_xy im.width im.height;\n\t\t\t\t\txy' = xy * Vector [1, 360 / im.height];\n\n\t\t\t\t\t// to rect, scale to image rect\n\t\t\t\t\tmap = run_cmplx rectangular xy';\n\t\t\t\t\tscale = min [im.width, im.height] / im.width;\n\t\t\t\t\tmap' = map * scale / 2;\n\n\t\t\t\t\tmap'' = map' + Vector [im.width / 2, im.height / 2];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_tilt_item = class\n\tMenupullright \"Ti_lt Brightness\" \"tilt brightness\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"linear left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height;\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"linear top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 \n\t\t\t\t\t\t(im_fgrey image.height image.width);\n\t\t\t\t\tscale = (ramp - 0.5) * tilt + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tLeft_right_cos_item = class\n\t\tMenuaction \"Cosine Left-_right\" \"cosine left-right brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Left-right tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t\t= map_unary tilt_lr x\n\t\t\t{\n\t\t\t\ttilt_lr image\n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTop_bottom_cos_item = class\n\t\tMenuaction \"Cosine Top-_bottom\" \"cosine top-bottom brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Top-bottom tilt\" (-1) 1 0;\n\t\t\tshift = Scale \"Shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\tramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\t\tshift.value;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCircular_item = class\n\t\tMenuaction \"_Circular\" \"circular brighten\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttilt = Scale \"Tilt\" (-1) 1 0;\n\t\t\thshift = Scale \"Horizontal shift by\" (-1) 1 0;\n\t\t\tvshift = Scale \"Vertical shift by\" (-1) 1 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary tilt_tb x\n\t\t\t{\n\t\t\t\ttilt_tb image \n\t\t\t\t\t= image * scale\n\t\t\t\t{\n\t\t\t\t\thramp = im_fgrey image.width image.height - 0.5 -\n\t\t\t\t\t\thshift.value;\n\t\t\t\t\tvramp = rot90 (im_fgrey image.height image.width) - 0.5 -\n\t\t\t\t\t\tvshift.value;\n\t\t\t\t\tramp = (hramp ** 2 + vramp ** 2) ** 0.5;\n\t\t\t\t\tscale = 0.5 * tilt.value * cos (ramp * 180) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_blend_item = class\n\tMenupullright \"_Blend\" \"blend objects together\" {\n\tScale_blend_item = class\n\t\tMenuaction \"_Scale\" \"blend two objects together with a scale\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tp = Scale \"Blend position\" 0 1 0.5;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess im1 im2 = im1 * (1 - p.value) + im2 * p.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_blend_item = class\n\t\tMenuaction \"_Image\" \"use an image to blend two objects\" {\n\t\taction a b c = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ti = Toggle \"Invert mask\" false;\n\n\t\t\t_result \n\t\t\t\t= map_trinary process a b c\n\t\t\t{\n\t\t\t\tprocess a b c \n\t\t\t\t\t= blend condition in1 in2, !i\n\t\t\t\t\t= blend (invert condition) in1 in2\n\t\t\t\t{\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t// prefer image as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!has_image a && has_image b\n\t\t\t\t\t\t// prefer mono images as the condition\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\thas_bands a && has_bands b && \n\t\t\t\t\t\t\tget_bands a > 1 && get_bands b == 1\n\t\t\t\t\t\t// prefer uchar as the condition\n\t\t\t\t\t\t= false,\n\t\t\t\t\t\t\thas_format a && has_format b && \n\t\t\t\t\t\t\tget_format a > Image_format.UCHAR && \n\t\t\t\t\t\t\t\tget_format b == Image_format.UCHAR\n\t\t\t\t\t\t= true;\n\t\t\t\t\t[condition, in1, in2] = sortc compare [a, b, c];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tLine_blend_item = class\n\t\tMenuaction \"_Along Line\" \n\t\t\t\"blend between image a and image b along a line\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Left to Right\",\n\t\t\t\t\"Top to Bottom\"\n\t\t\t] 0;\n\t\t\tblend_position = Scale \"Blend position\" 0 1 0.5;\n\t\t\tblend_width = Scale \"Blend width\" 0 1 0.05;\n\n\t\t\t_result\n\t\t\t\t= map_binary process a b\n            {\n                process a b \n\t\t\t\t\t= blend (Image condition) b a\n                {\n\t\t\t\t\toutput_width = max_pair a.width b.width;\n\t\t\t\t\toutput_height = max_pair a.height b.height;\n\t\t\t\t\trange\n\t\t\t\t\t\t= output_width, orientation == 0\n\t\t\t\t\t\t= output_height;\n\t\t\t\t\tblend_position' \n\t\t\t\t\t\t= floor (range * blend_position.value);\n\t\t\t\t\tblend_width' \n\t\t\t\t\t\t= 1, blend_width.value == 0\n\t\t\t\t\t\t= floor (range * blend_width.value);\n                   \tstart = blend_position' - blend_width' / 2;\n\n\t\t\t\t\tbackground = (make_xy output_width output_height) >= \n\t\t\t\t\t\tblend_position';\n                   \tramp \n\t\t\t\t\t\t= im_grey blend_width' output_height, orientation == 0\n                        = rot90 (im_grey blend_width' output_width);\n\t\t\t\t\tcondition \n\t\t\t\t\t\t= insert_noexpand start 0 ramp background?0, \n\t\t\t\t\t\t\torientation == 0\n\t\t\t\t\t\t= insert_noexpand 0 start ramp background?1;\n               \t}\n\t\t\t}\n\t\t}\n\t} \n\n\tBlend_alpha_item = class\n\t\tMenuaction \"Blend _Alpha\" \"blend images with optional alpha channels\" {\n\t\t// usage: layerit foreground background\n\t\t// input images must be either 1 or 3 bands, optionally + 1 band \n\t\t// which is used as the alpha channel\n\t\t// rich lott\n\t\n\t\tscale_mask im opacity\n\t\t\t= (unsigned char) (to_real opacity / 255 * im);\n\t\n\t\t// to mono\n\t\tintensity = colour_transform_to Image_type.B_W;\n\t\n\t\t// All the blend functions\n\t\t// I am grateful to this page\n\t\t// http://www.pegtop.net/delphi/blendmodes/\n\t\t// for most of the formulae.\n\t\n\t\tblend_normal mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg bg;\n\t\n\t\tblend_iflighter mask opacity fg bg\n\t\t\t= blend (if fg' > bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg;\n\t\t\tbg' = intensity bg;\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_ifdarker mask opacity fg bg\n\t\t\t= blend (if fg' < bg' then mask' else 0) fg bg\n\t\t{ \n\t\t\tfg' = intensity fg ;\n\t\t\tbg' = intensity bg ;\t\n\t\t\tmask' = scale_mask mask opacity ;\n\t\t}\n\t\n\t\tblend_multiply mask opacity fg bg\n\t\t\t= blend (scale_mask mask opacity) fg' bg\n\t\t{\n\t\t\tfg' = fg / 255 * bg;\n\t\t}\n\t\n\t\tblend_add mask opacity fg bg\n\t\t\t= blend mask fg' bg\t\t\n\t\t{\n\t\t\tfg' = opacity / 255 * fg + bg;\n\t\t}\n\t\n\t\tblend_subtract mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = bg - opacity / 255 * fg;\n\t\t}\n\t\n\t\tblend_screen mask opacity fg bg\n\t\t\t= blend mask fg' bg \n\t\t{\n\t\t\tfg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;\n\t\t}\n\t\n\t\tblend_burn mask opacity fg bg\n\t\t\t= blend mask fg'' bg\n\t\t{\n\t\t\t// fades to white which has no effect.\n\t\t\tfg' = (255 - opacity) + opacity * fg / 255;\n\t\t\tfg'' = 255 - 255 * (255 - bg) / fg';\n\t\t}\n\t\n\t\tblend_softlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;\n\t\t}\n\t\n\t\tblend_hardlight mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg'\n\t\t\t\t= 2 / 255 * fg * bg, bg < 129\n\t\t\t\t= 255 - 2 * (255 - bg) * (255 - fg) / 255;\n\t\t}\n\t\n\t\tblend_lighten mask opacity fg bg\n\t\t\t= blend mask' fg' bg \t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg < fg then fg else bg;\n\t\t}\n\t\n\t\tblend_darken mask opacity fg bg\n\t\t\t= blend mask' fg' bg\t\t\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = if bg > fg then fg else bg;\n\t\t}\n\t\n\t\tblend_dodge mask opacity fg bg\n\t\t\t= blend mask fg'' bg \n\t\t{\n\t\t\t// one added to avoid divide by zero\n\t\t\tfg' = 1 + 255 - (opacity / 255 * fg); \n\t\t\tfg'' = bg * 255 / fg';\n\t\t}\n\t\n\t\tblend_reflect mask opacity fg bg\n\t\t\t= blend mask' fg' bg \n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = bg * bg / (255 - fg);\n\t\t}\n\t\n\t\tblend_freeze mask opacity fg bg\n\t\t\t= blend mask' fg' bg\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);\n\t\t}\n\t\n\t\tblend_or mask opacity fg bg\n\t\t\t= bg | (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\tblend_and mask opacity fg bg\n\t\t\t= bg & (unsigned char) fg'\n\t\t{\n\t\t\tmask' = scale_mask mask opacity;\n\t\t\tfg' = fg * mask' / 255;\n\t\t}\n\t\n\t\t// blend types\n\t\tNORMAL = 0;\n\t\tIFLIGHTER = 1;\n\t\tIFDARKER = 2;\n\t\tMULTIPLY = 3;\n\t\tADD = 4;\n\t\tSUBTRACT = 5;\n\t\tSCREEN = 6;\n\t\tBURN = 7;\n\t\tDODGE = 8;\n\t\tHARDLIGHT = 9;\n\t\tSOFTLIGHT = 10;\n\t\tLIGHTEN = 11;\n\t\tDARKEN = 12;\n\t\tREFLECT = 13;\n\t\tFREEZE = 14;\n\t\tOR = 15;\n\t\tAND = 16;\n\n\t\t// names we show the user for blend types\n\t\tnames = Enum [\n\t\t\t_ \"Normal\" => NORMAL,\n\t\t\t_ \"If Lighter\" => IFLIGHTER,\n\t\t\t_ \"If Darker\" => IFDARKER,\n\t\t\t_ \"Multiply\" => MULTIPLY,\n\t\t\t_ \"Add\" => ADD,\n\t\t\t_ \"Subtract\" => SUBTRACT,\n\t\t\t_ \"Screen\" => SCREEN,\n\t\t\t_ \"Burn\" => BURN,\n\t\t\t_ \"Soft Light\" => SOFTLIGHT,\n\t\t\t_ \"Hard Light\" => HARDLIGHT,\n\t\t\t_ \"Lighten\" => LIGHTEN,\n\t\t\t_ \"Darken\" => DARKEN,\n\t\t\t_ \"Dodge\" => DODGE,\n\t\t\t_ \"Reflect\" => REFLECT,\n\t\t\t_ \"Freeze\" => FREEZE,\n\t\t\t_ \"Bitwise OR\" => OR,\n\t\t\t_ \"Bitwise AND\" => AND\n\t\t];\n\n\t\t// functions we call for each blend type\n\t\tactions = Table [\n\t\t\t[NORMAL, blend_normal],\n\t\t\t[IFLIGHTER, blend_iflighter],\n\t\t\t[IFDARKER, blend_ifdarker],\n\t\t\t[MULTIPLY, blend_multiply],\n\t\t\t[ADD, blend_add],\n\t\t\t[SUBTRACT, blend_subtract],\n\t\t\t[SCREEN, blend_screen],\n\t\t\t[BURN, blend_burn],\n\t\t\t[SOFTLIGHT, blend_softlight],\n\t\t\t[HARDLIGHT, blend_hardlight],\n\t\t\t[LIGHTEN, blend_lighten],\n\t\t\t[DARKEN, blend_darken],\n\t\t\t[DODGE, blend_dodge],\n\t\t\t[REFLECT, blend_reflect],\n\t\t\t[FREEZE, blend_freeze],\n\t\t\t[OR, blend_or],\n\t\t\t[AND, blend_and]\n\t\t];\n\t\n\t\t// make sure im has an alpha channel (set opaque if it hasn't)\n\t\tput_alpha im\n\t\t\t= im, im.bands == 4 || im.bands == 2 \n\t\t\t= im ++ 255;\n\t\n\t\t// make sure im has no alpha channel \n\t\tlose_alpha im\n\t\t\t= extract_bands 0 3 im, im.bands == 4 \n\t\t\t= im?0, im.bands == 2 \n\t\t\t= im;\n\t\n\t\t// does im have al alpha channel?\n\t\thas_alpha im = im.bands == 2 || im.bands == 4;\n\t\n\t\t// get the alpha (set opaque if no alpha)\n\t\tget_alpha img\n\t\t\t= img'?3, img.bands == 4 \n\t\t\t= img'?1\n\t\t{\n\t\t\timg' = put_alpha img;\n\t\t}\n\t\n\t\t// add an alpha ... cast the alpha image to match the main image\n\t\tappend_alpha im alpha\n\t\t\t= im ++ clip2fmt im.format alpha;\n\t\n\t\t// makes fg the same size as bg, displaced with u, v pixel offset\n\t\tmoveit fg bg u v\n\t\t\t= insert_noexpand u v fg bg'\n\t\t{\n\t\t\tbg' = image_new bg.width bg.height \n\t\t\t\tfg.bands fg.format fg.coding fg.type 0 0 0;\n\t\t}\n\t\n\t\taction bg fg = class \n\t\t\t_value {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tmethod = Option_enum \"Blend mode\" names \"Normal\";\n\t\t\topacity = Scale \"Opacity\" 0 255 255;\n\t\t\thmove = Scale \"Horizontal move by\" (-bg.width) (bg.width) 0; \n\t\t\tvmove = Scale \"Vertical move by\" (-bg.height) (bg.height) 0; \t\t\n\t\n\t\t\t_value\n\t\t\t\t= append_alpha blended merged_alpha, has_alpha bg\n\t\t\t\t= blended \n\t\t\t{\n\t\t\t\t// displace and resize fg (need to displace alpha too)\n\t\t\t\tfg' = moveit (put_alpha fg) bg hmove vmove;\n\t\n\t\t\t\t// transform to sRGB\n\t\t\t\tfg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');\n\t\t\t\tbg' = colour_transform_to Image_type.sRGB (lose_alpha bg);\n\t\n\t\t\t\t// alphas merged\n\t\t\t\tmerged_alpha = get_alpha bg | get_alpha fg';\n\t\n\t\t\t\t// blend together\n\t\t\t\tblended = (actions.lookup 0 1 method.value_thing) \n\t\t\t\t\t(get_alpha fg') opacity.value fg'' bg';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_overlay_header_item = class\n\tMenuaction \"_Overlay\" \n\t\t\"make a colour overlay of two monochrome images\" {\n\taction  a b = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour = Option \"Colour overlay as\" [\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n\t\t_result\n\t\t\t= map_binary overlay a b\n\t\t{\n\t\t\toverlay a b\n\t\t\t\t= image_set_type Image_type.sRGB \n\t\t\t\t\t[(a' ++ b' ++ 0), \n\t\t\t\t\t\t(a' ++ 0 ++ b'), \n\t\t\t\t\t\t(b' ++ a' ++ 0), \n\t\t\t\t\t\t(b' ++ 0 ++ a'), \n\t\t\t\t\t\t(0 ++ a' ++ b'), \n\t\t\t\t\t\t(0 ++ b' ++ a')]?colour\n\t\t\t{\n\t\t\t\ta' = colour_transform_to Image_type.B_W a;\n\t\t\t\tb' = colour_transform_to Image_type.B_W b;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_colourize_item = class \n\tMenuaction \"_Colourize\" \"use a colour image or patch to tint a mono image\" {\n\taction a b = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttint = Scale \"Tint\" 0 1 0.6;\n\n\t\t_result\n\t\t\t= map_binary tintit a b\n\t\t{\n\t\t\ttintit a b\n\t\t\t\t= colour_transform_to (get_type colour) colourized'\n\t\t\t{\n\t\t\t\t// get the mono thing first\n\t\t\t\t[mono, colour] = \n\t\t\t\t\tsortc (const (is_colour_type @ get_type)) [a, b];\n\n\t\t\t\tcolour' = tint * colour_transform_to Image_type.LAB colour;\n\t\t\t\tmono' = colour_transform_to Image_type.B_W mono;\n\t\t\t\tcolourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;\n\t\t\t\tcolourized' = image_set_type Image_type.LAB colourized;\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_browse_multiband_item = class \n\tMenupullright \"Bro_wse\" \"browse though an image, bitwise or bandwise\" {\n\tBandwise_item = class\n\t\tMenuaction \"B_andwise\" \"browse through the bands of a multiband image\" {\n\t\taction image = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tband = Scale \"Band\" 0 (image.bands - 1) 0;\n       \t\tdisplay = Option \"Display as\" [\n\t\t\t_ \"Grey\",\n\t\t\t_ \"Green over Red\",\n\t\t\t_ \"Blue over Red\",\n\t\t\t_ \"Red over Green\",\n\t\t\t_ \"Red over Blue\",\n\t\t\t_ \"Blue over Green\",\n\t\t\t_ \"Green over Blue\"\n\t\t] 0;\n\n        \t_result \n\t\t\t\t= output\n\t\t\t{\n\t\t\t\tdown = (int) band.value;\n\t\t\t\tup = down + 1;\n\t\t\t\tremainder = band.value - down;\n\n\t\t\t\tfade x a\n\t\t\t\t\t= Vector [0], x == 0\n\t\t\t\t\t= a * x;\n\n\t\t\t\ta = fade remainder image?up;\n\t\t\t\tb = fade (1 - remainder) image?down;\n\n\t\t\t\toutput = [\n\t\t\t\t\ta + b, \n\t\t\t\t\ta ++ b ++ 0, \n\t\t\t\t\ta ++ 0 ++ b, \n\t\t\t\t\tb ++ a ++ 0,\n\t\t\t\t\tb ++ 0 ++ a, \n\t\t\t\t\t0 ++ a ++ b, \n\t\t\t\t\t0 ++ b ++ a\n\t\t\t\t] ? display;\n\t\t\t}\n\t\t}\n\t}\n\n\tBitwise_item = class\n\t\tMenuaction \"Bi_twise\" \"browse through the bits of an image\" {\n\t\taction x = class  \n        \t_result {\n\t\t\t_vislevel = 3;\n\n        \tbit \n\t\t\t\t= Islider \"Bit\" 0 (nbits - 1) (nbits - 1)\n\t\t\t{\n\t\t\t\tnbits \n\t\t\t\t\t= x.bits, is_Image x\n\t\t\t\t\t= 8;\n\t\t\t\tIslider c f t v = class \n\t\t\t\t\tscope.Scale c f t ((int) v) {\n\t\t\t\t\tScale = Islider;\n\t\t\t\t}\n\t\t\t}\n\n        \t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im = (im & (0x1 << bit.value)) != 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nFilter_negative_item = class\n\tMenuaction \"Photographic _Negative\" \"swap black and white\" {\n\taction x \n\t\t= map_unary invert x\n\t{\n\t\tinvert in\n\t\t\t= clip2fmt in.format (colour_transform_to (get_type in) rgb')\n\t\t{\n\t\t\trgb = colour_transform_to Image_type.sRGB in;\n\t\t\trgb' = 255 - rgb;\n\t\t}\n\t}\n}\n\nFilter_solarize_item = class\n\tMenuaction \"_Solarise\" \"invert colours above a threshold\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tkink = Scale \"Kink\" 0 1 0.5;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= hist_map tab'''' image\n\t\t\t{\n\t\t\t\t// max pixel value for this format\n\t\t\t\tmx = Image_format.maxval image.format;\n\n\t\t\t\t// make a LUT ... just 8 and 16 bit\n\t\t\t\ttab \n\t\t\t\t\t= im_identity_ushort image.bands mx,\n\t\t\t\t\t\timage.format == \n\t\t\t\t\t\t\tImage_format.USHORT\n\t\t\t\t\t= im_identity image.bands;\n\t\t\t\ttab' = Image tab;\n\n\t\t\t\t// make basic ^ shape\n\t\t\t\ttab'' \n\t\t\t\t\t= tab' * (1 / kink), tab' < mx * kink\n\t\t\t\t\t= (mx - tab') / (1 - kink);\n\t\t\t\ttab''' = clip2fmt image.format tab'';\n\n\t\t\t\t// smooth a bit\n\t\t\t\tmask = matrix_blur (tab'''.width / 8);\n\t\t\t\ttab'''' = convsep mask tab''';\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_diffuse_glow_item = class\n\tMenuaction \"_Diffuse Glow\" \"add a halo to highlights\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tr = Scale \"Radius\" 0 50 5;\n\t\thighlights = Scale \"Highlights\" 0 100 95;\n\t\tglow = Scale \"Glow\" 0 1 0.5;\n\t\tcolour = Colour_new_item.Widget_colour_item.action;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= image'\n\t\t\t{\n\t\t\t\tmono = (unsigned char) (colour_transform_to \n\t\t\t\t\tImage_type.B_W image);\n\t\t\t\tthresh = hist_thresh (highlights.value / 100) mono;\n\t\t\t\tmask = mono > thresh;\n\t\t\t\tblur = convsep (matrix_gaussian_blur r.value) mask;\n\t\t\t\tcolour' = colour_transform_to image.type colour;\n\t\t\t\timage' = image + colour' * glow * (blur / 255);\n\t\t\t}\n\t\t}\n\t}\n}\n\nFilter_drop_shadow_item = class\n\tMenuaction \"Drop S_hadow\" \"add a drop shadow to an image\" {\n\taction x = class\n        _result {\n        _vislevel = 3;\n\n        sx = Scale \"Horizontal shadow\" (-50) 50 5;\n        sy = Scale \"Vertical shadow\" (-50) 50 5;\n        ss = Scale \"Shadow softness\" 0 20 5;\n        bg_colour = Expression \"Background colour\" 255;\n        sd_colour = Expression \"Shadow colour\" 128;\n        alpha = Toggle \"Shadow in alpha channel\" false;\n        transparent = Toggle \"Zero pixels are transparent\" false;\n\n        _result\n            = map_unary shadow x\n        {\n            shadow image\n            \t= Image final\n            {\n                blur_size = ss.value * 2 + 1;\n\n                // matrix we blur with to soften shadows\n                blur_matrix = matrix_gaussian_blur blur_size;\n                matrix_size = blur_matrix.width;\n                matrix_radius = (int) (matrix_size / 2) + 1;\n\n                // position and size of shadow image in input cods\n                // before and after fuzzing\n                shadow_rect = Rect sx.value sy.value \n\t\t\t\t\timage.width image.height;\n                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;\n\n                // size and pos of final image, in input cods\n                final_rect = image.rect.union fuzzy_shadow_rect;\n\n                // hard part of shadow in output cods\n                shadow_rect' = Rect \n                    (shadow_rect.left - final_rect.left)\n                    (shadow_rect.top - final_rect.top)\n                    shadow_rect.width shadow_rect.height;\n\n                // make the shadow mask ... true for parts which cast\n                // a shadow\n                mask \n                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), \n                \t\ttransparent\n                    = image_new image.width image.height 1 Image_format.UCHAR\n                        Image_coding.NOCODING Image_type.B_W 255 0 0;\n                mask' = embed 0 shadow_rect'.left shadow_rect'.top\n                        final_rect.width final_rect.height mask;\n\t\t\t\tmask'' = convsep blur_matrix mask';\n\n                // use mask to fade between bg and shadow colour\n                mk_background colour = image_new \n                \tfinal_rect.width final_rect.height\n                    image.bands image.format image.coding image.type\n                    colour 0 0;\n\n                bg_image = mk_background bg_colour.expr;\n                shadow_image = mk_background sd_colour.expr;\n                bg = blend mask'' shadow_image bg_image;\n\n                // make a full size mask \n                fg_mask = embed 0\n                    (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    final_rect.width final_rect.height mask;\n\n                // wrap up the input image ... put the shadow colour\n                // around it, so if we are outputting a separate\n                // alpha the shadow colour will be set correctly\n                fg = insert (image.rect.left - final_rect.left)\n                    (image.rect.top - final_rect.top)\n                    image.value shadow_image;\n\n                final\n                    // make a separate alpha\n                    = fg ++ mask'', alpha\n\n                    // paste image over shadow\n                    = if fg_mask then fg else bg;\n            }\n        }\n    }\n}\n\nFilter_paint_text_item = class \n\tMenuaction \"_Paint Text\" \"paint text into an image\" {\n\taction x \n\t\t= paint_position, is_Group x\n\t\t= paint_area\n\t{\n\t\tpaint_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[x, \"x\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\t\t\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\talign = Option \"Alignment\" [\"Left\", \"Centre\", \"Right\"] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tplace = Region x (x.width / 4) (x.height / 4) \n\t\t\t\t(x.width / 2) (x.height / 2);\n\t\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top (blend txt' fg place) x\n\t\t\t{\n\t\t\t\tfg = image_new place.width place.height x.bands x.format \n\t\t\t\t\tx.coding x.type colour.expr 0 0;\n\t\t\t\ttxt = Image (im_text text.value font.value \n\t\t\t\t\tplace.width align.value (to_real dpi));\n\t            bg = im_black place.width place.height 1;\n\t\t\t\ttxt' = insert_noexpand 0 0 txt bg;\n\t\t\t}\n\t\t}\n\t\n\t\tpaint_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttext = Pattern_images_item.Text_item.action;\n\t\t\tcolour = Expression \"Text colour\" 255;\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t_ \"North-west\",\n\t\t\t\t_ \"North\",\n\t\t\t\t_ \"North-east\",\n\t\t\t\t_ \"West\",\n\t\t\t\t_ \"Centre\",\n\t\t\t\t_ \"East\",\n\t\t\t\t_ \"South-west\",\n\t\t\t\t_ \"South\",\n\t\t\t\t_ \"South-east\",\n\t\t\t\t_ \"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary paint x\n\t\t\t{\n\t\t\t\tpaint image\n\t\t\t\t\t= insert_noexpand x' y' place' image\n\t\t\t\t{\n\t\t\t\t\txr = image.width - text.width;\n\t\t\t\t\tyr = image.height - text.height;\n\t\t\t\t\tx \n\t\t\t\t\t\t= left.expr, position == 9\n\t\t\t\t\t\t= [0, xr / 2, xr]?(position % 3);\n\t\t\t\t\ty\n\t\t\t\t\t\t= top.expr, position == 9\n\t\t\t\t\t\t= [0, yr / 2, yr]?(position / 3);\n\t\t\t\t\tx' = range 0 x (image.width - 1);\n\t\t\t\t\ty' = range 0 y (image.height - 1);\n\t\t\t\t\tw' = range 1 text.width (image.width - x');\n\t\t\t\t\th' = range 1 text.height (image.height - y');\n\t\n\t\t\t\t\tplace = extract_area x' y' w' h' image;\n\t\t\t\t\ttext' = insert_noexpand 0 0 text (im_black w' h' 1);\n\t\t\t\t\tfg = image_new w' h' image.bands image.format \n\t\t\t\t\t\timage.coding image.type colour.expr 0 0;\n\t\t\t\t\tplace' = blend text' fg place;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nAutotrace_item = class \n\tMenuaction \"_Trace\" \"convert a bitmap to an SVG file\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tdespeckle = Scale \"Despeckle level\" 1 20 1;\n\t\tline = Scale \"Line threshold\" 1 20 1;\n\t\tcenter = Toggle \"Trace centreline\" false;\n\t\tscale = Scale \"SVG scale\" 0.1 10 1;\n\n\t\tcommand \n\t\t\t= \"autotrace %s \" ++ join_sep \" \" \n\t\t\t\t[ofmt, ofile, desp, lint, cent]\n\t\t{\n\t\t\tprog = search_for_error \"autotrace\"; \n\t\t\tofmt = \"-output-format svg\";\n\t\t\tofile = \"-output-file %s\";\n\t\t\tdesp = \"-despeckle-level \" ++ print despeckle.value;\n\t\t\tlint = \"-line-threshold \" ++ print line.value;\n\t\t\tcent = if center then \"-centerline \" else \"\";\n\t\t}\n\n\t\t_result \n\t\t\t= Image output\n\t\t{\n\t\t\t[output] = vips_call \"system\" \n\t\t\t\t[command] \n\t\t\t\t[$in => [x.value],\n\t\t\t\t $in_format => \"%s.ppm\", \n\t\t\t\t $out => true,\n\t\t\t\t $out_format => \"%s.svg[scale=\" ++ print scale.value ++ \"]\"\n\t\t\t\t];\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/start/Histogram.def",
    "content": "Hist_new_item = class\n\tMenupullright \"_New\" \"new histogram\" {\n\tHist_item = class\n\t\tMenuaction \"_Identity\" \"make an identity histogram\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\t_result = Plot [] ([im_identity 1, im_identity_ushort 1 65536]?d);\n\t\t}\n\t}\n\n\tHist_new_from_matrix = Matrix_buildlut_item; \n\n\tHist_from_image_item = class\n\t\tMenuaction \"Ta_g Image As Histogram\" \"set image Type to Histogram\" {\n\t\taction x = hist_tag x;\n\t}\n\n\tTone_item = class \n\t\tMenuaction \"_Tone Curve\" \"make a new tone mapping curve\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\td = Option \"Depth\" [\"8 bit\", \"16 bit\"] 0;\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\t_result \n\t\t\t\t= tone_build fmt b w sp mp hp sa ma ha\n\t\t\t{\n\t\t\t\tfmt = [Image_format.UCHAR, Image_format.USHORT]?d;\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_convert_to_hist_item = class \n\tMenuaction \"Con_vert to Histogram\" \"convert anything to a histogram\" {\n\taction x = hist_tag (to_image x);\n}\n\nHist_find_item = class \n\tMenupullright \"_Find\" \"find a histogram\" {\n\tOned_item = class \n\t\tMenuaction \"_One Dimension\" \n\t\t\t\"for a n-band image, make an n-band 1D histogram\" {\n\t\taction x = map_unary hist_find x;\n\t}\n\n\tNd_item = class \n\t\tMenuaction \"_Many Dimensions\" \n\t\t\t\"for a n-band image, make an n-dimensional histogram\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// default to something small-ish\n\t\t\tbins = Expression \"Number of bins in each dimension\" 8;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess in\n\t\t\t\t\t= hist_find_nD bins in;\n\t\t\t}\n\t\t}\n\t}\n\n\tIndexed_item = class\n\t\tMenuaction \"_Indexed\" \n\t\t\t\"use a 1-band index image to pick bins for an n-band image\" {\n\t\taction x y  = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcombine = Combine_picker Combine_type.SUM;\n\n\t\t\t_result\n\t\t\t\t= map_binary map x y\n\t\t\t{\n\t\t\t\tmap a b\n\t\t\t\t\t= hist_find_indexed combine.value index im\n\t\t\t\t{\n\t\t\t\t\t[im, index] = sortc (const is_index) [a, b];\n\n\t\t\t\t\tis_index x\n\t\t\t\t\t\t= has_image x && b == 1 && \n\t\t\t\t\t\t\t(f == Image_format.UCHAR || f == Image_format.USHORT)\n\t\t\t\t\t{\n\t\t\t\t\t\tim = get_image x;\n\t\t\t\t\t\tb = get_bands x;\n\t\t\t\t\t\tf = get_format x;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nHist_map_item = class \n\tMenuaction \"_Map\" \"map an image through a histogram\" {\n\taction x y\n\t\t= map_binary map x y\n\t{\n\t\tmap a b\n\t\t\t= hist_map hist im\n\t\t{\n\t\t\t[im, hist] = sortc (const is_hist) [a, b];\n\t\t}\n\t}\n}\n\nHist_eq_item = Filter_enhance_item.Hist_equal_item;\n\n#separator\n\nHist_cum_item = class \n\tMenuaction \"_Integrate\" \n\t\t\"form cumulative histogram\" {\n\taction x = map_unary hist_cum x;\n}\n\nHist_diff_item = class \n\tMenuaction \"_Differentiate\" \n\t\t\"find point-to-point differences (inverse of Integrate)\" {\n\taction x = map_unary hist_diff x;\n}\n\nHist_norm_item = class \n\tMenuaction \"N_ormalise\" \"normalise a histogram\" {\n\taction x = map_unary hist_norm x;\n}\n\nHist_inv_item = class \n\tMenuaction \"In_vert\" \"invert a histogram\" {\n\taction x = map_unary hist_inv x;\n}\n\nHist_match_item = class \n\tMenuaction \"Ma_tch\" \n\t\t\"find LUT which will match first histogram to second\" {\n\taction in ref = map_binary hist_match in ref;\n}\n\nHist_zerox_item = class \n\tMenuaction \"_Zero Crossings\" \"find zero crossings\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Direction\" [\n\t\t\t\"Positive-going\", \n\t\t\t\"Negative-going\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary (zerox (if edge == 0 then -1 else 1)) x;\n\t}\n}\n\nHist_entropy_item = class Menuaction \"Entropy\" \"calculate histogram entropy\" {\n\taction x = hist_entropy x;\n}\n\n#separator\n\nHist_profile_item = class \n\tMenuaction \"Find _Profile\" \n\t\t\"search from image edges for non-zero pixels\" {\n\taction x = class  \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tedge = Option \"Search from\" [\n\t\t\t\"Top edge down\", \n\t\t\t\"Left edge to right\",\n\t\t\t\"Bottom edge up\",\n\t\t\t\"Right edge to left\"\n\t\t] 2;\n\n\t\t_result \n\t\t\t= map_unary profile x\n\t\t{\n\t\t\tprofile image\n\t\t\t\t= (Plot_histogram @ hist_tag) [\n\t\t\t\t\tprofilemb 0 image.value,\n\t\t\t\t\tprofilemb 1 image.value,\n\t\t\t\t\tprofilemb 0 (fliptb image.value),\n\t\t\t\t\tprofilemb 1 (fliplr image.value)\n\t\t\t\t]?edge;\n\n\t\t\t// im_profile only does 1 band images :-(\n\t\t\tprofilemb d = bandjoin @ map (converse im_profile d) @ bandsplit;\n\t\t}\n\t}\n}\n\nHist_project_item = class \n\tMenuaction \"Find Pro_jections\" \n\t\t\"find horizontal and vertical projections\" {\n\taction x = class {\n\t\t_vislevel = 2;\n\n\t\t_result = map_unary project x;\n\n\t\t// extract the result ... could be a group\n\t\textr n\n\t\t\t= Plot_histogram _result?n, is_list _result\n\t\t\t= Group (map (Plot_histogram @ converse subscript n) _result.value);\n\n\t\thorizontal = extr 0;\n\t\tvertical = extr 1;\n\t\tcentre = (gravity horizontal, gravity vertical);\n\t}\n}\n\n#separator\n\nHist_graph_item = class \n\tMenuaction \"P_lot Slice\" \"plot a slice along a guide or arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary graph x\n\t\t{\n\t\t\tgraph arrow\n\t\t\t\t= hist_tag area'\n\t\t\t{\n\t\t\t\tarea = extract_arrow \n\t\t\t\t\tdisplace.value vdisplace.value width.value arrow;\n\n\t\t\t\t// squish vertically to get an average\n\t\t\t\tarea' = resize Kernel_linear 1 (1 / width.value) area;\n\t\t\t}\n\t\t}\n\t}\n}\n\nExtract_arrow_item = class \n\tMenuaction \"Extract _Arrow\" \"extract the area around an arrow\" {\n\taction x = class \n\t\t_value {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 1 40 1;\n\t\tdisplace = Scale \"Horizontal displace\" (-50) 50 0; \n\t\tvdisplace = Scale \"Vertical displace\" (-50) 50 0; \n\n\t\t_value\n\t\t\t= map_unary (extract_arrow \n\t\t\t\tdisplace.value vdisplace.value width.value) x;\n\t}\n}\n\nHist_plot_item = class\n\tMenuaction \"Plot _Object\" \n\t\t\"plot an object as a bar, point or line graph\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcaption = Expression \"Chart caption\" \"none\";\n\t\tformat = Option_enum \"Format\" Plot_format.names \"YYYY\";\n\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\t\txcaption = Expression \"X axis caption\" \"none\";\n\t\tycaption = Expression \"Y axis caption\" \"none\";\n\t\tseries_captions = Expression \"Series captions\" [\"Band 0\"];\n\n\t\t_result\n\t\t\t= Plot options (image x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => style.value, $format => format.value] ++ \n\t\t\t\t\trange ++ captions;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\tcaptions \n\t\t\t\t= concat (map test caption_options) ++ \n\t\t\t\t  [$series_captions => series_captions.expr]\n\t\t\t{\n\t\t\t\tcaption_options = [\n\t\t\t\t\t$caption => caption.expr,\n\t\t\t\t\t$xcaption => xcaption.expr,\n\t\t\t\t\t$ycaption => ycaption.expr\n\t\t\t\t];\n\t\t\t\ttest x\n\t\t\t\t\t= [], value == \"none\"\n\t\t\t\t\t= [option_name => value]\n\t\t\t\t{\n\t\t\t\t\t[option_name, value] = x;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\timage x\n\t\t\t\t= image (extract_arrow 0 0 1 x), is_Arrow x\n\t\t\t\t= get_image x, has_image x\n\t\t\t\t= x2b im, b == 1\n\t\t\t\t= im\n\t\t\t{\n\t\t\t\tim = get_image (to_image x);\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\n\t\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t\t// we need to put columns into bands\n\t\t\t\tx2b im \n\t\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t\t{\n\t\t\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "share/nip2/start/Image.def",
    "content": "Image_new_item = class Menupullright \"_New\" \"make new things\" {\n\tImage_black_item = class Menuaction \"_Image\" \"make a new image\" {\n\t\tformat_names = [\n\t\t\t\"8-bit unsigned int - UCHAR\", \t\t// 0\n\t\t\t\"8-bit signed int - CHAR\", \t\t\t// 1\n\t\t\t\"16-bit unsigned int - USHORT\", \t// 2\n\t\t\t\"16-bit signed int - SHORT\", \t\t// 3\n\t\t\t\"32-bit unsigned int - UINT\", \t\t// 4\n\t\t\t\"32-bit signed int - INT\", \t\t\t// 5\n\t\t\t\"32-bit float - FLOAT\", \t\t\t// 6\n\t\t\t\"64-bit complex - COMPLEX\", \t\t// 7\n\t\t\t\"64-bit float - DOUBLE\", \t\t\t// 8\n\t\t\t\"128-bit complex - DPCOMPLEX\" \t\t// 9\n\t\t];\n\n\t\taction = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tnbands = Expression \"Image bands\" 1;\n\t\t\tformat_option = Option \"Image format\" format_names 0;\n\t\t\ttype_option = Option_enum \"Image type\"\n\t\t\t\tImage_type.type_names \"B_W\";\n\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t_result\n\t\t\t\t= image_new (to_real nwidth) (to_real nheight) (to_real nbands) \n\t\t\t\t\t(to_real format_option) Image_coding.NOCODING \n\t\t\t\t\ttype_option.value_thing pixel.expr 0 0;\n\t\t}\n\t}\n\n\tImage_new_from_image_item = class\n\t\tMenuaction \"_From Image\" \"make a new image based on image x\" {\n\t\taction x = class\n\t\t\tImage _result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tpixel = Expression \"Pixel value\" 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= image_new x.width x.height x.bands\n\t\t\t\t\t\tx.format x.coding x.type pixel.expr x.xoffset x.yoffset;\n\t\t}\n\t} \n\n\tImage_region_item = class \n\t\tMenupullright \"_Region on Image\" \"make a new region on an image\" {\n\t\tRegion_item = class \n\t\t\tMenuaction \"_Region\" \"make a region on an image\" {\n\t\t\taction image = scope.Region_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tMark_item = class \n\t\t\tMenuaction \"_Point\" \"make a point on an image\" {\n\t\t\taction image = scope.Mark_relative image 0.5 0.5;\n\t\t}\n\t\n\t\tArrow_item = class \n\t\t\tMenuaction \"_Arrow\" \"make an arrow on an image\" {\n\t\t\taction image = scope.Arrow_relative image 0.25 0.25 0.5 0.5;\n\t\t}\n\t\n\t\tHGuide_item = class \n\t\t\tMenuaction \"_Horizontal Guide\" \n\t\t\t\t\"make a horizontal guide on an image\" {\n\t\t\taction image = scope.HGuide image 0.5;\n\t\t}\n\t\n\t\tVGuide_item = class \n\t\t\tMenuaction \"_Vertical Guide\" \"make a vertical guide on an image\" {\n\t\t\taction image = scope.VGuide image 0.5;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tMove_item = class\n\t\t\tMenuaction \"From Region\" \n\t\t\t\t\"new region on image using existing region as a guide\" {\n\t\t\taction a b \n\t\t\t\t= map_binary process a b\n\t\t\t{\n\t\t\t\tprocess a b \n\t\t\t\t\t= x.Region target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Region x\n\t\t\t\t\t= x.Arrow target x.left x.top x.width x.height,\n\t\t\t\t\t\t\tis_Arrow x\n\t\t\t\t\t= error \"bad arguments to region-from-region\"\n\t\t\t\t{\n\t\t\t\t\t// prefer image then region\n\t\t\t\t\tcompare a b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\t!is_Image a && is_Image b\n\t\t\t\t\t\t= false, \n\t\t\t\t\t\t\tis_Region a && !is_Region b\n\t\t\t\t\t\t= true;\n\n\t\t\t\t\t[target, x] = sortc compare [a, b];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_convert_to_image_item = class \n\tMenuaction \"Con_vert to Image\" \"convert anything to an image\" {\n\taction x = to_image x;\n}\n\nImage_number_format_item = class\n\tMenupullright \"_Format\" \"convert numeric format\" {\n\n\tU8_item = class\n\t\tMenuaction \"_8 bit unsigned\" \"convert to unsigned 8 bit [0, 255]\" {\n\t\taction x = map_unary cast_unsigned_char x;\n\t}\n\n\tU16_item = class\n\t\tMenuaction \"1_6 bit unsigned\" \n\t\t\t\"convert to unsigned 16 bit [0, 65535]\" {\n\t\taction x = map_unary cast_unsigned_short x;\n\t}\n\n\tU32_item = class\n\t\tMenuaction \"_32 bit unsigned\" \n\t\t\t\"convert to unsigned 32 bit [0, 4294967295]\" {\n\t\taction x = map_unary cast_unsigned_int x;\n\t}\n\n    sep1 = Menuseparator;\n\n\tS8_item = class\n\t\tMenuaction \"8 _bit signed\" \"convert to signed 8 bit [-128, 127]\" {\n\t\taction x = map_unary cast_signed_char x;\n\t}\n\n\tS16_item = class\n\t\tMenuaction \"16 b_it signed\" \n\t\t\t\"convert to signed 16 bit [-32768, 32767]\" {\n\t\taction x = map_unary cast_signed_short x;\n\t}\n\n\tS32_item = class\n\t\tMenuaction \"32 bi_t signed\" \n\t\t\t\"convert to signed 32 bit [-2147483648, 2147483647]\" {\n\t\taction x = map_unary cast_signed_int x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tFloat_item = class\n\t\tMenuaction \"_Single precision float\" \n\t\t\t\"convert to IEEE 32 bit float\" {\n\t\taction x = map_unary cast_float x;\n\t}\n\n\tDouble_item = class\n\t\tMenuaction \"_Double precision float\" \n\t\t\t\"convert to IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double x;\n\t}\n\n    sep3 = Menuseparator;\n\n\tScmplxitem = class\n\t\tMenuaction \"Single _precision complex\" \n\t\t\t\"convert to 2 x IEEE 32 bit float\" {\n\t\taction x = map_unary cast_complex x;\n\t}\n\n\tDcmplx_item = class\n\t\tMenuaction \"Double p_recision complex\" \n\t\t\t\"convert to 2 x IEEE 64 bit float\" {\n\t\taction x = map_unary cast_double_complex x;\n\t}\n}\n\nImage_header_item = class \n\tMenupullright \"_Header\" \"do stuff to the image header\" {\n\n\tImage_get_item = class\n\t\tMenupullright \"_Get\" \"get header fields\" {\n\n\t\t// the header fields we can get\n\t\tfields = class {\n\t\t\ttype = 0;\n\t\t\twidth = 1;\n\t\t\theight = 2;\n\t\t\tformat = 3;\n\t\t\tbands = 4;\n\t\t\txres = 5;\n\t\t\tyres = 6;\n\t\t\txoffset = 7;\n\t\t\tyoffset = 8;\n\t\t\tcoding = 9;\n\n\t\t\tfield_names = Enum [\n\t\t\t\t$width => width,\n\t\t\t\t$height => height,\n\t\t\t\t$bands => bands,\n\t\t\t\t$format => format,\n\t\t\t\t$type => type,\n\t\t\t\t$xres => xres,\n\t\t\t\t$yres => yres,\n\t\t\t\t$xoffset => xoffset,\n\t\t\t\t$yoffset => yoffset,\n\t\t\t\t$coding => coding\n\t\t\t];\n\n\t\t\tfield_option name = Option_enum (_ \"Field\") field_names name;\n\n\t\t\tfield_funcs = Table [\n\t\t\t\t[type, get_type],\n\t\t\t\t[width, get_width],\n\t\t\t\t[height, get_height],\n\t\t\t\t[format, get_format],\n\t\t\t\t[bands, get_bands],\n\t\t\t\t[xres, get_xres],\n\t\t\t\t[yres, get_yres],\n\t\t\t\t[xoffset, get_xoffset],\n\t\t\t\t[yoffset, get_yoffset],\n\t\t\t\t[coding, get_coding]\n\t\t\t];\n\t\t}\n\n\t\tget_field field_name x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfield = fields.field_option field_name;\n\n\t\t\t_result \n\t\t\t\t= map_unary (Real @ \n\t\t\t\t\tfields.field_funcs.lookup 0 1 field.value_thing) x;\n\t\t}\n\n\t\tWidth_item = class \n\t\t\tMenuaction \"_Width\" \"get width\" {\n\t\t\taction x = get_field \"width\" x;\n\t\t}\n\n\t\tHeight_item = class \n\t\t\tMenuaction \"_Height\" \"get height\" {\n\t\t\taction x = get_field \"height\" x;\n\t\t}\n\n\t\tBands_item = class \n\t\t\tMenuaction \"_Bands\" \"get bands\" {\n\t\t\taction x = get_field \"bands\" x;\n\t\t}\n\n\t\tFormat_item = class \n\t\t\tMenuaction \"_Format\" \"get format\" {\n\t\t\taction x = get_field \"format\" x;\n\t\t}\n\n\t\tType_item = class \n\t\t\tMenuaction \"_Type\" \"get type\" {\n\t\t\taction x = get_field \"type\" x;\n\t\t}\n\n\t\tXres_item = class \n\t\t\tMenuaction \"_Xres\" \"get X resolution\" {\n\t\t\taction x = get_field \"xres\" x;\n\t\t}\n\n\t\tYres_item = class \n\t\t\tMenuaction \"_Yres\" \"get Y resolution\" {\n\t\t\taction x = get_field \"yres\" x;\n\t\t}\n\n\t\tXoffset_item = class \n\t\t\tMenuaction \"X_offset\" \"get X offset\" {\n\t\t\taction x = get_field \"xoffset\" x;\n\t\t}\n\n\t\tYoffset_item = class \n\t\t\tMenuaction \"Yo_ffset\" \"get Y offset\" {\n\t\t\taction x = get_field \"yoffset\" x;\n\t\t}\n\n\t\tCoding_item = class \n\t\t\tMenuaction \"_Coding\" \"get coding\" {\n\t\t\taction x = get_field \"coding\" x;\n\t\t}\n\n    \tsep1 = Menuseparator;\n\n\t\tCustom_item = class\n\t\t\tMenuaction \"C_ustom\" \"get any header field\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tfield = String \"Field\" \"Xsize\";\n\t\t\t\tparse = Option \"Parse\" [\n\t\t\t\t\t\"No parsing\",\n\t\t\t\t\t\"Parse string as integer\",\n\t\t\t\t\t\"Parse string as real\",\n\t\t\t\t\t\"Parse string as hh:mm:ss\"\n\t\t\t\t] 0;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary (wrap @ process @ get_header field.value) x\n\t\t\t\t{\n\t\t\t\t\tparse_str parse str = parse (split is_space str)?0;\n\n\t\t\t\t\tparse_field name cast parse x\n\t\t\t\t\t\t= cast x, is_number x\n\t\t\t\t\t\t= parse_str parse x, is_string x\n\t\t\t\t\t\t= error (\"not \" ++ name);\n\n\t\t\t\t\tget_int = parse_field \"int\" \n\t\t\t\t\t\tcast_signed_int parse_int;\n\t\t\t\t\tget_float = parse_field \"float\" \n\t\t\t\t\t\tcast_float parse_float;\n\t\t\t\t\tget_time = parse_field \"hh:mm:ss\" \n\t\t\t\t\t\tcast_signed_int parse_time;\n\n\t\t\t\t\twrap x\n\t\t\t\t\t\t= Real x, is_real x\n\t\t\t\t\t\t= Vector x, is_real_list x\n\t\t\t\t\t\t= Image x, is_image x\n\t\t\t\t\t\t= Bool x, is_bool x\n\t\t\t\t\t\t= Matrix x, is_matrix x\n\t\t\t\t\t\t= String \"String\" x, is_string x\n\t\t\t\t\t\t= List x, is_list x\n\t\t\t\t\t\t= x;\n\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tget_int, \n\t\t\t\t\t\tget_float,\n\t\t\t\t\t\tget_time\n\t\t\t\t\t]?parse;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tImage_set_meta_item = class\n\t\tMenuaction \"_Set\" \"set image metadata\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfname = String \"Field\" \"field-name\";\n\t\t\tval = Expression \"Value\" 42;\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= set_header fname.value val.expr image;\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_edit_header_item = class\n\t\tMenuaction \"_Edit\" \"change advisory header fields of image\" {\n\t\ttype_names = Image_type.type_names;\n\t\tall_names = sort (map (extract 0) type_names.value);\n\n\t\tget_prop has get def x\n\t\t\t= get x, has x\n\t\t\t= def;\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnxres = Expression \"Xres\" (get_prop has_xres get_xres 1 x);\n\t\t\tnyres = Expression \"Yres\" (get_prop has_yres get_yres 1 x);\n\t\t\tnxoff = Expression \"Xoffset\" (get_prop has_xoffset get_xoffset 0 x);\n\t\t\tnyoff = Expression \"Yoffset\" (get_prop has_yoffset get_yoffset 0 x);\n\n\t\t\ttype_option \n\t\t\t\t= Option_enum \"Image type\" Image_type.type_names \n\t\t\t\t\t(Image_type.type_names.get_name type)\n\t\t\t{\n\t\t\t\ttype \n\t\t\t\t\t= x.type, is_Image x\n\t\t\t\t\t= Image_type.MULTIBAND;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= Image (im_copy_set image.value type_option.value_thing\n\t\t\t\t\t\t(to_real nxres) (to_real nyres) \n\t\t\t\t\t\t(to_real nxoff) (to_real nyoff));\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_cache_item = class\n\tMenuaction \"C_ache\" \"cache calculated image pixels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttile_width = Number \"Tile width\" 128;\n\t\ttile_height = Number \"Tile height\" 128;\n\t\tmax_tiles = Number \"Maximum number of tiles to cache\" (-1);\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= cache (to_real tile_width) (to_real tile_height) \n\t\t\t\t\t(to_real max_tiles) image;\n\t\t}\n\t}\n}\n\n#separator\n\nImage_levels_item = class \n\tMenupullright \"_Levels\" \"change image levels\" {\n\tScale_item = class\n\t\tMenuaction \"_Scale to 0 - 255\" \"linear transform to fit 0 - 255 range\" {\n\t\taction x = map_unary scale x;\n\t}\n\n\tLinear_item = class\n\t\tMenuaction \"_Linear\" \"linear transform of image levels\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tscale = Scale \"Scale\" 0.001 3 1;\n\t\t\toffset = Scale \"Offset\" (-128) 128 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary adj x\n\t\t\t{\n\t\t\t\tadj x\n\t\t\t\t\t// only force back to input type if this is a thing\n\t\t\t\t\t// with a type ... so we work for Colour / Matrix etc.\n\t\t\t\t\t= clip2fmt x.format x', has_member \"format\" x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = x * scale + offset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = class\n\t\tMenuaction \"_Power\" \"power transform of image levels (gamma)\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tgamma = Scale \"Gamma\" 0.001 4 1;\n\t\t\timage_maximum_hint = \"You may need to change image_maximum if \" ++\n\t\t\t\t\"this is not an 8 bit image\";\n\t\t\tim_mx \n\t\t\t\t= Expression \"Image maximum\" mx\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t\t= Image_format.maxval x.format, has_format x\n\t\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= map_unary gam x\n\t\t\t{\n\t\t\t\tgam x\n\t\t\t\t\t= clip2fmt (get_format x) x', has_format x\n\t\t\t\t\t= x'\n\t\t\t\t{\n\t\t\t\t\tx' = (im_mx.expr / im_mx.expr ** gamma) * x ** gamma;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tTone_item = class\n\t\tMenuaction \"_Tone Curve\" \"adjust tone curve\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tb = Scale \"Black point\"  0 100 0;\n\t\t\tw = Scale \"White point\"  0 100 100;\n\n\t\t\tsp = Scale \"Shadow point\" 0.1 0.3 0.2;\n\t\t\tmp = Scale \"Mid-tone point\" 0.4 0.6 0.5;\n\t\t\thp = Scale \"Highlight point\" 0.7 0.9 0.8;\n\n\t\t\tsa = Scale \"Shadow adjust\" (-15) 15 0;\n\t\t\tma = Scale \"Mid-tone adjust\" (-30) 30 0;\n\t\t\tha = Scale \"Highlight adjust\" (-15) 15 0;\n\n\t\t\tcurve = tone_build x.format b w sp mp hp sa ma ha;\n\n\t\t\t_result = map_unary (hist_map curve) x;\n\t\t}\n\t}\n}\n\nImage_transform_item = class \n\tMenupullright \"_Transform\" \"transform images\" {\n\tRotate_item = class \n\t\tMenupullright \"Ro_tate\" \"rotate image\" {\n\t\tFixed_item = class\n\t\t\tMenupullright \"_Fixed\" \"clockwise rotation by fixed angles\" {\n\t        rotate_widget default x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Option \"Rotate by\" [\n\t\t\t\t\t\"Don't rotate\", \n\t\t\t\t\t\"90 degrees clockwise\",\n\t\t\t\t\t\"180 degrees\",\n\t\t\t\t\t\"90 degrees anticlockwise\"\n\t\t\t\t] default;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess = [\n\t\t\t\t\t\t// we can't use id here since we want to \"declass\"\n\t\t\t\t\t\t// the members of x ... consider if x is a crop class,\n\t\t\t\t\t\t// for example, we don't want to inherit from crop, we\n\t\t\t\t\t\t// want to make a new image class\n\t\t\t\t\t\trot180 @ rot180,\n\t\t\t\t\t\trot90,\n\t\t\t\t\t\trot180,\n\t\t\t\t\t\trot270\n\t\t\t\t\t] ? angle;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tRot90_item = class\n\t\t\t\tMenuaction \"_90 Degrees\" \"clockwise rotation by 90 degrees\" {\n\t\t\t\taction x = rotate_widget 1 x;\n\t\t\t}\n\t\n\t\t\tRot180_item = class\n\t\t\t\tMenuaction \"_180 Degrees\" \"clockwise rotation by 180 degrees\" {\n\t\t\t\taction x = rotate_widget 2 x;\n\t\t\t}\n\t\n\t\t\tRot270_item = class\n\t\t\t\tMenuaction \"_270 Degrees\" \"clockwise rotation by 270 degrees\" {\n\t\t\t\taction x = rotate_widget 3 x;\n\t\t\t}\n\t\t}\n\n\t\tFree_item = class\n\t\t\tMenuaction \"_Free\" \"clockwise rotation by any angle\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\tangle = Scale \"Angle\" (-180) 180 0;\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= rotate interp angle image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\tStraighten_item = class\n\t\t\tMenuaction \"_Straighten\" \n\t\t\t\t(\"smallest rotation that makes an arrow either horizontal \" ++\n\t\t\t\t\"or vertical\") {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary straighten x\n\t\t\t\t{\n\t\t\t\t\tstraighten arrow\n\t\t\t\t\t\t= rotate interp angle'' arrow.image\n\t\t\t\t\t{\n\t\t\t\t\t\tx = arrow.width;\n\t\t\t\t\t\ty = arrow.height;\n\t\t\n\t\t\t\t\t\tangle = im (polar (x, y));\n\t\t\n\t\t\t\t\t\tangle'\n\t\t\t\t\t\t\t= angle - 360, angle > 315\n\t\t\t\t\t\t\t= angle - 180, angle > 135\n\t\t\t\t\t\t\t= angle;\n\t\t\n\t\t\t\t\t\tangle''\n\t\t\t\t\t\t\t= -angle', angle' >= (-45) && angle' < 45\n\t\t\t\t\t\t\t= 90 - angle';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tFlip_item = class \n\t\tMenupullright \"_Flip\" \"mirror left/right or up/down\" {\n\t\tLeft_right_item = class\n\t\t\tMenuaction \"_Left Right\" \"mirror object left/right\" {\n\t\t\taction x = map_unary fliplr x;\n\t\t}\n\t\n\t\tTop_bottom_item = class\n\t\t\tMenuaction \"_Top Bottom\" \"mirror object top/bottom\" {\n\t\t\taction x = map_unary fliptb x;\n\t\t}\n\t}\n\n\tResize_item = class \n\t\tMenupullright \"_Resize\" \"change image size\" {\n\t\tScale_item = class\n\t\t\tMenuaction \"_Scale\" \"scale image size by a factor\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\txfactor = Expression \"Horizontal scale factor\" 1;\n\t\t\t\tyfactor = Expression \"Vertical scale factor\" 1;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= resize kernel xfactor yfactor image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_item = class\n\t\t\tMenuaction \"_Size To\" \"resize to a fixed size\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\twhich = Option \"Resize axis\" [\n\t\t\t\t\t\"Shortest\",\n\t\t\t\t\t\"Longest\",\n\t\t\t\t\t\"Horizontal\",\n\t\t\t\t\t\"Vertical\"\n\t\t\t\t] 0;\n\t\t\t\tsize = Expression \"Resize to (pixels)\" 128;\n\t\t\t\taspect = Toggle \"Break aspect ratio\" false;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t\t_result\n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image\n\t\t\t\t\t\t= resize kernel h v image, aspect\n\t\t\t\t\t\t= resize kernel fac fac image\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = to_real size / image.width;\n\t\t\t\t\t\tyfac = to_real size / image.height;\n\t\t\t\t\t\tmax_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac > yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\tmin_factor \n\t\t\t\t\t\t\t= [xfac, 1], xfac < yfac\n\t\t\t\t\t\t\t= [1, yfac];\n\t\t\t\t\t\t[h, v] = [\n\t\t\t\t\t\t\tmax_factor, \n\t\t\t\t\t\t\tmin_factor, \n\t\t\t\t\t\t\t[xfac, 1], \n\t\t\t\t\t\t\t[1, yfac]]?which;\n\n\t\t\t\t\t\tfac \n\t\t\t\t\t\t\t= h, v == 1\n\t\t\t\t\t\t\t= v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tSize_within_item = class\n\t\t\tMenuaction \"Size _Within\" \"size to fit within a rectangle\" {\n\t\t\taction x = class \n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\t// the rects we size to fit within\n\t\t\t\t_rects = [\n\t\t\t\t\t[2048, 1536], [1920, 1200], [1600, 1200], [1400, 1050], \n\t\t\t\t\t[1280, 1024], [1024, 768], [800, 600], [640, 480] \n\t\t\t\t];\n\n\t\t\t\twithin = Option \"Fit within (pixels)\" (\n\t\t\t\t\t[print w ++ \" x \" ++ print h :: [w, h] <- _rects] ++\n\t\t\t\t\t[\"Custom\"]\n\t\t\t\t) 4;\n\t\t\t\tcustom_width = Expression \"Custom width\" 1000;\n\t\t\t\tcustom_height = Expression \"Custom height\" 1000;\n\t\t\t    size = Option \"Page size\" [\n\t\t\t\t\t\"Full page\", \"Half page\", \"Quarter page\" \n\t\t\t\t] 0;\n\t\t\t\tkernel = Kernel_picker Kernel_type.LINEAR;\n\n\t\t\t \t_result\n\t\t\t\t \t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\txdiv = [1, 2, 2]?size;\n\t\t\t\t\tydiv = [1, 1, 2]?size;\n\t\t\t\t\tallrect = _rects ++ [\n\t\t\t\t\t\t[custom_width.expr, custom_height.expr]\n\t\t\t\t\t];\n\t\t\t\t\t[width, height] = allrect?within;\n\n\t\t\t\t\tprocess x\n\t\t\t\t\t\t= resize kernel fac fac x, fac < 1\n\t\t\t\t\t\t= x\n\t\t\t\t\t{\n\t\t\t\t\t\txfac = (width / xdiv) / x.width;\n\t\t\t\t\t\tyfac = (height / ydiv) / x.height;\n\t\t\t\t\t\tfac = min_pair xfac yfac;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tResize_canvas_item = class\n\t\t\tMenuaction \"_Canvas\" \"change size of surrounding image\" {\n\t\t\taction x = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// try to guess a sensible size for the new image \n\t\t\t\t_guess_size\n\t\t\t\t\t= x.rect, is_Image x\n\t\t\t\t\t= Rect 0 0 100 100;\n\t\n\t\t\t\tnwidth = Expression \"New width (pixels)\" _guess_size.width;\n\t\t\t\tnheight = Expression \"New height (pixels)\" _guess_size.height;\n\t\t\t\tbgcolour = Expression \"Background colour\" 0;\n\t\n\t\t\t\tposition = Option \"Position\" [\n\t\t\t\t\t\"North-west\",\n\t\t\t\t\t\"North\",\n\t\t\t\t\t\"North-east\",\n\t\t\t\t\t\"West\",\n\t\t\t\t\t\"Centre\",\n\t\t\t\t\t\"East\",\n\t\t\t\t\t\"South-west\",\n\t\t\t\t\t\"South\",\n\t\t\t\t\t\"South-east\",\n\t\t\t\t\t\"Specify in pixels\"\n\t\t\t\t] 4;\n\t\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\t\ttop = Expression \"Pixels from top\" 0;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= map_unary process x\n\t\t\t\t{\n\t\t\t\t\tprocess image \n\t\t\t\t\t\t= insert_noexpand xp yp image background\n\t\t\t\t\t{\n\t\t\t\t\t\twidth = image.width;\n\t\t\t\t\t\theight = image.height;\n\t\t\t\t\t\tcoding = image.coding;\n\t\t\t\t\t\tbands \n\t\t\t\t\t\t\t= 3, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.bands;\n\t\t\t\t\t\tformat \n\t\t\t\t\t\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t\t\t\t\t\t= image.format;\n\t\t\t\t\t\ttype = image.type;\n\t\n\t\t\t\t\t\t// placement vectors ... left, centre, right\n\t\t\t\t\t\txposv = [0, to_real nwidth / 2 - width / 2, \n\t\t\t\t\t\t\tto_real nwidth - width];\n\t\t\t\t\t\typosv = [0, to_real nheight / 2 - height / 2, \n\t\t\t\t\t\t\tto_real nheight - height];\n\t\t\t\t\t\txp \n\t\t\t\t\t\t\t= left, position == 9\n\t\t\t\t\t\t\t= xposv?((int) (position % 3));\n\t\t\t\t\t\typ \n\t\t\t\t\t\t\t= top, position == 9\n\t\t\t\t\t\t\t= yposv?((int) (position / 3));\n\t\n\t\t\t\t\t\tbackground = image_new nwidth nheight\n\t\t\t\t\t\t\tbands format coding type bgcolour.expr 0 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_map_item = class\n\t\tMenuaction \"_Map\" \"map an image through a 2D transform image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tinterp = Interpolate_picker Interpolate_type.BILINEAR;\n\n\t\t\t_result\n\t\t\t\t= map_binary trans a b\n\t\t\t{\n\t\t\t\ttrans a b\n\t\t\t\t\t= mapim interp.value in index\n\t\t\t\t{\n\t\t\t\t\t// get the index image first\n\t\t\t\t\t[index, in] = sortc (const is_twocomponent) [a, b];\n\n\t\t\t\t\t// is a two-component image, ie. one band complex, or\n\t\t\t\t\t// two-band non-complex\n\t\t\t\t\tis_twocomponent x\n\t\t\t\t\t\t= is_nonc x || is_c x;\n\t\t\t\t\tis_nonc x\n\t\t\t\t\t\t= has_bands x && get_bands x == 2 && \n\t\t\t\t\t\t\thas_format x && !is_complex_format (get_format x);\n\t\t\t\t\tis_c x\n\t\t\t\t\t\t= has_bands x && get_bands x == 1 && \n\t\t\t\t\t\t\thas_format x && is_complex_format (get_format x);\n\t\t\t\t\tis_complex_format f\n\t\t\t\t\t\t= f == Image_format.COMPLEX || \n\t\t\t\t\t\t\tf == Image_format.DPCOMPLEX;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_item = Perspective_item;\n\n\tImage_rubber_item = class \n\t\tMenupullright \"Ru_bber Sheet\" \n\t\t\t\"automatically warp images to superposition\" {\n\t\trubber_interp = Option \"Interpolation\" [\"Nearest\", \"Bilinear\"] 1;\n\t\trubber_order = Option \"Order\" [\"0\", \"1\", \"2\", \"3\"] 1;\n\t\trubber_wrap = Toggle \"Wrap image edges\" false;\n\n\t\t// a transform ... a matrix, plus the size of the image the\n\t\t// matrix was made for\n\t\tTransform matrix image_width image_height = class \n\t\t\tmatrix {\n\t\t\t// scale a transform ... if it worked for a m by n image, make\n\t\t\t// it work for a (m * xfac) by (y * yfac) image\n\t\t\trescale xfac yfac \n\t\t\t\t= Transform (Matrix (map2 (map2 multiply) matrix.value facs))\n\t\t\t\t\t(image_width * xfac) (image_height * yfac)\n\t\t\t{\n\t\t\t\tfacs = [\n\t\t\t\t\t[xfac, yfac],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1, 1],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac],\n\t\t\t\t\t[1 / xfac, 1 / yfac]\n\t\t\t\t];\n\t\t\t}\n\t\t}\n\n\t\t// yuk!!!! fix is_instanceof to not need absolute names\n\t\tis_Transform = is_instanceof \n\t\t\t\"Image_transform_item.Image_rubber_item.Transform\";\n\n\t\tFind_item = class\n\t\t\tMenuaction \"_Find\" \n\t\t\t\t(\"find a transform which will map sample image onto \" ++\n\t\t\t\t\"reference\") {\n\t\t\taction reference sample = class\n\t\t\t\t_trn {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\torder = rubber_order;\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\t\t\tmax_err = Expression \"Maximum error\" 0.3;\n\t\t\t\tmax_iter = Expression \"Maximum iterations\" 10;\n\t\n\t\t\t\t// transform\n\t\t\t\t[sample', trn, err] = transform_search \n\t\t\t\t\tmax_err max_iter order interp wrap\n\t\t\t\t\tsample reference;\n\t\t\t\ttransformed_image = Image sample';\n\t\t\t\t_trn = Transform trn reference.width reference.height;\n\t\t\t\tfinal_error = err;\n\t\t\t}\n\t\t}\n\n\t\tApply_item = class\n\t\t\tMenuaction \"_Apply\" \"apply a transform to an image\" {\n\t\t\taction a b = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\t\n\t\t\t\t// controls\n\t\t\t\tinterp = rubber_interp;\n\t\t\t\twrap = rubber_wrap;\n\t\n\t\t\t\t_result\n\t\t\t\t\t= map_binary trans a b\n\t\t\t\t{\n\t\t\t\t\ttrans a b\n\t\t\t\t\t\t= transform interp wrap t' i\n\t\t\t\t\t{\n\t\t\t\t\t\t// get the transform arg first\n\t\t\t\t\t\t[i, t] = sortc (const is_Transform) [a, b];\n\t\t\t\t\t\tt' = t.rescale (i.width / t.image_width) \n\t\t\t\t\t\t\t(i.height / t.image_height);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tMatch_item = class\n\t\tMenuaction \"_Linear Match\" \n\t\t\t\"rotate and scale one image to match another\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// try to find an image ... for a group, get the first item\n\t\t\tfind_image x\n\t\t\t\t= x, is_Image x\n\t\t\t\t= find_image x?0, is_list x\n\t\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t\t= error \"unable to find image\";\n\n\t\t\t_a = find_image x;\n\t\t\t_b = find_image y;\n\n\t\t\tap1 = Mark_relative _a 0.5 0.25;\n\t\t\tbp1 = Mark_relative _b 0.5 0.25;\n\t\t\tap2 = Mark_relative _a 0.5 0.75;\n\t\t\tbp2 = Mark_relative _b 0.5 0.75;\n\t\t\n\t\t\trefine = Toggle \"Refine selected tie-points\" false;\n\t\t\tlock = Toggle \"No resize\" false;\n\t\t\n\t\t\t_result\n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess a b\n\t\t\t\t\t= Image b'''\n\t\t\t\t{\n\t\t\t\t\t_prefs = Workspaces.Preferences;\n\t\t\t\t\twindow = _prefs.MOSAIC_WINDOW_SIZE;\n\t\t\t\t\tobject = _prefs.MOSAIC_OBJECT_SIZE;\n\t\t\t\t\t\n\t\t\t\t\ta' = a.value;\n\t\t\t\t\tb' = b.value;\n\t\t\t\n\t\t\t\t\tb'' = clip2fmt a.format b';\n\t\t\t\n\t\t\t\t\t// return p2 ... if lock is set, return a p2 a standard\n\t\t\t\t\t// distance along the vector joining p1 and p2\n\t\t\t\t\tnorm p1 p2\n\t\t\t\t\t\t= Rect left' top' 0 0, lock\n\t\t\t\t\t\t= p2\n\t\t\t\t\t{\n\t\t\t\t\t\tv = (p2.left - p1.left, p2.top - p1.top);\n\t\t\t\t\t\t// 100000 to give precision since we pass points as\n\t\t\t\t\t\t// ints to match\n\t\t\t\t\t\tn = 100000 * sign v;\n\t\t\t\t\t\tleft' = p1.left + re n;\n\t\t\t\t\t\ttop' = p1.top + im n;\n\t\t\t\t\t}\n\t\t\t\n\t\t\t\t\tap2'' = norm ap1 ap2;\n\t\t\t\t\tbp2'' = norm bp1 bp2;\n\t\t\t\n\t\t\t\t\tb''' \n\t\t\t\t\t\t= im_match_linear_search a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top\n\t\t\t\t\t\t\tobject window,\n\t\t\t\t\t\t\t\t// we can't search if lock is on\n\t\t\t\t\t\t\t\trefine && !lock\n\t\t\t\t\t\t= im_match_linear a' b''\n\t\t\t\t\t\t\tap1.left ap1.top bp1.left bp1.top\n\t\t\t\t\t\t\tap2''.left ap2''.top bp2''.left bp2''.top;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_perspective_match_item = Perspective_match_item;\n}\n\nImage_band_item = class \n\tMenupullright \"_Band\" \"manipulate image bands\" {\n\t// like extract_bands, but return [] for zero band image\n\t// makes compose a bit simpler\n\texb b n x\n\t\t= [], to_real n == 0\n\t\t= extract_bands b n x;\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from band\" 0;\n\t\t\tnumber = Expression \"Extract this many bands\" 1;\n\n\t\t\t_result = map_unary (exb first number) x;\n\t\t}\n\t}\n\n\tInsert_item = class Menuaction \"_Insert\" \"insert bands into image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at position\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_binary process x y\n\t\t\t{\n\t\t\t\tprocess im1 im2\n\t\t\t\t\t= exb 0 f im1 ++ im2 ++ exb f (b - f) im1\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tb = im1.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tDelete_item = class Menuaction \"_Delete\" \"delete bands from image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from band\" 0;\n\t\t\tnumber = Expression \"Delete this many bands\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= exb 0 f im ++ exb (f + n) (b - (f + n)) im\n\t\t\t\t{\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = im.bands;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tBandwise_item = Image_join_item.Bandwise_item;\n\n    sep1a = Menuseparator;\n\n\tBandand_item = class\n\t\tMenuaction \"Bitwise Band AND\" \"bitwise AND of image bands\" {\n\t\taction x = bandand x;\n\t}\n\n\tBandor_item = class\n\t\tMenuaction \"Bitwise Band OR\" \"bitwise OR of image bands\" {\n\t\taction x = bandor x;\n\t}\n\n    sep2 = Menuseparator;\n\n\tTo_dimension_item = class \n\t\tMenuaction \"To D_imension\" \"convert bands to width or height\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= foldl1 [join_lr, join_tb]?orientation (bandsplit im);\n\t\t\t}\n\t\t}\n\t}\n\n\tTo_bands_item = class \n\t\tMenuaction \"To B_ands\" \"turn width or height to bands\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess im\n\t\t\t\t\t= bandjoin (map extract_column [0 .. im.width - 1]),\n\t\t\t\t\t\torientation == 0\n\t\t\t\t\t= bandjoin (map extract_row [0 .. im.height - 1])\n\t\t\t\t{\n\t\t\t\t\textract_column n\n\t\t\t\t\t\t= extract_area n 0 1 im.height im;\n\t\t\t\t\textract_row n\n\t\t\t\t\t\t= extract_area 0 n im.width 1 im;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_alpha_item = class \n\tMenupullright \"_Alpha\" \"manipulate image alpha\" {\n\n\tAdd_item = class Menuaction \"_Add\" \"add alpha\" {\n\t\taction x = class\n\t\t\t_result { \n\t\t\t_vislevel = 3;\n\n\t\t\topacity = Expression \"Opacity (255 == solid)\" 255;\n\t\t\t\n\t\t\t_result = x ++ to_real opacity;\n\t\t}\n\t}\n\n\tFlatten_item = class Menuaction \"_Flatten\" \"flatten alpha out of image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbg = Expression \"Background\" 0;\n\n\t\t\t_result = map_unary (flattenimage bg) x;\n\t\t}\n\t}\n\n\tExtract_item = class Menuaction \"_Extract\" \"extract alpha\" {\n\t\taction x \n\t\t\t= map_unary exb x\n\t\t{\n\t\t\texb x = extract_bands (x.bands - 1) 1 x;\n\t\t}\n\t}\n\n\tDrop_item = class Menuaction \"_Drop\" \"drop alpha\" {\n\t\taction x \n\t\t\t= map_unary exb x\n\t\t{\n\t\t\texb x = extract_bands 0 (x.bands - 1) x;\n\t\t}\n\t}\n\n    sep1 = Menuseparator;\n\n\tPremultiply_item = class Menuaction \"_Premultiply\" \"premultiply alpha\" {\n\t\taction x = premultiply x;\n\t}\n\n\tUnpremultiply_item = class \n\t\tMenuaction \"_Unpremultiply\" \"unpremultiply alpha\" {\n\t\taction x = unpremultiply x; \n\t}\n\n    sep2 = Menuseparator;\n\n\tComposite2_item = class \n\t\tMenuaction \"_Composite two\" \"composite a pair of images\" {\n\t\taction x y = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tblend = Option_enum (_ \"Blend mode\") modes \"over\"\n\t\t\t{\n\t\t\t\tmodes = Blend_type.types;\n\t\t\t}\n\t\t\tcompositing_space = Option_enum (_ \"Compositing space\") spaces \"sRGB\"\n\t\t\t{\n\t\t\t\tspaces = Image_type.image_colour_spaces;\n\t\t\t}\n\t\t\tpremultiplied = Toggle (_ \"Premultiplied\") false;\n\n\t\t\t_result \n\t\t\t\t= Image output\n\t\t\t{\n\t\t\t\t[output] = vips_call \"composite\" \n\t\t\t\t\t[[y.value, x.value], blend.value] \n\t\t\t\t\t[$compositing_space => compositing_space.value_thing,\n\t\t\t\t\t $premultiplied => premultiplied.value\n\t\t\t\t\t];\n\t\t\t}\n\t\t}\n\t}\n\n\tComposite3_item = class \n\t\tMenuaction \"_Composite three\" \"composite three images\" {\n\t\taction x y z = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tblend1 = Option_enum (_ \"Blend mode\") modes \"over\"\n\t\t\t{\n\t\t\t\tmodes = Blend_type.types;\n\t\t\t}\n\t\t\tblend2 = Option_enum (_ \"Blend mode\") modes \"over\"\n\t\t\t{\n\t\t\t\tmodes = Blend_type.types;\n\t\t\t}\n\t\t\tcompositing_space = Option_enum (_ \"Compositing space\") spaces \"sRGB\"\n\t\t\t{\n\t\t\t\tspaces = Image_type.image_colour_spaces;\n\t\t\t}\n\t\t\tpremultiplied = Toggle (_ \"Premultiplied\") false;\n\n\t\t\t_result \n\t\t\t\t= Image output\n\t\t\t{\n\t\t\t\t[output] = vips_call \"composite\" \n\t\t\t\t\t[[z.value, y.value, x.value], [blend1.value, blend2.value]] \n\t\t\t\t\t[$compositing_space => compositing_space.value_thing,\n\t\t\t\t\t $premultiplied => premultiplied.value\n\t\t\t\t\t];\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_crop_item = class \n\tMenuaction \"_Crop\" \"extract a rectangular area from an image\" {\n\taction x \n\t\t= crop x [l, t, w, h]\n\t{\n\t\tfields = [\n\t\t\t[has_left, get_left, 0],\n\t\t\t[has_top, get_top, 0],\n\t\t\t[has_width, get_width, 100],\n\t\t\t[has_height, get_height, 100]\n\t\t];\n\n\t\t[l, t, w, h] \n\t\t\t= map get_default fields\n\t\t{\n\t\t\tget_default line\n\t\t\t\t= get x, has x\n\t\t\t\t= default\n\t\t\t{\n\t\t\t\t[has, get, default] = line;\n\t\t\t}\n\t\t}\n\t}\n\n\tcrop x geo = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tl = Expression \"Crop left\" ((int) (geo?0 + geo?2 / 4));\n\t\tt = Expression \"Crop top\" ((int) (geo?1 + geo?3 / 4));\n\t\tw = Expression \"Crop width\" (max_pair 1 ((int) (geo?2 / 2)));\n\t\th = Expression \"Crop height\" (max_pair 1 ((int) (geo?3 / 2)));\n\n\t\t_result \n\t\t\t= map_nary (list_5ary extract) [x, l.expr, t.expr, w.expr, h.expr]\n\t\t{\n\t\t\textract im l t w h\n\t\t\t\t= extract_area left' top' width' height' im\n\t\t\t{\n\t\t\t\twidth' = min_pair (to_real w) im.width;\n\t\t\t\theight' = min_pair (to_real h) im.height;\n\t\t\t\tleft' = range 0 (to_real l) (im.width - width');\n\t\t\t\ttop' = range 0 (to_real t) (im.height - height');\n\t\t\t}\n\t\t}\n\t}\n}\n\nTrim_item = class Menuaction \"_Trim\" \"crop away edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthresh = Scale \"threshold\" 0 100 10;\n\t\tbackground = Expression \"Background\" default_background\n\t\t{\n\t\t\tdefault_background \n\t\t\t\t= map mean (bandsplit (extract_area 0 0 1 1 x));\n\t\t}\n\n\t\t_result\n\t\t\t= Region x l t w h\n\t\t{\n\t\t\t[l, t, w, h] = vips_call \"find_trim\" [x.value] [\n\t\t\t\t$threshold => thresh.value,\n\t\t\t\t$background => background.expr\n\t\t\t];\n\t\t}\n\t}\n}\n\nImage_insert_item = class\n\tMenuaction \"_Insert\" \"insert a small image into a large image\" {\n\taction a b \n\t\t= insert_position, is_Group a || is_Group b\n\t\t= insert_area\n\t{\n\t\tinsert_area = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\t// sort to get smallest first\n\t\t\t_pred x y = x.width * x.height < y.width * y.height;\n\t\t\t[_a', _b'] = sortc _pred [a, b];\n\n\t\t\tplace \n\t\t\t\t= Area _b' left top width height\n\t\t\t{\n\t\t\t\t// be careful in case b is smaller than a \n\t\t\t\tleft = max_pair 0 ((_b'.width - _a'.width) / 2);\n\t\t\t\ttop = max_pair 0 ((_b'.height - _a'.height) / 2);\n\t\t\t\twidth = min_pair _a'.width _b'.width;\n\t\t\t\theight = min_pair _a'.height _b'.height;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= insert_noexpand place.left place.top \n\t\t\t\t\t(clip2fmt _b'.format a'') _b'\n\t\t\t{\n\t\t\t\ta'' = extract_area 0 0 place.width place.height _a';\n\t\t\t}\n\t\t}\n\n\t\tinsert_position = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tposition = Option \"Position\" [\n\t\t\t\t\"North-west\",\n\t\t\t\t\"North\",\n\t\t\t\t\"North-east\",\n\t\t\t\t\"West\",\n\t\t\t\t\"Centre\",\n\t\t\t\t\"East\",\n\t\t\t\t\"South-west\",\n\t\t\t\t\"South\",\n\t\t\t\t\"South-east\",\n\t\t\t\t\"Specify in pixels\"\n\t\t\t] 4;\n\t\t\tleft = Expression \"Pixels from left\" 0;\n\t\t\ttop = Expression \"Pixels from top\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_binary insert a b\n\t\t\t{\n\t\t\t\tinsert a b \n\t\t\t\t\t= insert_noexpand left top (clip2fmt b.format a) b, \n\t\t\t\t\t\tposition == 9\n\t\t\t\t\t= insert_noexpand xp yp (clip2fmt b.format a) b\n\t\t\t\t{\n\t\t\t\t\txr = b.width - a.width;\n\t\t\t\t\tyr = b.height - a.height;\n\t\t\t\t\txp = [0, xr / 2, xr]?((int) (position % 3));\n\t\t\t\t\typ = [0, yr / 2, yr]?((int) (position / 3));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_select_item = Select_item;\n\nImage_draw_item = class \n\tMenupullright \"_Draw\" \"draw lines, circles, rectangles, floods\" {\n\tLine_item = class Menuaction \"_Line\" \"draw line on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tx1 = Expression \"Start x\" 0;\n\t\t\ty1 = Expression \"Start y\" 0;\n\t\t\tx2 = Expression \"End x\" 100;\n\t\t\ty2 = Expression \"End y\" 100;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary line x\n\t\t\t{\n\t\t\t\tline im \n\t\t\t\t\t= draw_line x1 y1 x2 y2 i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tRect_item = class Menuaction \"_Rectangle\" \"draw rectangle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\trx = Expression \"Left\" 50;\n\t\t\try = Expression \"Top\" 50;\n\t\t\trw = Expression \"Width\" 100;\n\t\t\trh = Expression \"Height\" 100;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\tt = Scale \"Line thickness\" 1 50 3;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary rect x\n\t\t\t{\n\t\t\t\trect im \n\t\t\t\t\t= draw_rect_width rx ry rw rh f t i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tCircle_item = class Menuaction \"_Circle\" \"draw circle on image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcx = Expression \"Centre x\" 100;\n\t\t\tcy = Expression \"Centre y\" 100;\n\t\t\tr = Expression \"Radius\" 50;\n\n\t\t\tf = Toggle \"Fill\" true;\n\n\t\t\ti = Expression \"Ink\" [0];\n\n\t\t\t_result \n\t\t\t\t= map_unary circle x\n\t\t\t{\n\t\t\t\tcircle im \n\t\t\t\t\t= draw_circle cx cy r f i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tFlood_item = class Menuaction \"_Flood\" \"flood bounded area of image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsx = Expression \"Start x\" 0;\n\t\t\tsy = Expression \"Start y\" 0;\n\n\t\t\te = Option \"Flood while\" [\n\t\t\t\t\"Not equal to ink\",\n\t\t\t\t\"Equal to start point\"\n\t\t\t] 0;\n\n\t\t\t// pick a default ink that won't flood, if we can\n\t\t\ti \n\t\t\t\t= Expression \"Ink\" default_ink\n\t\t\t{\n\t\t\t\tdefault_ink\n\t\t\t\t\t= [0], ! has_image x\n\t\t\t\t\t= pixel;\n\t\t\t\tpixel = map mean (bandsplit (extract_area sx sy 1 1 im));\n\t\t\t\tim = get_image x;\n\t\t\t}\n\n\t\t\t_result \n\t\t\t\t= map_unary flood x\n\t\t\t{\n\t\t\t\tflood im \n\t\t\t\t\t= draw_flood sx sy i.expr im, e == 0\n\t\t\t\t\t= draw_flood_blob sx sy i.expr im;\n\t\t\t}\n\t\t}\n\t}\n\n\tDraw_scalebar_item = class Menuaction \"_Scale\" \"draw scale bar\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpx = Expression \"Left\" 50;\n\t\t\tpy = Expression \"Top\" 50;\n\t\t\twid = Expression \"Width\" 100;\n\t\t\tthick = Scale \"Line thickness\" 1 50 3;\n\t\t\ttext = String \"Dimension text\" \"50μm\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\tpos = Option \"Position Text\" [\"Above\", \"Below\"] 1;\n\t\t\tvp = Option \"Dimension by\" [\n\t\t\t\t\"Inner Vertical Edge\", \n\t\t\t\t\"Centre of Vertical\", \n\t\t\t\t\"Outer Vertical Edge\"\n\t\t\t] 1;\n            dpi = Expression \"DPI\" 100;\n            ink = Colour \"Lab\" [50,0,0];\n      \n            _result\n                = map_unary process x\n            {\n                process im\n                    = blend (Image scale) ink' im\n                {\n                    // make an ink compatible with the image\n                    ink' = colour_transform_to (get_type im) ink;\n\n                    x = to_real px;\n                    y = to_real py;\n                    w = to_real wid;\n                    d = to_real dpi;\n\n                    t = floor thick;\n\n                    bg = image_new (get_width im) (get_height im) (get_bands im)\n                        (get_format im) (get_coding im) (get_type im) 0 0 0;\n                    draw_block x y w t im =\n                        draw_rect_width x y w t true 1 [255] im;\n                    label = im_text text.value font.value w 1 d;\n                    lw = get_width label;\n                    lh = get_height label;\n                    ly = [y - lh - t, y + 2 * t]?pos;\n                    vx = [\n\t\t\t\t\t\t[x - t, x + w],\n\t\t\t\t\t\t[x - t / 2, x + w - t / 2],\n\t\t\t\t\t\t[x, x + w - t]\n\t\t\t\t\t]?vp;\n\n\t\t\t\t\tscale = (draw_block x y w t @\n\t\t\t\t\t\tdraw_block vx?0 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tdraw_block vx?1 (y - 2 * t) t (t * 5) @\n\t\t\t\t\t\tinsert_noexpand (x + w / 2 - lw / 2) ly label)\n\t\t\t\t\t\tbg;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nImage_join_item = class \n\tMenupullright \"_Join\" \"join two or more images together\" {\n\tBandwise_item = class\n\t\tMenuaction \"_Bandwise Join\" \"join two images bandwise\" {\n\t\taction a b = join a b;\n\t}\n\n    sep1 = Menuseparator;\n\n\tjoin_lr shim bg align a b\n\t\t= im2\n\t{\n\t\tw = a.width + b.width + shim;\n\t\th = max_pair a.height b.height;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\tya = [0, max_pair 0 ((b.height - a.height)/2), \n\t\t\tmax_pair 0 (b.height - a.height)]; \n\t\tyb = [0, max_pair 0 ((a.height - b.height)/2), \n\t\t\tmax_pair 0 (a.height - b.height)]; \n\t\n\t\tim1 = insert_noexpand 0 ya?align a back;\n\t\tim2 = insert_noexpand (a.width + shim) yb?align b im1;\n\t}\n\t\n\tjoin_tb shim bg align a b\n\t\t= im2\n\t{\n\t\tw = max_pair a.width b.width;\n\t\th = a.height + b.height + shim;\n\t\n\t\tback = image_new w h a.bands a.format a.coding a.type bg 0 0;\n\t\n\t\txa = [0, max_pair 0 ((b.width - a.width)/2), \n\t\t\tmax_pair 0 (b.width - a.width)]; \n\t\txb = [0, max_pair 0 ((a.width - b.width)/2), \n\t\t\tmax_pair 0 (a.width - b.width)]; \n\t\n\t\tim1 = insert_noexpand xa?align 0 a back;\n\t\tim2 = insert_noexpand xb?align (a.height + shim) b im1;\n\t}\n\n\thalign_names = [\"Top\", \"Centre\", \"Bottom\"];\n\tvalign_names = [\"Left\", \"Centre\", \"Right\"];\n\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two images left-right\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" halign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_lr shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"join two images top-bottom\" {\n\t\taction a b = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tshim = Scale \"Spacing\" 0 100 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\talign = Option \"Alignment\" valign_names 1;\n\t\n\t\t\t_result = map_binary \n\t\t\t\t(join_tb shim.value bg_colour.expr align.value) a b;\n\t\t}\n\t}\n\n    sep2 = Menuseparator;\n\n\tArray_item = class\n\t\tMenuaction \"_Array\" \n\t\t\t\"join a list of lists of images into a single image\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\n\t\t\t// we can't use map_unary since chop-into-tiles returns a group of\n\t\t\t// groups and we want to be able to reassemble that\n\t\t\t// TODO: chop-into-tiles should return an array class which\n\t\t\t// displays as group but does not have the looping behaviour?\n\t\t\t_result \n\t\t\t\t= (image_set_origin 0 0 @ \n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value \n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list x));\n\t\t}\n\t}\n\n\tArrayFL_item = class\n\t\tMenuaction \"_Array from List\"\n\t\t\t\"join a list of images into a single image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tncol = Number \"Max. Number of Columns\" 1;\n\t\t\thshim = Scale \"Horizontal spacing\" (-100) (100) 0;\n\t\t\tvshim = Scale \"Vertical spacing\" (-100) (100) 0;\n\t\t\tbg_colour = Expression \"Background colour\" 0;\n\t\t\thalign = Option \"Horizontal alignment\" valign_names 1;\n\t\t\tvalign = Option \"Vertical alignment\" halign_names 1;\n\t\t\tsnake = Toggle \"Reverse the order of every other row\" false; \n\n\t\t\t_l \n\t\t\t\t= split_lines ncol.value x.value, is_Group x\n\t\t\t\t= split_lines ncol.value x;\n\n\t\t\t_l'\n\t\t\t\t= map2 reverse_if_odd [0..] _l, snake\n\t\t\t\t= _l\n\t\t\t{\n\t\t\t\treverse_if_odd n x\n\t\t\t\t\t= reverse x, n % 2 == 1\n\t\t\t\t\t= x;\n\t\t\t}\n\n\t\t\t_result\n\t\t\t\t= (image_set_origin 0 0 @\n\t\t\t\t\tfoldl1 (join_tb vshim.value bg_colour.expr halign.value) @\n\t\t\t\t\tmap (foldl1 (join_lr hshim.value\n\t\t\t\t\t\tbg_colour.expr valign.value))) (to_list (to_list _l'));\n\t\t}\n\t}\n}\n\nImage_tile_item = class \n\tMenupullright \"Til_e\" \"tile an image across and down\" {\n\ttile_widget default_type x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\t\t\n\t\tacross = Expression \"Tiles across\" 2;\n\t\tdown = Expression \"Tiles down\" 2;\n\t\trepeat = Option \"Tile type\" \n\t\t\t[\"Replicate\", \"Four-way mirror\"] default_type;\n\n\t\t_result\n\t\t\t= map_unary process x\n\t\t{\n\t\t\tprocess image\n\t\t\t\t= tile across down image, repeat == 0\n\t\t\t\t= tile across down image''\n\t\t\t{\n\t\t\t\timage' = insert image.width 0 (fliplr image) image;\n\t\t\t\timage'' = insert 0 image.height (fliptb image') image';\n\t\t\t}\n\t\t}\n\t}\n\n\tReplicate_item = class\n\t\tMenuaction \"_Replicate\" \"replicate image across and down\" {\n\t\taction x = tile_widget 0 x;\n\t}\n\n\tFourway_item = class\n\t\tMenuaction \"_Four-way Mirror\" \"four-way mirror across and down\" {\n\t\taction x = tile_widget 1 x;\n\t}\n\n\tChop_item = class\n\t\tMenuaction \"_Chop Into Tiles\" \"slice an image into tiles\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttile_width = Expression \"Tile width\" 100;\n\t\t\ttile_height = Expression \"Tile height\" 100;\n\t\t\thoverlap = Expression \"Horizontal overlap\" 0;\n\t\t\tvoverlap = Expression \"Vertical overlap\" 0;\n\n\t\t\t_result\n\t\t\t\t= map_unary (Group @ map Group @ process) x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= imagearray_chop tile_width tile_height\n\t\t\t\t\t\thoverlap voverlap x;\n\t\t\t}\n\t\t}\n\t}\n}\n\n#separator\n\nPattern_images_item = class \n\tMenupullright \"_Patterns\" \"make a variety of useful patterns\" {\n\tGrey_item = class \n\t\tMenuaction \"Grey _Ramp\" \"make a smooth grey ramp\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\torientation = Option \"Orientation\" [\n\t\t\t\t\"Horizontal\", \n\t\t\t\t\"Vertical\"\n\t\t\t] 0;\n\t\t\tfoption = Option \"Format\" [\"8 bit\", \"float\"] 0;\n\n\t\t\t_result \n\t\t\t\t= Image im\n\t\t\t{\n\t\t\t\tgen \n\t\t\t\t\t= im_grey, foption == 0\n\t\t\t\t\t= im_fgrey;\n\t\t\t\tw = to_real nwidth;\n\t\t\t\th = to_real nheight;\n\t\t\t\tim \n\t\t\t\t\t= gen w h, orientation == 0\n\t\t\t\t\t= rot90 (gen h w);\n\t\t\t}\n\t\t}\n\t}\n\n\tXy_item = class \n\t\tMenuaction \"_XY Image\" \n\t\t\t\"make a two band image whose pixel values are their coordinates\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\n\t\t\t_result = Image (make_xy nwidth nheight); \n\t\t}\n\t}\n\n\tNoise_item = class\n\t\tMenupullright \"_Noise\" \"various noise generators\" {\n\t\tGaussian_item = class \n\t\t\tMenuaction \"_Gaussian\" \"make an image of gaussian noise\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\t\tmean = Scale \"Mean\" 0 255 128;\n\t\t\t\tdeviation = Scale \"Deviation\" 0 128 50;\n\n\t\t\t\t_result = Image (gaussnoise nwidth nheight \n\t\t\t\t\tmean.value deviation.value);\n\t\t\t}\n\t\t}\n\n\t\tFractal_item = class \n\t\t\tMenuaction \"_Fractal\" \"make a fractal noise image\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tdimension = Scale \"Dimension\" 2.001 2.999 2.001;\n\n\t\t\t\t_result = Image (im_fractsurf (to_real nsize) dimension.value); \n\t\t\t}\n\t\t}\n\n\t\tPerlin_item = class \n\t\t\tMenuaction \"_Perlin\" \"Perlin noise image\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\t\tcell_size = Expression \"Cell size (pixels)\" 8;\n\t\t\t\teight = Toggle \"Eight bit output\" true;\n\n\t\t\t\t_result \n\t\t\t\t\t= 128 * im + 128, eight\n\t\t\t\t\t= im\n\t\t\t\t{\n\t\t\t\t\tim = perlin cell_size nwidth nheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tWorley_item = class \n\t\t\tMenuaction \"_Worley\" \"Worley noise image\" {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnwidth = Expression \"Image width (pixels)\" 512;\n\t\t\t\tnheight = Expression \"Image height (pixels)\" 512;\n\t\t\t\tcell_size = Expression \"Cell size (pixels)\" 256;\n\n\t\t\t\t_result \n\t\t\t\t\t= worley cell_size nwidth nheight;\n\t\t\t}\n\t\t}\n\n\t}\n\n\tCheckerboard_item = class \n\t\tMenuaction \"_Checkerboard\" \"make a checkerboard image\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thpsize = Expression \"Horizontal patch size\" 8;\n\t\t\tvpsize = Expression \"Vertical patch size\" 8;\n\t\t\thpoffset = Expression \"Horizontal patch offset\" 0;\n\t\t\tvpoffset = Expression \"Vertical patch offset\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes ^ ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hpoffset;\n\t\t\t\typixels = pixels?1 + to_real vpoffset;\n\n\t\t\t\tmake_stripe pix swidth = pix % (swidth * 2) >= swidth;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hpsize);\n\t\t\t\tystripes = make_stripe ypixels (to_real vpsize);\n\t\t\t}\n\t\t}\n\t}\n\n\tGrid_item = class \n\t\tMenuaction \"Gri_d\" \"make a grid\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\thspace = Expression \"Horizontal line spacing\" 8;\n\t\t\tvspace = Expression \"Vertical line spacing\" 8;\n\t\t\tthick = Expression \"Line thickness\" 1;\n\t\t\thoff = Expression \"Horizontal grid offset\" 4;\n\t\t\tvoff = Expression \"Vertical grid offset\" 4;\n\n\t\t\t_result\n\t\t\t\t= Image (xstripes | ystripes)\n\t\t\t{\n\t\t\t\tpixels = make_xy nwidth nheight;\n\t\t\t\txpixels = pixels?0 + to_real hoff;\n\t\t\t\typixels = pixels?1 + to_real voff;\n\n\t\t\t\tmake_stripe pix swidth = pix % swidth < to_real thick;\n\n\t\t\t\txstripes = make_stripe xpixels (to_real hspace);\n\t\t\t\tystripes = make_stripe ypixels (to_real vspace);\n\t\t\t}\n\t\t}\n\t}\n\n\tText_item = class \n\t\tMenuaction \"_Text\" \"make a bitmap of some text\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ttext = String \"Text to paint\" \"<i>Hello</i> world!\";\n\t\t\tfont = Fontname \"Use font\" Workspaces.Preferences.PAINTBOX_FONT;\n\t\t\tfontfile = Pathname \"Font file\" \"\";\n\t\t\twidth = Expression \"Text width\" 0;\n\t\t\theight = Expression \"Text height\" 0;\n\t\t\talign = Option \"Alignment\" [\n\t\t\t\t\"Left\",\n\t\t\t\t\"Centre\", \n\t\t\t\t\"Right\" \n\t\t\t] 0;\n\t\t\tdpi = Expression \"DPI\" 300;\n\t\t\tfit = Toggle \"Fit text to box\" false;\n\t\t\tspacing = Expression \"Line spacing\" 0;\n\n\t\t\t_result \n\t\t\t\t= Image out\n\t\t\t{\n\t\t\t\tbase_options = [\n\t\t\t\t\t$font => font.value,\n\t\t\t\t\t$align => align.value\n\t\t\t\t];\n\n\t\t\t\tset_option name default value\n\t\t\t\t\t= [name => value], value != default\n\t\t\t\t\t= [];\n\n\t\t\t\toptions = base_options ++ concat [\n\t\t\t\t\tset_option $width 0 (to_real width),\n\t\t\t\t\tset_option $height 0 (to_real height),\n\t\t\t\t\tset_option $fontfile \"\" fontfile.value,\n\t\t\t\t\tif !fit then set_option $dpi 72 (to_real dpi) else [],\n\t\t\t\t\tset_option $spacing 0 (to_real spacing)\n\t\t\t\t];\n\n\t\t\t\t[out] = vips_call \"text\" [text.value] options;\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_CIELAB_slice_item = class\n\t\tMenuaction \"CIELAB _Slice\" \"make a slice through CIELAB space\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\tL = Scale \"L value\" 0 100 50;\n\n\t\t\t_result = Image (lab_slice (to_real nsize) L.value);\n\t\t}\n\t}\n\n\tsense_option = Option \"Sense\" [\n\t\t\"Pass\", \n\t\t\"Reject\"\n\t] 0;\n\n\tbuild fn size\n\t\t= (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)\n\t\t\t(im_create_fmask size size);\n\n\tNew_ideal_item = class \n\t\tMenupullright \"_Ideal Fourier Mask\" \n\t\t\t\"make various ideal Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\tparam f = f sense.value fc.value 0 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\tparam f = f (sense.value + 6) fc.value rw.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"ideal Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\tparam f = f (sense.value + 12) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_gaussian_item = class \n\t\tMenupullright \"_Gaussian Fourier Mask\" \n\t\t\t\"make various Gaussian Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++\n\t\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\tparam f = f (sense.value + 4) fc.value ac.value 0 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\tparam f = f (sense.value + 10) fc.value rw.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Gaussian Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\tparam f = f (sense.value + 16) fcx.value fcy.value\n\t\t\t\t\t\t\tr.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNew_butterworth_item = class \n\t\tMenupullright \"_Butterworth Fourier Mask\" \n\t\t\t\"make various Butterworth Fourier filter masks\" {\n\t\tHigh_low_item = class \n\t\t\tMenuaction \"_High or Low Pass\" \n\t\t\t\t(\"make a mask image for a highpass/lowpass \" ++ \n\t\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\tparam f = f (sense.value + 2) order.value fc.value \n\t\t\t\t\t\t\tac.value 0 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tRing_item = class \n\t\t\tMenuaction \"_Ring Pass or Ring Reject\"\n\t\t\t\t(\"make a mask image for an ring pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfc = Scale \"Frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\trw = Scale \"Ring width\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\tparam f = f (sense.value + 8) order.value fc.value \n\t\t\t\t\t\trw.value ac.value 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tBand_item = class \n\t\t\tMenuaction \"_Band Pass or Band Reject\"\n\t\t\t\t(\"make a mask image for a band pass/reject \" ++\n\t\t\t\t\"Butterworth Fourier filter\") {\n\t\t\taction = class\n\t\t\t\t_result {\n\t\t\t\t_vislevel = 3;\n\n\t\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\t\t\t\tsense = sense_option;\n\t\t\t\tfcx = Scale \"Horizontal frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tfcy = Scale \"Vertical frequency cutoff\" 0.01 0.99 0.5;\n\t\t\t\tr = Scale \"Radius\" 0.01 0.99 0.5;\n\t\t\t\tac = Scale \"Amplitude cutoff\" 0.01 0.99 0.5;\n\t\t\t\torder = Scale \"Order\" 1 10 2;\n\n\t\t\t\t_result \n\t\t\t\t\t= build param (to_real nsize)\n\t\t\t\t{\n\t\t\t\t\tparam f = f (sense.value + 14) order.value fcx.value\n\t\t\t\t\t\tfcy.value r.value ac.value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nTest_images_item = class \n\tMenupullright \"Test I_mages\" \"make a variety of test images\" {\n\tEye_item = class \n\t\tMenuaction \"_Spatial Response\" \n\t\t\t\"image for testing the eye's spatial response\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tnheight = Expression \"Image height (pixels)\" 64;\n\t\t\tfactor = Scale \"Factor\" 0.001 1 0.2;\n\n\t\t\t_result = Image (im_eye (to_real nwidth) (to_real nheight) \n\t\t\t\tfactor.value);\n\t\t}\n\t}\n\n\tZone_plate = class \n\t\tMenuaction \"_Zone Plate\" \"make a zone plate\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnsize = Expression \"Image size (pixels)\" 64;\n\n\t\t\t_result = Image (im_zone (to_real nsize));\n\t\t}\n\t}\n\n\tFrequency_test_chart_item = class \n\t\tMenuaction \"_Frequency Testchart\" \n\t\t\t\"make a black/white frequency test pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tnwidth = Expression \"Image width (pixels)\" 64;\n\t\t\tsheight = Expression \"Strip height (pixels)\" 10;\n\t\t\twaves = Expression \"Wavelengths\" [64, 32, 16, 8, 4, 2];\n\n\t\t\t_result \n\t\t\t\t= imagearray_assemble 0 0 (transpose [strips])\n\t\t\t{\n\t\t\t\tfreq_slice wave = Image (sin (grey / wave) > 0);\n\t\t\t\tstrips = map freq_slice waves.expr;\n\t\t\t\tgrey = im_fgrey (to_real nwidth) (to_real sheight) * \n\t\t\t\t\t360 * (to_real nwidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tCRT_test_chart_item = class \n\t\tMenuaction \"CRT _Phosphor Chart\" \n\t\t\t\"make an image for measuring phosphor colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbrightness = Scale \"Brightness\" 0 255 200;\n\t\t\tpsize = Expression \"Patch size (pixels)\" 32;\n\n\t\t\t_result \n\t\t\t\t= Image (imagearray_assemble 0 0 [[green, red], [blue, white]])\n\t\t\t{\n\n\t\t\t\tblack = image_new (to_real psize) (to_real psize) 1\n\t\t\t\t\tImage_format.FLOAT Image_coding.NOCODING \n\t\t\t\t\tImage_type.B_W 0 0 0;\n\t\t\t\tnotblack = black + brightness;\n\n\t\t\t\tgreen = black ++ notblack ++ black;\n\t\t\t\tred = notblack ++ black ++ black;\n\t\t\t\tblue = black ++ black ++ notblack;\n\t\t\t\twhite = notblack ++ notblack ++ notblack;\n\t\t\t}\n\t\t}\n\t}\n\n\tGreyscale_chart_item = class \n\t\tMenuaction \"_Greyscale\" \"make a greyscale\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.B_W \n\t\t\t\t\t(clip2fmt Image_format.UCHAR wedge))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tCMYK_test_chart_item = class \n\t\tMenuaction \"_CMYK Wedges\" \"make a set of CMYK wedges\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpwidth = Expression \"Patch width\" 8;\n\t\t\tpheight = Expression \"Patch height\" 8;\n\t\t\tnpatches = Expression \"Number of patches\" 16;\n\n\t\t\t_result\n\t\t\t\t= Image (image_set_type Image_type.CMYK \n\t\t\t\t\t(clip2fmt Image_format.UCHAR strips))\n\t\t\t{\n\t\t\t\twedge \n\t\t\t\t\t= 255 / (to_real npatches - 1) * \n\t\t\t\t\t\t(int) (strip?0 / to_real pwidth)\n\t\t\t\t{\n\t\t\t\t\tstrip = make_xy (to_real pwidth * to_real npatches) pheight;\n\t\t\t\t}\n\n\t\t\t\tblack = wedge * 0;\n\n\t\t\t\tC = wedge ++ black ++ black ++ black;\n\t\t\t\tM = black ++ wedge ++ black ++ black;\n\t\t\t\tY = black ++ black ++ wedge ++ black;\n\t\t\t\tK = black ++ black ++ black ++ wedge;\n\n\t\t\t\tstrips = imagearray_assemble 0 0 [[C],[M],[Y],[K]];\n\t\t\t}\n\t\t}\n\t}\n\n\tColour_atlas_item = class\n\tMenuaction \"_Colour Atlas\"\n\t\t\"make a grid of patches grouped around a colour\" {\n\t\taction = class \n\t\t\t_result {   \n\t\t\t_vislevel = 3;\n       \n\t\t\tstart = Colour_picker \"Lab\" [50,0,0];\n\t\t\tnstep = Expression \"Number of steps\" 9;\n\t\t\tssize = Expression \"Step size\" 10; \n\t\t\tpsize = Expression \"Patch size\" 32;\n\t\t\tsepsize = Expression \"Separator size\" 4;\n\t\n\t\t\t_result\n\t\t\t\t= colour_transform_to (get_type start) blocks'''\n\t\t\t{\n\t\t\t\tsize = (to_real nstep * 2 + 1) * to_real psize - \n\t\t\t\t\tto_real sepsize;\n\t\t\t\txy = make_xy size size; \n\n\t\t\t\txy_grid = (xy % to_real psize) < \n\t\t\t\t\t(to_real psize - to_real sepsize);\n\t\t\t\tgrid = xy_grid?0 & xy_grid?1;\n\n\t\t\t\tblocks = (int) (to_real ssize * ((int) (xy / to_real psize)));\n\t\t\t\tlab_start = colour_transform_to Image_type.LAB start;\n\t\t\t\tblocks' = blocks - to_real nstep * to_real ssize + \n\t\t\t\t\tVector (tl lab_start.value);\n\t\t\t\tblocks'' = hd lab_start.value ++ Image blocks';\n\t\t\t\tblocks''' \n\t\t\t\t\t= image_set_type Image_type.LAB blocks'', Image grid\n\t\t\t\t\t= 0;\n            }    \n        }\n    }\n}\n\n"
  },
  {
    "path": "share/nip2/start/Magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate Magick.def\n   13-Apr-2014 snibgo\n     Put \"new image\" items into sub-menu.\n     New class VirtualPixlBack.\n   17-Apr-2014 snibgo\n     Many small changes.\n     A few new menu options.\n     Created sub-menu for multi-input operations.\n   3-May-2014 jcupitt\n     Put quotes around ( in shadow to help unix\n\n   Last update: 17-Apr-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n*/\n\n// We don't need Noop.\n/*===\nMagick_noop_item = class\n\tMenuaction \"_Noop\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_testPar_item = class\n\tMenuaction \"_TestPar\" \"no operation\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"( +clone ) +append \",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/* Removed Read_item and Write_item, much better to use nip2 load/save image.\n * Plus they can load all libMagick formats anyway.\n */\n\n\n// Put \"new image\" items into sub-menu\nMagick_NewImageMenu_item = class\n\tMenupullright \"_New image\" \"make a new image\" {\n\n\tMagick_newcanvas_item = class\n\t\tMenuaction \"_Solid colour\" \"make image of solid colour\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tcolour = Magick.generalcol_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"\\\"canvas:\" ++ colour._flag ++ \"\\\"\", \n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_builtin_item = class\n\t\tMenuaction \"_Built-in image\" \"create a built-in image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tbuiltin = Magick.builtin_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tbuiltin._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_gradient_item = class\n\t\tMenuaction \"_Gradient\" \"make a linear gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\ttopColour = Magick.generalcol_widget;\n\t\t\tbottomColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"gradient:\", \n\t\t\t\t\ttopColour._flag, \"-\", bottomColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_hald_item = class\n\t\tMenuaction \"_Hald-clut image\" \"create an identity hald-clut image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\torder = Expression \"order\" 8;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"hald:\" ++ print order.expr,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_pattern_item = class\n\t\tMenuaction \"_Pattern\" \"create pattern\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tpattern = Magick.pattern_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tpattern._flag,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_plasma_item = class\n\t\tMenuaction \"_Plasma image\" \"create plasma image\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\t// FIXME? ColourA-ColourB.\n\t\t\t// FIXME? Allow plasma:fractal?\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\t\"plasma:\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n\n\tMagick_radialgradient_item = class\n\t\tMenuaction \"_Radial gradient\" \n\t\t\t\"make a radial gradient between two colours\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsize = Magick.Size_widget;\n\t\t\tinnerColour = Magick.generalcol_widget;\n\t\t\touterColour = Magick.generalcol_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\tsize._flag,\n\t\t\t\tconcat [\"\\\"radial-gradient:\", \n\t\t\t\t\tinnerColour._flag, \"-\", outerColour._flag, \"\\\"\"],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system0 command; \n\t\t}\n\t}\n}  // end Magick_NewImageMenu_item\n\n\nMagick_MultiMenu_item = class\n\tMenupullright \"_Multiple inputs\" \"make an image from multiple images\" {\n\n\tMagick_composite_item = class\n\t\tMenuaction \"_Composite\" \"composite two images (without mask)\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag,\n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_compositeMask_item = class\n\t\tMenuaction \"_Composite masked\" \"composite two images (with mask)\" {\n\t\taction x y z = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tmethod = Magick.compose_widget;\n\t\t\toffsets = Magick.OffsetGeometry_widget;\n\t\t\tgravity = Magick.gravity_widget; \n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-geometry\", offsets._flag,\n\t\t\t\tgravity._flag,\n\t\t\t\tmethod._flag, \n\t\t\t\t\"-composite\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system3 command x y z; \n\t\t}\n\t}\n\n\t// FIXME: other operations like remap that take another image as arguments are:\n\t// mask (pointless?), texture, tile (pointless?)\n\n\t// FIXME: operations that take a filename that isn't an image:\n\t// cdl, profile\n\n\tMagick_clut_item = class\n\t\tMenuaction \"_Clut\" \"replace values using second image as colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t// FIXME: uses -intensity \"when mapping greyscale CLUT image to alpha channel if set by -channels\"\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\tMagick_haldclut_item = class\n\t\tMenuaction \"_Hald clut\" \"replace values using second image as Hald colour look-up table\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-hald-clut\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n\n\t// Encipher and decipher: key files can be text or image files.\n\n\tMagick_encipher_item = class\n\t\tMenuaction \"_Encipher/Decipher\" \"encipher or decipher an image image\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname = Pathname \"Read key file\" \"\";\n\t\t\tisDecipher = Toggle \"Decipher\" false;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname.value == \"\" then \"\" else (\n\t\t\t\t\t( if isDecipher then \"-decipher \" else \"-encipher \") ++\n\t\t\t\t\t( \"\\\"\" ++ pathname.value ++ \"\\\"\" )\n\t\t\t\t),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_profile_item = class\n\t\tMenuaction \"_Profile\" \"assigns/applies an ICC profile\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpathname1 = Pathname \"Read profile file\" \"\";\n\t\t\tpathname2 = Pathname \"Read profile file\" \"\";\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tif pathname1.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname1.value ++ \"\\\"\"),\n\t\t\t\tif pathname2.value == \"\" then \"\" else (\n\t\t\t\t\t\"-profile \" ++\n\t\t\t\t\t\"\\\"\" ++ pathname2.value ++ \"\\\"\"),\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_remap_item = class\n\t\tMenuaction \"_Remap\" \"reduce colours to those in another image\" {\n\t\taction x y = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-remap\",\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system2 command x y; \n\t\t}\n\t}\n\n}  // end Magick_MultiMenu_item\n\n\nMagick_image_type_item = class\n\tMenuaction \"_Image Type\" \"change image type\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\timagetype = Magick.imagetype_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\timagetype._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nsep2 = Menuseparator;\n\nMagick_alpha_item = class\n\tMenuaction \"_Alpha\" \"add/remove alpha channel\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\talpha = Magick.alpha_widget; \n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\talpha._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_annotate_item = class\n\tMenuaction \"_Annotate\" \"add text annotation\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttext = Magick.text_widget;\n\t\tfont = Magick.Font_widget;\n\t\tgeometry = Magick.AnnotGeometry_widget; \n\t\tgravity = Magick.gravity_widget; \n\t\tforeground = Magick.foreground_widget;\n\t\tundercol = Magick.undercol_widget;\n\t\tantialias = Magick.antialias_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfont._flag,\n\t\t\tantialias._flag,\n\t\t\tgravity._flag,\n\t\t\tforeground._flag,\n\t\t\tundercol._flag,\n\t\t\t\"-annotate\", \n\t\t\tgeometry._flag, \n\t\t\t\"\\\"\" ++ text.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoGamma_item = class\n\tMenuaction \"_AutoGamma\" \"automatic gamma\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-gamma\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_autoLevel_item = class\n\tMenuaction \"_AutoLevel\" \"automatic level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-auto-level\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_blurSharpMenu_item = class\n\tMenupullright \"_Blur/Sharpen\" \"blur and sharpen\" {\n\n\tMagick_adaptive_blur_item = class\n\t\tMenuaction \"_Adaptive Blur\" \"blur less near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\t// note: adaptive-blur doesn't regard VP.\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-adaptive-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blur_item = class\n\t\tMenuaction \"_Blur\" \"blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_gaussianBlur_item = class\n\t\tMenuaction \"_Gaussian Blur\" \"blur with a Gaussian operator\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-gaussian-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_motionBlur_item = class\n\t\tMenuaction \"_Motion Blur\" \"simulate motion blur\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tangle = Scale \"angle\" (-360) 360 0;\n\t\t\tchannels = Magick.ch_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-motion-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_rotationalBlur_item = class\n\t\tMenuaction \"_RotationalBlur\" \"blur around the centre\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-radial-blur\", \n\t\t\t\tprint angle.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_selectiveBlur_item = class\n\t\tMenuaction \"_Selective Blur\" \"blur where contrast is less than or equal to threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag,\n\t\t\t\t\"-selective-blur\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++  \"+\" ++\n\t\t\t\t\tprint threshold.value ++ \"%%\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMagick_adaptive_sharpen_item = class\n\t\tMenuaction \"_Adaptive Sharpen\" \"sharpen more near edges\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\t\"-adaptive-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_sharpen_item = class\n\t\tMenuaction \"_Sharpen\" \"sharpen\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-sharpen\",\n\t\t\t\tprint radius.value ++ \"x\" ++ print sigma.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_unsharpen_item = class\n\t\tMenuaction \"_Unsharp\" \"sharpen with unsharp mask\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tradius = Magick.blur_rad_widget; \n\t\t\tsigma = Magick.sigma_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tgain = Scale \"Gain\" (-10) 10 1;\n\t\t\tthreshold = Scale \"Threshold\" 0 1 0.05;\n\t\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tvirtpixback._flag, \n\t\t\t\tchannels._flag, \n\t\t\t\t\"-unsharp\",\n\t\t\t\tprint radius.value ++ \"x\" ++\n\t\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\t\tprint gain.value ++ \"+\" ++\n\t\t\t\t\tprint threshold.value,\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end BlurSharpMenu_item\n\n\nMagick_border_item = class\n\tMenuaction \"_Border\" \"add border of given colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcompose = Magick.compose_widget;\n\t\twidth = Expression \"Width\" 3;\n\t\tbordercol = Magick.bordercol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag,\n\t\t\tbordercol._flag,\n\t\t\t\"-border\", \n\t\t\tprint width.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_brightCont_item = class\n\tMenuaction \"_Brightness-contrast\" \"adjust the brightness and/or contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbri = Scale \"brightness\" (-100) 100 0;\n\t\tcon = Scale \"contrast\" (-100) 100 0;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-brightness-contrast\", \n\t\t\tprint bri.value ++ \"x\" ++ print con.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// Note: canny requires ImageMagick 6.8.9-0 or later.\n\nMagick_canny_item = class\n\tMenuaction \"_Canny\" \"detect a wide range of edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tlowPc = Scale \"lower percent\" 0 100 10;\n\t\thighPc = Scale \"lower percent\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-canny\", \n\t\t\tconcat [\"\\\"\",\n\t\t\t\tprint radius.value ++ \"x\" ++ \n\t\t\t\tprint sigma.value ++ \"+\" ++\n\t\t\t\tprint lowPc.value ++ \"%%+\" ++\n\t\t\t\tprint highPc.value ++ \"%%\" ++ \"\\\"\"\n\t\t\t],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_charcoal_item = class\n\tMenuaction \"_Charcoal\" \"simulate a charcoal drawing\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tfactor = Scale \"factor\" 0 50 1;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-charcoal\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_chop_item = class\n\tMenuaction \"_Chop\" \"remove pixels from the interior\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-chop\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorize_item = class\n\tMenuaction \"_Colorize\" \"colorize by given amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tval = Scale \"value\" 0 100 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-colorize\", \n\t\t\tprint val.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colors_item = class\n\tMenuaction \"_Colors\" \"reduce number of colors\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\t\tquantize = Magick.colorspace_widget;\n\t\tcolors = Expression \"Colours\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-quantize\", quantize._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\tdither._flag,\n\t\t\t\"-colors\", \n\t\t\tprint colors.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: color-matrix?\n\nMagick_colorspace_item = class\n\tMenuaction \"_Colourspace\" \"convert to arbitrary colourspace\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolsp = Magick.colorspace_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-colorspace\",\n\t\t\tcolsp._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_colorspaceGray_item = class\n\tMenuaction \"_Colourspace gray\" \"convert to gray using given intensity method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\t\"-colorspace gray\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrast_item = class\n\tMenuaction \"_Contrast\" \"increase or reduce the contrast\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tisReduce = Toggle \"reduce contrast\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t(if isReduce then \"+\" else \"-\") ++ \"contrast\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_contrastStretch_item = class\n\tMenuaction \"_Contrast stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-contrast-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: convolve (bias, kernel)\n\nMagick_crop_item = class\n\tMenuaction \"_Crop\" \"cut out a rectangular region\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tgravity._flag,\n\t\t\t\"-crop\",\n\t\t\tgeometry._flag,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_deskew_item = class\n\tMenuaction \"_Deskew\" \"straighten the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\t// FIXME: toggle auto-crop?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-deskew\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_despeckle_item = class\n\tMenuaction \"_Despeckle\" \"reduce the speckles\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-despeckle\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_distort_item = class\n\tMenuaction \"_Distort\" \"distort using a method and arguments\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tdistort = Magick.distort_widget;\n\t\targs = String \"Arguments\" \"1,0\";\n\t\tisPlus = Toggle \"Extend to show entire image\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t(if isPlus then \"+\" else \"-\") ++ \"distort\",\n\t\t\tdistort._flag,\n\t\t\targs.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_draw_item = class\n\tMenuaction \"_Draw\" \"annotate with one or more graphic primitives\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\targs = String \"Arguments\" \"line 0,0 9,9 rectangle 10,10 20,20\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-draw\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_edge_item = class\n\tMenuaction \"_Edge\" \"detect edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-edge\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_emboss_item = class\n\tMenuaction \"_Emboss\" \"emboss\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"Radius\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-emboss\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_enhance_item = class\n\tMenuaction \"_Enhance\" \"enhance a noisy image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-enhance\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_equalize_item = class\n\tMenuaction \"_Equalize\" \"equalize the histogram\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-equalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_evaluate_item = class\n\tMenuaction \"_Evaluate\" \"evaluate an expression on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\toperation = Magick.evaluate_widget;\n\t\tval = Expression \"value\" 5;\n\t\tisPc = Toggle \"Value is percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag, \n\t\t\toperation._flag, \n\t\t\tprint val.expr ++ if isPc then \"%%\" else \"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_extent_item = class\n\tMenuaction \"_Extent\" \"set the image size and offset\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-extent\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\nMagick_FlipFlopMenu_item = class\n\tMenupullright \"_Flip/flop\" \"flip/flop/transverse/transpose\" {\n\n\tMagick_flip_item = class\n\t\tMenuaction \"_Flip vertically\" \"mirror upside-down\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flip\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_flop_item = class\n\t\tMenuaction \"_Flop horizontally\" \"mirror left-right\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-flop\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transpose_item = class\n\t\tMenuaction \"_Transpose\" \"mirror along the top-left to bottom-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transpose +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_transverse_item = class\n\t\tMenuaction \"_Transverse\" \"mirror along the bottom-left to top-right diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-transverse +repage\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end Magick_FlipFlopMenu_item\n\n\nMagick_floodfill_item = class\n\tMenuaction \"_Floodfill\" \"recolour neighbours that match\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tfuzz = Magick.fuzz_widget;\n\t\tcoordinate = Magick.coordinate_widget;\n\n\t\t// -draw \"color x,y floodfill\"\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-draw \\\" color\",\n\t\t\tcoordinate._flag,\n\t\t\t\"floodfill \\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_frame_item = class\n\tMenuaction \"_Frame\" \"surround with border or beveled frame\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tborder = Magick.bordercol_widget;\n\t\tcompose = Magick.compose_widget;\n\t\tmatte = Magick.mattecol_widget;\n\t\tgeometry = Magick.FrameGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tcompose._flag, \n\t\t\tborder._flag, \n\t\t\tmatte._flag, \n\t\t\t\"-frame\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_function_item = class\n\tMenuaction \"_Function\" \"evaluate a function on each pixel channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfunction = Magick.function_widget;\n\t\t// FIXME: explain values; use sensible defaults.\n\t\tvalues = String \"values\" \"0,0,0,0\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-function\", \n\t\t\tfunction._flag, \n\t\t\tvalues.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_fx_item = class\n\tMenuaction \"_Fx\" \"apply a mathematical expression\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\targs = String \"Expression\" \"u*1/2\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\tinterpolate._flag,\n\t\t\tvirtpixback._flag,\n\t\t\t\"-fx\",\n\t\t\tconcat [\"\\\"\", args.value, \"\\\"\"],\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gamma_item = class\n\tMenuaction \"_Gamma\" \"apply a gamma correction\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tgamma = Magick.gamma_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-gamma\",\n\t\t\tprint gamma.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradient_item = class\n\tMenuaction \"_Gradient\" \"apply a linear gradient\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolourA = Magick.generalcol_widget;\n\t\tcolourB = Magick.generalcol_widget;\n\n\t\tposition = Option \"colourA is at\" [\n\t\t\t\t\"top\", \"bottom\", \n\t\t\t\t\"left\", \"right\", \n\t\t\t\t\"top-left\", \"top-right\", \n\t\t\t\t\"bottom-left\", \"bottom-right\"] 0;\n\t\t_baryArg\n\t\t\t= concat [\"0,0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 0\n\t\t\t= concat [\"0,0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 1\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],0,\", colourB._flag], position.value == 2\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],0,\", colourA._flag], position.value == 3\n\t\t\t= concat [\"0,0,\", colourA._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourB._flag], position.value == 4\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourA._flag, \" 0,%%[fx:h-1],\", colourB._flag], position.value == 5\n\t\t\t= concat [\"%%[fx:w-1],0,\", colourB._flag, \" 0,%%[fx:h-1],\", colourA._flag], position.value == 6\n\t\t\t= concat [\"0,0,\", colourB._flag, \" %%[fx:w-1],%%[fx:h-1],\", colourA._flag], position.value == 7\n\t\t\t= \"dunno\";\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color barycentric \\\"\" ++ _baryArg ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_gradientCorn_item = class\n\tMenuaction \"_Gradient corners\" \n\t\t\"apply a bilinear gradient between the corners\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcolour_top_left = Magick.generalcol_widget;\n\t\tcolour_top_right = Magick.generalcol_widget;\n\t\tcolour_bottom_left = Magick.generalcol_widget;\n\t\tcolour_bottom_right = Magick.generalcol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sparse-color bilinear \\\"\" ++\n\t\t\t\t\"0,0,\" ++ colour_top_left._flag ++\n\t\t\t\t\",%%[fx:w-1],0\" ++ colour_top_right._flag ++\n\t\t\t\t\",0,%%[fx:h-1]\" ++ colour_bottom_left._flag ++\n\t\t\t\t\",%%[fx:w-1],%%[fx:h-1]\" ++ colour_bottom_right._flag ++ \"\\\"\",\n\t\t\t\"+depth\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_histogram_item = class\n\tMenuaction \"_Histogram\" \"make a histogram image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-define histogram:unique-colors=false histogram:\" ++\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_implode_item = class\n\tMenuaction \"_Implode\" \"implode pixels about the center\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfactor = Scale \"factor\" 0 20 1;\n\t\tinterpolate = Magick.interpolate_widget;\n\t\t// FIXME: virtual-pixel?\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tinterpolate._flag,\n\t\t\t\"-implode\", \n\t\t\tprint factor.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_level_item = class\n\tMenuaction \"_Level\" \"adjust the level of channels\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"black point\" (-100) 200 0;\n\t\twht = Scale \"white point\" (-100) 200 100;\n\t\tgam = Scale \"gamma\" 0 30 1;\n\t\tisPc = Toggle \"Levels are percent\" true;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \",\" ++ \n\t\t\t\tprint wht.value ++ (if isPc then \"%%\" else \"\") ++ \",\" ++ \n\t\t\t\tprint gam.value ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_levelCols_item = class\n\tMenuaction \"_Level colors\" \"adjust levels to given colours\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcolour_black = Magick.generalcol_widget;\n\t\tcolour_white = Magick.generalcol_widget;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"level-colors\",\n\t\t\t\"\\\"\" ++ colour_black._flag ++ \",\" ++ colour_white._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_linearStretch_item = class\n\tMenuaction \"_Linear stretch\" \"stretches tones, making some black/white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tblk = Scale \"percent to make black\" 0 100 0;\n\t\twht = Scale \"percent to make white\" 0 100 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-linear-stretch\",\n\t\t\t\"\\\"\" ++ print blk.value ++ \"x\" ++ print wht.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_magnify_item = class\n\tMenuaction \"_Magnify\" \"double the size of the image with pixel art scaling\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-magnify\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_modulate_item = class\n\tMenuaction \"_Modulate\" \"modulate brightness, saturation and hue\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmodcolsp = Magick.ModColSp_widget;\n\t\tbright = Scale \"brightness\" 0 200 100;\n\t\tsat = Scale \"saturation\" 0 200 100;\n\t\thue = Scale \"hue\" 0 200 100;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tmodcolsp._flag,\n\t\t\t\"-modulate\",\n\t\t\tprint bright.value ++ \",\" ++ print sat.value ++ \",\" ++ \n\t\t\t\tprint hue.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_monochrome_item = class\n\tMenuaction \"_Monochrome\" \"transform to black and white\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// FIXME: also intensity?\n\n\t\tintensity = Magick.intensity_widget;\n\t\ttreedepth = Expression \"Treedepth\" 8;\n\t\tdither = Magick.dither_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tdither._flag,\n\t\t\t\"-treedepth\", \n\t\t\tprint treedepth.expr, \n\t\t\t\"-monochrome\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_morphology_item = class\n\t// See http://www.imagemagick.org/Usage/morphology/\n\tMenuaction \"_Morphology\" \"apply a morphological method\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tmethod = Magick.morphmeth_widget;\n\t\titer = Expression \"Iterations (-1=repeat until done)\" 1;\n\n\t\tkernel = Magick.kernel_widget;\n\t\t// FIXME: custom kernel eg \"3x1+2+0:1,0,0\"\n\t\t//   width x height + offsx + offsy : {w*h values}\n\t\t//   each value is 0.0 to 1.0 or \"NaN\" or \"-\"\n\n\t\t// kernel args, mostly float radius,scale. radius=0=default. default scale = 1.0\n\t\t// but\n\t\t//   ring takes: radius1, radius2, scale\n\t\t//   rectangle and comet take: width x height + offsx + offsy\n\t\t//   blur takes: radius x sigma\n\t\t// FIXME: for now, simply allow any string input.\n\t\tkernel_arg = String \"Kernel arguments\" \"\";\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-morphology\",\n\t\t\tmethod._flag ++ \":\" ++ print iter.expr, \n\t\t\tkernel._flag ++\n\t\t\t(if kernel_arg.value == \"\" then \"\" else \":\") ++ kernel_arg.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_negate_item = class\n\tMenuaction \"_Negate\" \"negate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-negate\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_addNoise_item = class\n\tMenuaction \"_add Noise\" \"add noise\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tattenuate = Scale \"attenuate\" 0 1.0 1.0;\n\t\tnoise = Magick.noise_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-attenuate\", \n\t\t\tprint attenuate.value,\n\t\t\tnoise._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_normalize_item = class\n\tMenuaction \"_Normalize\" \"normalize\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tintensity = Magick.intensity_widget;\n\t\tchannels = Magick.channels_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tintensity._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-normalize\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_opaque_item = class\n\tMenuaction \"_Opaque\" \"change this colour to the fill colour\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tfill = Magick.foreground_widget;\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfill._flag,\n\t\t\tchannels._flag,\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"opaque\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_paint_item = class\n\tMenuaction \"_Paint\" \"simulate an oil painting\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trad = Expression \"radius\" 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-paint\",\n\t\t\tprint rad.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n/*=== FIXME Bug; remove for now.\nPolaroid_item = class\n\tMenuaction \"_Polaroid\" \"simulate a polaroid picture\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle\" (-90) 90 20;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-polaroid\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n===*/\n\nMagick_posterize_item = class\n\tMenuaction \"_Posterize\" \"reduce to (n) levels per channel\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tlevels = Expression \"levels\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-posterize\",\n\t\t\tprint levels.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_raise_item = class\n\tMenuaction \"_Raise\" \"lighten or darken image edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthk = Expression \"Thickness\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-raise\",\n\t\t\tprint thk.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_resize_item = class\n\tMenuaction \"_Resize\" \"resize to given width and height\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfilter = Magick.filter_widget;\n\t\ttype = Magick.ResizeType_widget;\n\t\twidth = Scale \"Width\" 1 100 10;\n\t\theight = Scale \"Height\" 1 100 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tfilter._flag,\n\t\t\t\"-\" ++ type._flag,\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"!\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_roll_item = class\n\tMenuaction \"_Roll\" \"roll an image horizontally or vertically\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\trollx = Expression \"X\" 3;\n\t\trolly = Expression \"Y\" 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-roll\",\n\t\t\t(if rollx.expr >= 0 then \"+\" else \"\") ++ print rollx.expr ++\n\t\t\t(if rolly.expr >= 0 then \"+\" else \"\") ++ print rolly.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_rotate_item = class\n\tMenuaction \"_Rotate\" \"rotate\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Scale \"angle (degrees)\" (-360) 360 20;\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"+distort\",\n\t\t\t\"SRT\",\n\t\t\tprint angle.value,\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -segment, but cluster-threshold should be percentage of image area.\n\nMagick_sepia_item = class\n\tMenuaction \"_Sepia tone\" \"simulate a sepia-toned photo\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 80;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sepia-tone\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shade_item = class\n\tMenuaction \"_Shade\" \"shade with a distant light source\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tazimuth = Scale \"Azimuth (degrees)\" (-360) 360 0;\n\t\televation = Scale \"Elevation (degrees)\" 0 90 45;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shade\",\n\t\t\tprint azimuth.value ++ \"x\" ++ print elevation.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shadow_item = class\n\tMenuaction \"_Shadow\" \"simulate a shadow\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshadowCol = Magick.generalcol_widget;\n\t\topacity = Scale \"Opacity (percent)\" 0 100 75;\n\t\tsigma = Scale \"Sigma\" 0 30 2;\n\t\t// FIXME: make offsets a single widget?\n\t\toffsx = Scale \"X-offset\" (-20) 20 4;\n\t\toffsy = Scale \"Y-offset\" (-20) 20 4;\n\t\tarePc = Toggle \"offsets are percentages\" false;\n\n\t\t// FIXME: raw operation creates page offset, which vips dislikes.\n\t\t// So we take this futher, compositing with source.\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"\\\"(\\\" +clone\",\n\t\t\t\"-background\", \"\\\"\" ++ shadowCol._flag ++ \"\\\"\",\n\t\t\t\"-shadow\",\n\t\t\tconcat [\n\t\t\t\t\"\\\"\",\n\t\t\t\tprint opacity.value, \"x\", print sigma.value,\n\t\t\t\t(if offsx.value >= 0 then \"+\" else \"\"), print offsx.value,\n\t\t\t\t(if offsy.value >= 0 then \"+\" else \"\"), print offsy.value,\n\t\t\t\t(if arePc then \"%%\" else \"\"),\n\t\t\t\t\"\\\"\"\n\t\t\t],\n\t\t\t\"\\\")\\\" +swap -background None -layers merge\",\n\t\t\t\"+repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shave_item = class\n\tMenuaction \"_Shave\" \"shave pixels from the edges\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Scale \"Width\" 0 50 10;\n\t\theight = Scale \"Height\" 0 50 10;\n\t\tisPc = Toggle \"Width and height are percent\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-shave\",\n\t\t\t\"\\\"\" ++ print width.value ++ \"x\" ++ print height.value ++\n\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_shear_item = class\n\tMenuaction \"_Shear\" \"shear along the x-axis and/or y-axis\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-shear\",\n\t\t\tprint shearX.expr ++ \"x\" ++ print shearY.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sigmoid_item = class\n\tMenuaction \"_Sigmoid\" \"increase or decrease mid-tone contrast sigmoidally\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tcontrast = Scale \"contrast\" 0 30 3;\n\t\tmidpoint = Scale \"mid-point (percent)\" 0 100 50;\n\t\tisInv = Toggle \"Invert effect\" false;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t(if isInv then \"+\" else \"-\") ++ \"sigmoidal-contrast\",\n\t\t\t\"\\\"\" ++ print contrast.value ++ \"x\" ++ \n\t\t\t\tprint midpoint.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_sketch_item = class\n\tMenuaction \"_Sketch\" \"simulate a pencil sketch\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\tangle = Scale \"angle\" (-360) 360 0;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-sketch\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if angle >= 0 then (\"+\" ++ print angle.value) else \"\"),\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_solarize_item = class\n\tMenuaction \"_Solarize\" \"negate all pixels above a threshold level\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchannels = Magick.channels_widget;\n\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tchannels._flag,\n\t\t\t\"-solarize\",\n\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n// FIXME: -sparse-color needs abitrary list of {x,y,colour}.\n\nMagick_splice_item = class\n\tMenuaction \"_Splice\" \"splice a colour into the image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tbackground = Magick.background_widget;\n\t\tgravity = Magick.gravity_widget; \n\t\tgeometry = Magick.WhxyGeometry_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag, \n\t\t\tgravity._flag,\n\t\t\t\"-splice\", \n\t\t\tgeometry._flag,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_spread_item = class\n\tMenuaction \"_Spread\" \"displace pixels by random amount\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tvirtpixback = Magick.VirtualPixelBack_widget;\n\t\tamount = Expression \"Amount (pixels)\" 5;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tvirtpixback._flag,\n\t\t\t\"-spread\",\n\t\t\tprint amount.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_statistic_item = class\n\tMenuaction \"_Statistic\" \"replace each pixel with statistic from neighbourhood\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width\" 5;\n\t\theight = Expression \"Height\" 5;\n\t\tstatisticType = Magick.StatType_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-statistic\", \n\t\t\tstatisticType._flag, \n\t\t\tprint width.expr ++ \"x\" ++ print height.expr,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_swirl_item = class\n\tMenuaction \"_Swirl\" \"swirl around the centre\" {\n\taction x = class \n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tangle = Magick.angle_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-swirl\",\n\t\t\tprint angle.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_thresholdMenu_item = class\n\tMenupullright \"_Threshold\" \"make black or white\" {\n\n\tMagick_threshold_item = class\n\t\tMenuaction \"_Threshold\" \"apply black/white threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tintensity = Magick.intensity_widget;\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tintensity._flag,\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-threshold\", \n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_blackThreshold_item = class\n\t\tMenuaction \"_Black threshold\" \"where below threshold set to black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-black-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_whiteThreshold_item = class\n\t\tMenuaction \"_White threshold\" \"where above threshold set to white\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tthreshold = Scale \"Threshold (percent)\" 0 100 50;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-white-threshold\",\n\t\t\t\t\"\\\"\" ++ print threshold.value ++ \"%%\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_latThreshold_item = class\n\t\tMenuaction \"_Local Adaptive Threshold\" \"where above average plus offset set to white, otherwise black\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twidth = Expression \"Width\" 10;\n\t\t\theight = Expression \"Height\" 10;\n\t\t\toffset = Scale \"Offset (percent)\" (-100) 100 0;\n\t\t\t// note: \"-lat\" doesn't respond to channels\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\t\"-lat\",\n\t\t\t\tconcat [\"\\\"\", print width.expr, \"x\", print height.expr, \n\t\t\t\t\t(if offset.value >= 0 then \"+\" else \"\"), print offset.value,\n\t\t\t\t\t\"%%\\\"\"\n\t\t\t\t],\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n\tMagick_randThreshold_item = class\n\t\tMenuaction \"_Random Threshold\" \"between specified limits, apply random threshold\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tchannels = Magick.channels_widget;\n\t\t\tlow = Scale \"Low threshold\" 0 100 10;\n\t\t\thigh = Scale \"High threshold\" 0 100 90;\n\t\t\tisPc = Toggle \"Thresholds are percent\" true;\n\n\t\t\tcommand = Magick.command [\n\t\t\t\t\"\\\"%s\\\"\",\n\t\t\t\tchannels._flag,\n\t\t\t\t\"-random-threshold\", \n\t\t\t\t\"\\\"\" ++ print low.value ++ \"x\" ++ print high.value ++\n\t\t\t\t\t(if isPc then \"%%\" else \"\") ++ \"\\\"\",\n\t\t\t\t\"\\\"%s\\\"\"\n\t\t\t];\n\n\t\t\t_result = Magick.system command x; \n\t\t}\n\t}\n\n} // end ThresholdMenu_item\n\n\n// Note: alternatives include:\n// convert in.tif -write mpr:TILE +delete -size 200x200 -background XXXX -tile-offset +30+30 tile:mpr:TILE out.tif\n\nMagick_tile_item = class\n\tMenuaction \"_Tile\" \"fill given size with tiled image\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tsize = Magick.Size_widget;\n\n\t\tcommand = Magick.command [\n\t\t\tsize._flag,\n\t\t\t\"tile:\" ++ \"\\\"%s\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_tint_item = class\n\tMenuaction \"_Tint\" \"apply a tint\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tforeground = Magick.foreground_widget;\n\t\tamount = Scale \"amount (percent)\" 0 100 50;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tforeground._flag,\n\t\t\t\"-tint\",\n\t\t\t// snibgo note: although the amount is a percentage, it doesn't need \"%\" character.\n\t\t\tprint amount.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_transparent_item = class\n\tMenuaction \"_Transparent\" \"make this colour transparent\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tchangeColour = Magick.changeCol_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print changeColour.fuzz.value ++ \"%%\\\"\",\n\t\t\t(if changeColour.nonMatch then \"+\" else \"-\") ++ \"transparent\",\n\t\t\t\"\\\"\" ++ changeColour.colour._flag ++ \"\\\"\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_trim_item = class\n\tMenuaction \"_Trim\" \"trims away border\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tfuzz = Magick.fuzz_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-fuzz\",\n\t\t\t\"\\\"\" ++ print fuzz.value ++ \"%%\\\"\",\n\t\t\t\"-trim +repage\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_uniqueCols_item = class\n\tMenuaction \"_Unique colours\" \"discard all but one of any pixel color\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-unique-colors\",\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_vignette_item = class\n\tMenuaction \"_Vignette\" \"soften the edges in vignette style\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tradius = Magick.blur_rad_widget; \n\t\tsigma = Magick.sigma_widget;\n\t\trx = Scale \"Rolloff x (percent)\" 0 100 10;\n\t\try = Scale \"Rolloff y (percent)\" 0 100 10;\n\t\tbackground = Magick.background_widget;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\tbackground._flag,\n\t\t\t\"-vignette\",\n\t\t\tprint radius.value ++ \"x\" ++ print sigma.value ++\n\t\t\t\t(if rx.value >= 0 then \"+\" else \"\") ++ print rx.value ++\n\t\t\t\t(if ry.value >= 0 then \"+\" else \"\") ++ print ry.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\nMagick_wave_item = class\n\tMenuaction \"_Wave\" \"shear the columns into a sine wave\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\tamplitude = Scale \"Amplitude (pixels)\" 0 100 10;\n\t\twavelength = Scale \"Wavelength (pixels)\" 0 100 10;\n\n\t\tcommand = Magick.command [\n\t\t\t\"\\\"%s\\\"\",\n\t\t\t\"-wave\",\n\t\t\tprint amplitude.value ++ \"x\" ++ print wavelength.value,\n\t\t\t\"\\\"%s\\\"\"\n\t\t];\n\n\t\t_result = Magick.system command x; \n\t}\n}\n\n\n"
  },
  {
    "path": "share/nip2/start/Makefile.am",
    "content": "startdir = $(pkgdatadir)/start\n\nstart_DATA = \\\n\tMath.def \\\n\tImage.def \\\n\tMagick.def \\\n\tColour.def \\\n\tTasks.def \\\n\tObject.def \\\n\tFilter.def \\\n\tMatrix.def \\\n\tWidgets.def \\\n\tHistogram.def \\\n\tPreferences.ws \\\n\t_joe_extra.def \\\n\t_joe_utilities.def \\\n\t_convert.def \\\n\t_generate.def \\\n\t_list.def \\\n\t_predicate.def \\\n\t_stdenv.def \\\n\t_Object.def \\\n\t_magick.def \\\n\t_types.def \n\nEXTRA_DIST = $(start_DATA)\n\n"
  },
  {
    "path": "share/nip2/start/Math.def",
    "content": "Math_arithmetic_item = class \n\tMenupullright \"_Arithmetic\" \"basic arithmetic for objects\" {\n\tAdd_item = class\n\t\tMenuaction \"_Add\" \"add a and b\" {\n\t\taction a b = map_binary add a b;\n\t}\n\n\tSubtract_item = class\n\t\tMenuaction \"_Subtract\" \"subtract b from a\" {\n\t\taction a b = map_binary subtract a b;\n\t}\n\n\tMultiply_item = class\n\t\tMenuaction \"_Multiply\" \"multiply a by b\" {\n\t\taction a b = map_binary multiply a b;\n\t}\n\n\tDivide_item = class\n\t\tMenuaction \"_Divide\" \"divide a by b\" {\n\t\taction a b = map_binary divide a b;\n\t}\n\n\tRemainder_item = class\n\t\tMenuaction \"_Remainder\" \n\t\t\t\"remainder after integer division of a by b\" {\n\t\taction a b = map_binary remainder a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAbsolute_value_item = class\n\t\tMenuaction \"A_bsolute Value\" \"absolute value of x\" {\n\t\taction x = map_unary abs x;\n\t}\n\n\tAbsolute_value_vector_item = class\n\t\tMenuaction \"Absolute Value _Vector\" \n\t\t\t\"like Absolute Value, but treat pixels as vectors\" {\n\t\taction x = map_unary abs_vec x;\n\t}\n\n\tSign_item = class\n\t\tMenuaction \"S_ign\" \"unit vector\" {\n\t\taction x = map_unary sign x;\n\t}\n\n\tNegate_item = class\n\t\tMenuaction \"_Negate\" \"multiply by -1\" {\n\t\taction x = map_unary unary_minus x;\n\t}\n}\n\nMath_trig_item = class \n\tMenupullright \"_Trigonometry\" \"trigonometry operations (all in degrees)\" {\n\tSin_item = class\n\t\tMenuaction \"_Sine\" \"calculate sine x\" {\n\t\taction x = map_unary sin x;\n\t}\n\n\tCos_item = class\n\t\tMenuaction \"_Cosine\" \"calculate cosine x\" {\n\t\taction x = map_unary cos x;\n\t}\n\n\tTan_item = class\n\t\tMenuaction \"_Tangent\" \"calculate tangent x\" {\n\t\taction x = map_unary tan x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tAsin_item = class\n\t\tMenuaction \"Arc S_ine\" \"calculate arc sine x\" {\n\t\taction x = map_unary asin x;\n\t}\n\n\tAcos_item = class\n\t\tMenuaction \"Arc C_osine\" \"calculate arc cosine x\" {\n\t\taction x = map_unary acos x;\n\t}\n\n\tAtan_item = class\n\t\tMenuaction \"Arc T_angent\" \"calculate arc tangent x\" {\n\t\taction x = map_unary atan x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRad_item = class\n\t\tMenuaction \"_Degrees to Radians\" \"convert degrees to radians\" {\n\t\taction x = map_unary rad x;\n\t}\n\n\tDeg_item = class\n\t\tMenuaction \"_Radians to Degrees\" \"convert radians to degrees\" {\n\t\taction x = map_unary deg x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tAngle_range_item = class\n\t\tMenuaction \"Angle i_n Range\" \n\t\t\t\"is angle within t degrees of r, mod 360\" {\n\t\taction t r angle\n\t\t      =\tclock (max - angle) < 2*r\n\t\t{\n\t\t\tmax = clock (t + r);\n\n\t\t\tclock a \n\t\t\t      =\ta + 360, a < 0;\n\t\t\t      =\ta - 360, a >= 360;\n\t\t\t      = a;\n\t\t}\n\t}\n}\n\nMath_log_item = class \n\tMenupullright \"_Log\" \"logarithms and anti-logs\" {\n\tExponential_item = class\n\t\tMenuaction \"_Exponential\" \"calculate e ** x\" {\n\t\taction x = map_unary (power e) x;\n\t}\n\n\tLog_natural_item = class\n\t\tMenuaction \"Natural _Log\" \"log base e of x\" {\n\t\taction x = map_unary log x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tExponential10_item = class\n\t\tMenuaction \"E_xponential base 10\" \"calculate 10 ** x\" {\n\t\taction x = map_unary (power 10) x;\n\t}\n\n\tLog10_item = class\n\t\tMenuaction \"L_og Base 10\" \"log base 10 of x\" {\n\t\taction x = map_unary log10 x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tRaise_to_power_item = class\n\t\tMenuaction \"_Raise to Power\" \"calculate x ** y\" {\n\t\taction x y = map_binary power x y;\n\t}\n}\n\nMath_complex_item = class \n\tMenupullright \"_Complex\" \"operations on complex numbers and images\" {\n\tComplex_extract = class \n\t\tMenupullright \"_Extract\" \"extract fields from complex\" {\n\t\tReal_item = class \n\t\t\tMenuaction \"_Real\" \n\t\t\t\t\"extract real part of complex\" {\n\t\t\taction in = map_unary re in;\n\t\t}\n\n\t\tImaginary_item = class \n\t\t\tMenuaction \"_Imaginary\" \n\t\t\t\t\"extract imaginary part of complex\" {\n\t\t\taction in = map_unary im in;\n\t\t}\n\t}\n\n\tComplex_build_item = class \n\t\tMenuaction \"_Build\" \"join a and b to make a complex\" {\n\t\taction a b = map_binary comma a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tPolar_item = class \n\t\tMenuaction \"_Polar\" \n\t\t\t\"convert real and imag to amplitude and phase\" {\n\t\taction a = map_unary polar a;\n\t}\n\n\tRectangular_item = class \n\t\tMenuaction \"_Rectagular\" \n\t\t\t(\"convert (amplitude, phase) image to rectangular \" ++\n\t\t\t\"coordinates\") {\n\t\taction x = map_unary rectangular x;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tConjugate_item = class \n\t\tMenuaction \"_Conjugate\" \"invert imaginary part\" {\n\t\taction x = map_unary conj x;\n\t}\n}\n\nMath_boolean_item = class \n\tMenupullright \"_Boolean\" \"bitwise boolean operations for integer objects\" {\n\tAnd_item = class \n\t\tMenuaction \"_AND\" \"bitwise AND of a and b\" {\n\t\taction a b = map_binary bitwise_and a b;\n\t}\n\n\tOr_item = class \n\t\tMenuaction \"_OR\" \"bitwise OR of a and b\" {\n\t\taction a b = map_binary bitwise_or a b;\n\t}\n\n\tEor_item = class \n\t\tMenuaction \"_XOR\" \"bitwise exclusive or of a and b\" {\n\t\taction a b = map_binary eor a b;\n\t}\n\n\tNot_item = class \n\t\tMenuaction \"_NOT\" \"invert a\" {\n\t\taction a = map_unary not a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tRight_shift_item = class \n\t\tMenuaction \"Shift _Right\" \"shift a right by b bits\" {\n\t\taction a b = map_binary right_shift a b;\n\t}\n\n\tLeft_shift_item = class \n\t\tMenuaction \"Shift _Left\" \"shift a left by b bits\" {\n\t\taction a b = map_binary left_shift a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tIf_then_else_item = class \n\t\tMenuaction \"_If Then Else\" \n\t\t\t\"b where a is non-zero, c elsewhere\" {\n\t\taction a b c \n\t\t\t= map_trinary ite a b c\n\t\t{\n\t\t\t// can't use if_then_else, we need a true trinary\n\t\t\tite a b c = if a then b else c;\n\t\t}\n\t}\n\n\tBandand_item = Image_band_item.Bandand_item; \n\n\tBandor_item = Image_band_item.Bandor_item; \n}\n\nMath_relational_item = class \n\tMenupullright \"R_elational\" \"comparison operations\" {\n\tEqual_item = class \n\t\tMenuaction \"_Equal to\" \"test a equal to b\" {\n\t\taction a b = map_binary equal a b;\n\t}\n\n\tNot_equal_item = class \n\t\tMenuaction \"_Not Equal to\" \"test a not equal to b\" {\n\t\taction a b = map_binary not_equal a b;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMore_item = class \n\t\tMenuaction \"_More Than\" \"test a strictly greater than b\" {\n\t\taction a b = map_binary more a b;\n\t}\n\n\tLess_item = class \n\t\tMenuaction \"_Less Than\" \"test a strictly less than b\" {\n\t\taction a b = map_binary less a b;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tMore_equal_item = class \n\t\tMenuaction \"M_ore Than or Equal to\" \n\t\t\t\"test a greater than or equal to b\" {\n\t\taction a b = map_binary more_equal a b;\n\t}\n\n\tLess_equal_item = class \n\t\tMenuaction \"L_ess Than or Equal to\" \n\t\t\t\"test a less than or equal to b\" {\n\t\taction a b = map_binary less_equal a b;\n\t}\n}\n\nMath_list_item = class \n\tMenupullright \"L_ist\" \"operations on lists\" {\n\tHead_item = class \n\t\tMenuaction \"_Head\" \"first element in list\" {\n\t\taction x = map_unary hd x;\n\t}\n\n\tTail_item = class \n\t\tMenuaction \"_Tail\" \"list without the first element\" {\n\t\taction x = map_unary tl x;\n\t}\n\n\tLast_item = class \n\t\tMenuaction \"_Last\" \"last element in list\" {\n\t\taction x = map_unary last x;\n\t}\n\n\tInit_item = class \n\t\tMenuaction \"_Init\" \"list without the last element\" {\n\t\taction x = map_unary init x;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"reverse order of elements in list\" {\n\t\taction x = map_unary reverse x;\n\t}\n\n\tSort_item = class \n\t\tMenuaction \"_Sort\" \"sort list into ascending order\" {\n\t\taction x = map_unary sort x;\n\t}\n\n\tMake_set_item = class \n\t\tMenuaction \"_Make Set\" \"remove duplicates from list\" {\n\t\taction x = map_unary mkset equal x;\n\t}\n\n\tTranspose_list_item = class \n\t\tMenuaction \"Tr_anspose\" \n\t\t\t\"exchange rows and columns in a list of lists\" {\n\t\taction x = map_unary transpose x;\n\t}\n\n\tConcat_item = class \n\t\tMenuaction \"_Concat\" \n\t\t\t\"flatten a list of lists into a single list\" {\n\t\taction l = map_unary concat l;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tLength_item = class \n\t\tMenuaction \"L_ength\" \"find the length of list\" {\n\t\taction x = map_unary len x;\n\t}\n\n\tSubscript_item = class \n\t\tMenuaction \"S_ubscript\" \n\t\t\t\"return element n from list (index from zero)\" {\n\t\taction n x = map_binary subscript n x;\n\t}\n\n\tTake_item = class \n\t\tMenuaction \"_Take\" \"take the first n elements of list x\" {\n\t\taction n x = map_binary take n x;\n\t}\n\n\tDrop_item = class \n\t\tMenuaction \"_Drop\" \"drop the first n elements of list x\" {\n\t\taction n x = map_binary drop n x;\n\t}\n\n\tsep3 = Menuseparator;\n\n\tJoin_item = class \n\t\tMenuaction \"_Join\" \"join two lists end to end\" {\n\t\taction a b = map_binary join a b;\n\t}\n\n\tDifference_item = class \n\t\tMenuaction \"_Difference\" \"difference of two lists\" {\n\t\taction a b = map_binary difference a b;\n\t}\n\n\tCons_item = class \n\t\tMenuaction \"C_ons\" \"put element a on the front of list x\" {\n\t\taction a x = map_binary cons a x;\n\t}\n\n\tZip_item = class \n\t\tMenuaction \"_Zip\" \"join two lists, pairwise\" {\n\t\taction a b = map_binary zip2 a b;\n\t}\n}\n\nMath_round_item = class \n\tMenupullright \"_Round\" \"various rounding operations\" {\n\t/* smallest integral value not less than x \n\t */\n\tCeil_item = class \n\t\tMenuaction \"_Ceil\" \"smallest integral value not less than x\" {\n\t\taction x = map_unary ceil x;\n\t}\n\n\tFloor_item = class \n\t\tMenuaction \"_Floor\" \n\t\t\t\"largest integral value not greater than x\" {\n\t\taction x = map_unary floor x;\n\t}\n\n\tRint_item = class \n\t\tMenuaction \"_Round to Nearest\" \"round to nearest integer\" {\n\t\taction x = map_unary rint x;\n\t}\n}\n\nMath_fourier_item = class \n\tMenupullright \"_Fourier\" \"Fourier transform\" {\n\tForward_item = class \n\t\tMenuaction \"_Forward\" \"fourier transform of image\" {\n\t\taction a = map_unary (rotquad @ fwfft) a;\n\t}\n\n\tReverse_item = class \n\t\tMenuaction \"_Reverse\" \"inverse fourier transform of image\" {\n\t\taction a = map_unary (invfft @ rotquad) a;\n\t}\n\n\tRotate_quadrants_item = class \n\t\tMenuaction \"Rotate _Quadrants\" \"rotate quadrants\" {\n\t\taction a = map_unary rotquad a;\n\t}\n}\n\nMath_stats_item = class \n\tMenupullright \"_Statistics\" \"measure various statistics of objects\" {\n\tValue_item = class \n\t\tMenuaction \"_Value\" \"value of point in object\" {\n\t\taction a = class _result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tposition = Expression \"Coordinate\" (0, 0);\n\t\n\t\t\t_result = map_binary point position.expr a;\n\t\t}\n\t}\n\n\tMean_item = class \n\t\tMenuaction \"_Mean\" \"arithmetic mean value\" {\n\t\taction a = map_unary mean a;\n\t}\n\n\tGmean_item = class \n\t\tMenuaction \"_Geometric Mean\" \"geometric mean value\" {\n\t\taction a = map_unary meang a;\n\t}\n\n\tZmean_item = class \n\t\tMenuaction \"_Zero-excluding Mean\" \"mean value of non-zero elements\" {\n\t\taction a = map_unary meanze a;\n\t}\n\n\tDeviation_item = class \n\t\tMenuaction \"_Standard Deviation\" \"standard deviation of object\" {\n\t\taction a = map_unary deviation a;\n\t}\n\n\tZdeviation_item = class \n\t\tMenuaction \"Z_ero-excluding Standard Deviation\" \n\t\t\t\"standard deviation of non-zero elements\" {\n\t\taction a = map_unary deviationze a;\n\t}\n\n\tSkew_item = class \n\t\tMenuaction \"S_kew\" \"skew of image or list or vector\" {\n\t\taction a = map_unary skew a;\n\t}\n\n\tKurtosis_item = class \n\t\tMenuaction \"Kurtosis\" \"kurtosis of image or list or vector\" {\n\t\taction a = map_unary kurtosis a;\n\t}\n\n\tStats_item = class \n\t\tMenuaction \"Ma_ny Stats\" \"calculate many stats in a single pass\" {\n\t\taction a = map_unary stats a;\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMax_item = class \n\t\tMenuaction \"M_aximum\" \"maximum of object\" {\n\t\taction a = map_unary max a;\n\t}\n\n\tMin_item = class \n\t\tMenuaction \"M_inimum\" \"minimum of object\" {\n\t\taction a = map_unary min a;\n\t}\n\n\tMaxpos_item = class \n\t\tMenuaction \"_Position of Maximum\" \"position of maximum in object\" {\n\t\taction a = map_unary maxpos a;\n\t}\n\n\tMinpos_item = class \n\t\tMenuaction \"P_osition of Minimum\" \"position of minimum in object\" {\n\t\taction a = map_unary minpos a;\n\t}\n\n\tGravity_item = class \n\t\tMenuaction \"Centre of _Gravity\" \n\t\t\t\"position of centre of gravity of histogram\" {\n\t\taction a = map_unary gravity a;\n\t}\n\n\tsep2 = Menuseparator;\n\n\tCount_set_item = class \n\t\tMenuaction \"_Non-zeros\" \"number of non-zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cset a\n\t\t{\n\t\t\tcset i = (mean (i != 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_clear_item = class \n\t\tMenuaction \"_Zeros\" \"number of zero elements in object\" {\n\t\taction a \n\t\t\t= map_unary cclear a\n\t\t{\n\t\t\tcclear i = (mean (i == 0) * i.width * i.height) / 255;\n\t\t}\n\t}\n\n\tCount_edges_item = class \n\t\tMenuaction \"_Edges\" \n\t\t\t\"count average edges across or down image\" {\n\t\taction x = class  \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tedge = Option \"Count\" [\n\t\t\t\t\"Horizontal lines\", \n\t\t\t\t\"Vertical lines\"\n\t\t\t] 0;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image = Number (edge.labels?edge) \n\t\t\t\t\t(im_cntlines image.value edge.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\n\tLinear_regression_item = class\n\t\tMenuaction \"_Linear Regression\" \"fit a line to a set of points\" {\n\t\taction xes yes = linreg xes yes;\n\t}\n\n\tWeighted_linear_regression_item = class\n\t\tMenuaction \"_Weighted Linear Regression\" \n\t\t\t\"fit a line to a set of points and deviations\" {\n\t\taction xes yes devs = linregw xes yes devs;\n\t}\n\n\tCluster_item = class \n\t\tMenuaction \"_Cluster\" \"cluster a list of numbers\" {\n\t\taction l = class {\n\t\t\t_vislevel = 3;\n\t\n\t\t\tthresh = Expression \"Threshold\" 10;\n\t\n\t\t\t[_r, _w] = cluster thresh.expr l;\n\t\n\t\t\tresult = _r;\n\t\t\tweights = _w;\n\t\t}\n\t}\n}\n\nMath_base_item = class \n\tMenupullright \"Bas_e\" \"convert number bases\" {\n\tHexadecimal_item = class \n\t\tMenuaction \"_Hexadecimal\" \"convert to hexadecimal (base 16)\" {\n\t\taction a = map_unary (print_base 16) a;\n\t}\n\n\tBinary_item = class \n\t\tMenuaction \"_Binary\" \"convert to binary (base 2)\" {\n\t\taction a = map_unary (print_base 2) a;\n\t}\n\n\tOctal_item = class \n\t\tMenuaction \"_Octal\" \"convert to octal (base 8)\" {\n\t\taction a = map_unary (print_base 8) a;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/start/Matrix.def",
    "content": "\nMatrix_build_item = class \n\tMenupullright \"_New\" \"make a new matrix of some sort\" {\n\n\tPlain_item = class \n\t\tMenuaction \"_Plain\" \"make a new plain matrix widget\" {\n\t\taction = Matrix (identity_matrix 3);\n\t}\n\n\tConvolution_item = class \n\t\tMenuaction \"_Convolution\" \"make a new convolution matrix widget\" {\n\t\taction = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];\n\t}\n\n\tRecombination_item = class \n\t\tMenuaction \"_Recombination\" \n\t\t\t\"make a new recombination matrix widget\" {\n\t\taction = Matrix_rec (identity_matrix 3);\n\t}\n\n\tMorphology_item = class \n\t\tMenuaction \"_Morphology\" \"make a new morphology matrix widget\" {\n\t\taction = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];\n\t}\n\n\tsep1 = Menuseparator;\n\n\tMatrix_identity_item = class \n\t\tMenuaction \"_Identity\" \"make an identity matrix\" {\n\t\taction = identity (identity_matrix 5);\n\t\t\n\t\tidentity v = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix (identity_matrix (to_real s)), to_real s != len v;\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = identity value;\n\t\t}\n\t}\n\n\tMatrix_series_item = class \n\t\tMenuaction \"_Series\" \"make a series\" {\n\t\taction = series (mkseries 0 1 5);\n\n\t\tmkseries s t e \n\t\t\t= transpose [[to_real s, to_real s + to_real t .. to_real e]];\n\n\t\tseries v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\t_s = v?0?0;\n\t\t\t_t = v?1?0 - v?0?0;\n\t\t\t_e = (last v)?0;\n\n\t\t\ts = Expression \"Start value\" _s;\n\t\t\tt = Expression \"Step by\" _t;\n\t\t\te = Expression \"End value\" _e;\n\n\t\t\t_result \n\t\t\t\t= Matrix (mkseries s t e), \n\t\t\t\t\t\tto_real s != _s || to_real t != _t || to_real e != _e\n\t\t\t\t= Matrix v;\n\n\t\t\tMatrix_vips value scale offset filename display = series value;\n\t\t}\n\t}\n\n\tMatrix_square_item = class \n\t\tMenuaction \"_Square\" \"make a square matrix\" {\n\t\taction = square (mksquare 5);\n\n\t\tmksquare s = replicate s (take s [1, 1 ..]);\n\n\t\tsquare v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Expression \"Size\" (len v);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == to_real s\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mksquare (to_real s); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = square value;\n\t\t}\n\t}\n\n\tMatrix_circular_item = class \n\t\tMenuaction \"_Circular\" \"make a circular matrix\" {\n\t\taction = circle (mkcircle 3);\n\n\t\tmkcircle r\n\t\t\t\t= map2 (map2 pyth) xes yes\n\t\t{\n\t\t\tline = [-r .. r];\n\t\t\txes = replicate (2 * r + 1) line;\n\t\t\tyes = transpose xes;\n\t\t\tpyth a b \n\t\t\t\t\t= 1, (a**2 + b**2) ** 0.5 <= r\n\t\t\t\t\t= 0;\n\t\t}\n\n\t\tcircle v = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tr = Expression \"Radius\" ((len v - 1) / 2);\n\n\t\t\t_result \n\t\t\t\t= Matrix_con (sum v) 0 v, len v == r.expr * 2 + 1\n\t\t\t\t= Matrix_con (sum m) 0 m\n\t\t\t{\n\t\t\t\tm = mkcircle (to_real r); \n\t\t\t}\n\n\t\t\tMatrix_vips value scale offset filename display = circle value;\n\t\t}\n\t}\n\n\tMatrix_gaussian_item = class \n\t\tMenuaction \"_Gaussian\" \"make a gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.2;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_gauss_imask, integer\n\t\t\t\t\t= im_gauss_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n\tMatrix_laplacian_item = class \n\t\tMenuaction \"_Laplacian\" \"make the Laplacian of a Gaussian matrix\" {\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\ts = Scale \"Sigma\" 0.001 10 1.5;\n\t\t\tma = Scale \"Minimum amplitude\" 0 1 0.1;\n\t\t\tinteger = Toggle \"Integer\" false;\n\n\t\t\t_result \n\t\t\t\t= fn s.value ma.value\n\t\t\t{\n\t\t\t\tfn\n\t\t\t\t\t= im_log_imask, integer\n\t\t\t\t\t= im_log_dmask;\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nMatrix_to_matrix_item = class\n\tMenuaction \"Con_vert to Matrix\" \"convert anything to a matrix\" {\n\taction x = to_matrix x;\n}\n\n#separator\n\nMatrix_extract_item = class\n\tMenupullright \"_Extract\" \"extract rows or columns from a matrix\" {\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"extract rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from row\" 0;\n\t\t\tnumber = Expression \"Extract this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= extract_area 0 first (get_width x) number x;\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"extract columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Extract from column\" 0;\n\t\t\tnumber = Expression \"Extract this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area first 0 number (get_height x) x;\n\t\t\t}\n\t\t}\n\t}\n\n\tArea_item = class\n\t\tMenuaction \"_Area\" \"extract area\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tleft = Expression \"First column\" 0;\n\t\t\ttop = Expression \"First row\" 0;\n\t\t\twidth = Expression \"Number of columns\" 1;\n\t\t\theight = Expression \"Number of rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= extract_area left top width height x;\n\t\t\t}\n\t\t}\n\t}\n\n\tDiagonal_item = class\n\t\tMenuaction \"_Diagonal\" \"extract diagonal\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhich = Option \"Extract\" [\n\t\t\t\t\"Leading Diagonal\",\n\t\t\t\t\"Trailing Diagonal\"\n\t\t\t] 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess mat\n\t\t\t\t\t= mat.Matrix_base (map2 extr [0..] mat.value),\n\t\t\t\t\t\twhich == 0\n\t\t\t\t\t= mat.Matrix_base (map2 extr \n\t\t\t\t\t\t[mat.width - 1, mat.width - 2 .. 0] mat.value);\n\t\t\t\textr n l = [l?n];\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_insert_item = class\n\tMenupullright \"_Insert\" \"insert rows or columns into a matrix\" {\n\t// make a new 8-bit uchar image of wxh with pixels set to p\n\t// use to generate new cells\n\tnewim w h p\n\t\t= image_new w h 1 \n\t\t\tImage_format.UCHAR Image_coding.NOCODING Image_type.B_W p 0 0;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"insert rows\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at row\" 0;\n\t\t\tnumber = Expression \"Insert this many rows\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, new, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim w number item.expr)];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 f w (h - f) x], f < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"insert columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Insert at column\" 0;\n\t\t\tnumber = Expression \"Insert this many columns\" 1;\n\t\t\titem = Expression \"Set new cells to\" 0;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, new, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tnew = [(if is_Matrix x then to_matrix else id) \n\t\t\t\t\t\t(newim number h item.expr)];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area f 0 (w - f) h x], f < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_delete_item = class\n\tMenupullright \"_Delete\" \"delete rows or columns from a matrix\" {\n\t// remove number of items, starting at first\n\tdelete first number l = take (to_real first) l ++ \n\t\tdrop (to_real first + to_real number) l;\n\n\tRows_item = class\n\t\tMenuaction \"_Rows\" \"delete rows\" {\n\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from row\" 0;\n\t\t\tnumber = Expression \"Delete this many rows\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_tb (concat [top, bottom])\n\t\t\t\t{\n\t\t\t\t\ttop \n\t\t\t\t\t\t= [extract_area 0 0 w f x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tbottom \n\t\t\t\t\t\t= [extract_area 0 b w (h - b) x], b < h\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tb = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tColumns_item = class\n\t\tMenuaction \"_Columns\" \"delete columns\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfirst = Expression \"Delete from column\" 0;\n\t\t\tnumber = Expression \"Delete this many columns\" 1;\n\n\t\t\t_result \n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess x\n\t\t\t\t\t= foldl1 join_lr (concat [left, right])\n\t\t\t\t{\n\t\t\t\t\tleft \n\t\t\t\t\t\t= [extract_area 0 0 f h x], f > 0\n\t\t\t\t\t\t= [];\n\t\t\t\t\tright \n\t\t\t\t\t\t= [extract_area r 0 (w - r) h x], r < w\n\t\t\t\t\t\t= [];\n\n\t\t\t\t\tf = to_real first;\n\t\t\t\t\tn = to_real number;\n\t\t\t\t\tr = f + n;\n\t\t\t\t\tw = get_width x;\n\t\t\t\t\th = get_height x;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_join = class\n\tMenupullright \"_Join\" \"join two matricies\" {\n\tLeft_right_item = class\n\t\tMenuaction \"_Left to Right\" \"join two matricies left-right\" {\n\t\taction a b = map_binary join_lr a b;\n\t}\n\n\tTop_bottom_item = class\n\t\tMenuaction \"_Top to Bottom\" \"joiin two matricies top-bottom\" {\n\t\taction a b = map_binary join_tb a b;\n\t}\n}\n\nMatrix_rotate_item = class\n\tMenupullright \"_Rotate\" \"clockwise rotation by fixed angles\" {\n\n\trot90 = Image_transform_item.Rotate_item.Fixed_item.Rot90_item;\n\n\trot180 = Image_transform_item.Rotate_item.Fixed_item.Rot180_item;\n\n\trot270 = Image_transform_item.Rotate_item.Fixed_item.Rot270_item;\n\n\tMatrix_rot45_item = class\n\t\tMenuaction \"_45 Degrees\" \n\t\t\t\"45 degree rotate (square, odd-length-sides only)\" {\n\t\taction x = map_unary rot45 x;\n\t}\n}\n\nMatrix_flip_item = Image_transform_item.Flip_item;\n\nMatrix_sort_item = class \n\tMenuaction \"_Sort\" \"sort by column or row\" {\n\taction x = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\to = Option (_ \"Orientation\") [\n\t\t\t_ \"Sort by column\",\n\t\t\t_ \"Sort by row\"\n\t\t] 0;\n\t\ti = Expression (_ \"Sort on index\") 0;\n\t\td = Option (_ \"Direction\") [\n\t\t\t_ \"Ascending\",\n\t\t\t_ \"Descending\"\n\t\t] 0;\n\n\t\t_result \n\t\t\t= map_unary sort x\n\t\t{\n\t\t\tidx = to_real i;\n\t\t\tpred a b \n\t\t\t\t= a?idx <= b?idx, d == 0\n\t\t\t\t= a?idx >= b?idx;\n\t\t\tsort x\n\t\t\t\t= (x.Matrix_base @ sortc pred) x.value,\n\t\t\t\t\to == 0\n\t\t\t\t= (x.Matrix_base @ transpose @ sortc pred @ transpose) x.value;\n\t\t}\n\t}\n}\n\n#separator\n\nMatrix_invert_item = class\n\tMenuaction \"In_vert\" \"calculate inverse matrix\" {\n\taction x = map_unary (converse power (-1)) x;\n}\n\nMatrix_transpose_item = class\n\tMenuaction \"_Transpose\" \"swap rows and columns\" {\n\taction x = map_unary transpose x;\n}\n\n#separator\n\nMatrix_plot_scatter_item = class \n\tMenuaction \"_Plot Scatter\" \n\t\t\"plot a scatter graph of a matrix of [x,y1,y2,..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_vislevel = 3;\n\n\t\tauto = Toggle \"Auto Range\" true;\n\t\txmin = Expression \"X range minimum\" 0;\n\t\txmax = Expression \"X range maximum\" 1;\n\t\tymin = Expression \"Y range minimum\" 0;\n\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t_result\n\t\t\t= Plot options ((x2b @ get_image @ to_image) x)\n\t\t{\n\t\t\toptions\n\t\t\t\t= [$style => Plot_style.POINT, $format => Plot_format.XYYY] ++ \n\t\t\t\t\trange;\n\t\t\trange\n\t\t\t\t= [], auto\n\t\t\t\t= [$xmin => xmin.expr, $xmax => xmax.expr, \n\t\t\t\t\t$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t// matrix to image makes a 1-band mxn image\n\t\t\t// we need to put columns into bands\n\t\t\tx2b im\n\t\t\t\t= bandjoin (map extract_col [0 .. w - 1])\n\t\t\t{\n\t\t\t\tw = get_width im;\n\t\t\t\th = get_height im;\n\t\t\t\tb = get_bands im;\n\t\t\t\textract_col x = extract_area x 0 1 h im;\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatrix_plot_item = Hist_plot_item;\n\nMatrix_buildlut_item = class \n\tMenuaction \"_Build LUT From Scatter\" \n\t\t\"make a lookup table from a matrix of [x,y1,y2..] coordinates\" {\n\taction x = class\n\t\t_result {\n\t\t_check_args = [\n\t\t\t[x, \"x\", check_Matrix]\n\t\t];\n\t\t_result = buildlut x;\n\t}\n}\n"
  },
  {
    "path": "share/nip2/start/Object.def",
    "content": "Object_duplicate_item = class\n\tMenuaction \"_Duplicate\" \"take a copy of an object\" {\n\taction x = map_unary copy x;\n}\n\n#separator\n\nObject_list_to_group_item = class\n\tMenuaction \"_List to Group\" \"turn a list of objects into a group\" {\n\taction x = to_group x;\n}\n\nObject_group_to_list_item = class\n\tMenuaction \"_Group to List\" \"turn a group into a list of objects\" {\n\taction x = to_list x;\n}\n\n#separator\n\nObject_break_item = class\n\tMenuaction \"_Break Up Object\" \n\t\t\"break an object into a list of components\" {\n\taction x\n\t\t= map_unary break x\n\t{\n\t\tbreak x\n\t\t\t= bandsplit x, is_Image x\n\t\t\t= map Vector x.value, is_Matrix x\n\t\t\t= x.value, is_Vector x || is_Real x\n\t\t\t= error \"Breakup: not Image/Matrix/Vector/Real\";\n\t}\n}\n\nObject_assemble_item = class\n\tMenuaction \"_Assemble Objects\" \n\t\t\"assemble a list of objects into a single object\" {\n\taction x\n\t\t= map_unary ass x\n\t{\n\t\tass x\n\t\t\t= [], x == []\n\t\t\t= Vector x, is_real_list x\n\t\t\t= Matrix x, is_matrix x\n\t\t\t= bandjoin x, is_listof is_Image x\n\t\t\t= Vector (map get_value x), is_listof is_Real x\n\t\t\t= Matrix (map get_value x), is_listof is_Vector x\n\t\t\t= error \"Assemble: not list of Image/Vector/Real/image/real\";\n\t}\n}\n"
  },
  {
    "path": "share/nip2/start/Preferences.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.7.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"680\" window_height=\"800\" filename=\"$VIPSHOME/share/$PACKAGE/start/Preferences.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"100\" lpane_open=\"false\" rpane_position=\"400\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"Preferences\">\n    <Column x=\"0\" y=\"3067\" open=\"false\" selected=\"false\" sform=\"false\" next=\"99\" name=\"B\" caption=\"Interface column -- don't touch this!\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"CSV_SEPARATOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"O1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PRINT_CARTIESIAN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F10.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"USE_GRAPHICSMAGICK\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D45.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_PANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"237\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"788\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PROGRAM_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"700\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TRACE_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_LPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"100\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_OPEN\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WORKSPACE_RPANE_POSITION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"400\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RELOAD\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D42.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_STATUSBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLBAR_STYLE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MATRIX_FILE_TYPE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_RECOMP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"N2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_MAX_UNDO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[-1,0,1,5,10]?N1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PAINTBOX_FONT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"N4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PNG_INTERLACE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"M2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_LINELENGTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D41.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A6.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JPEG_ICC_PROFILE_FILE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"A8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PPM_MODE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"G1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_COMPRESSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_JPEG_Q\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_LAYOUT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C16.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C18.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_TILE_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"C20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_MULTI_RES\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_FORMAT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_PREDICTOR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TIFF_BIGTIFF\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"C26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_START\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D25.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_SEARCH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D2.expr\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PATH_TMP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_SLIDER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D28.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_RECOMP_REGION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D29.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_AUTO_WS_SAVE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D30.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_DISPLAY_LED\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_TOOLKITBROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_MAX_HEAP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"D38.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_PIN_FILESEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"F1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_STATUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CONVERSION\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_RULERS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_CROSSHAIR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E20.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL_HQ\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E26.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DISPLAY_THUMBNAIL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E21.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CALC_TRACE_FUNCTIONS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"H1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_DEVICE\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CHANNEL\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_BRIGHTNESS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_COLOUR\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CONTRAST\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_HUE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_FRAMES\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"J13.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_MONO\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"J14.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K1.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_LEFT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_TOP\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_WIDTH\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_CROP_HEIGHT\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"K9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIDEO_ASPECT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"K11.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_MAX_BLEND_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_REFINE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_WINDOW_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I5.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_OBJECT_SIZE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I7.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MOSAIC_BALANCE_GAMMA\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I9.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"680\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MAINW_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L2.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BROWSER_REMOTE\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"L4.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_WIDTH\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E23.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IMAGE_WINDOW_HEIGHT\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E24.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"POPUP_NEW_ROWS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E25.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_HISTORY_MAX\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D43.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VIPS_CPUS\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D44.value\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2831\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"I\" caption=\"Mosaic defaults\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Maximum blend width&quot; 0 100 10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Refine tie-points&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search windows this size&quot; 30\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Search for objects this size&quot; 10\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Image gamma for mosaic balance&quot; 1 3 1.6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2495\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"J\" caption=\"Video for linux\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"J2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;Device&quot; &quot;/dev/video&quot;\"/>\n            <Pathname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Channel&quot; [&quot;TV&quot;, &quot;Composite 1&quot;, &quot;Composite 2&quot;, &quot;Composite 3&quot;] 1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Brightness&quot; 0 32767 23000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Colour&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Contrast&quot; 0 32767 27000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Hue&quot; 0 32767 32767\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Number of frames to average&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Grab monochrome&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2208\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"K\" caption=\"General video capture\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"K1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Crop video: \" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Crop video&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop left&quot; 1\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop top&quot; 6\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number  &quot;Crop width&quot; 747\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Crop height&quot; 570\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Aspect ratio (stretch vertically\\nby this much)&quot; 1.202\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2072\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"M\" caption=\"PNG save options\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"M1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Compression&quot; (map print [0..9]) 6\"/>\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Interlace&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1970\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"G\" caption=\"PPM/PGM/PBM save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"PPM mode\" labelsn=\"2\" labels0=\"Binary\" labels1=\"ASCII\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Mode&quot; [&quot;Binary&quot;, &quot;ASCII&quot;] 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1620\" open=\"true\" selected=\"true\" sform=\"false\" next=\"27\" name=\"C\" caption=\"TIFF save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Compression&quot; [&quot;None&quot;, &quot;LZW&quot;, &quot;Zip (deflate)&quot;, &quot;PACKBITS&quot;, &quot;JPEG&quot;, &quot;CCITTFAX4&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;JPEG quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Deflate/LZW predictor&quot; [&quot;None&quot;,&quot;Horizontal difference&quot;,&quot;Floating-point&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Layout\" labelsn=\"2\" labels0=\"Strip\" labels1=\"Tile\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Layout&quot; [&quot;Strip&quot;, &quot;Tile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile width&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Tile height&quot; 128\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Multi-res&quot; [&quot;Single image&quot;, &quot;Image pyramid&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Format&quot; [&quot;No truncation&quot;,&quot;Save 1 band 8 bit images as 1 bit&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Save as BigTIFF&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1518\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"O\" caption=\"CSV save\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"String &quot;Separator character&quot; &quot;\\t&quot;\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1348\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"A\" caption=\"JPEG save\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Scale &quot;Quality factor&quot; 0 100 75\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;ICC profile&quot; [&quot;Use image profile, if any&quot;, &quot;Embed profile from file&quot;, &quot;Don't attach a profile&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Pathname/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Pathname &quot;ICC profile file&quot; &quot;$VIPSHOME/share/nip2/data/sRGB.icm&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1144\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"F\" caption=\"Widgets\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Pin up file requestors&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Option &quot;Main window toolbar&quot; [&quot;Default style&quot;, &quot;Icon only&quot;, &quot;Text only&quot;, &quot;Icon and text&quot;, &quot;Icon and text to right&quot;] 0\"/>\n            <Option caption=\"Main window toolbar\" labelsn=\"5\" labels0=\"Default style\" labels1=\"Icon only\" labels2=\"Text only\" labels3=\"Icon and text\" labels4=\"Icon and text to right\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display LEDs in workspace&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Display complex numbers as coordinates&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1044\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"H\" caption=\"Debug options\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Disassemble functions\" value=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;untitled&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"906\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"L\" caption=\"Help browser\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"L2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Command to start browser&quot; &quot;firefox&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Go-to-page argument&quot; &quot;-remote 'openURL(%s)'&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"734\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"N\" caption=\"Paintbox \">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option caption=\"Max undo steps\" labelsn=\"5\" labels0=\"Unlimited\" labels1=\"None\" labels2=\"1\" labels3=\"5\" labels4=\"10\" value=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Option &quot;Max undo steps&quot; [&quot;Unlimited&quot;, &quot;None&quot;, &quot;1&quot;, &quot;5&quot;, &quot;10&quot;] 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Fontname &quot;Default paintbox font&quot; &quot;Sans 12&quot;\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Fontname/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update during paint&quot; true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"458\" open=\"true\" selected=\"false\" sform=\"false\" next=\"27\" name=\"E\" caption=\"Image display\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"E20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use crosshair cursor in image windows&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Thumbnail size&quot; 64\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;High-quality thumbnails&quot; false\"/>\n            <Toggle/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window width&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Default maximum image window height&quot;  750\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto image window pop up&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"46\" name=\"D\" caption=\"Calculation\">\n      <Subcolumn vislevel=\"2\">\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Data path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;data&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;data&quot;], &quot;.&quot;]\"/>\n            <Expression caption=\"Data path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"String &quot;Temporary files&quot; (path_relative [&quot;$SAVEDIR&quot;, &quot;tmp&quot;])\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <String/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Expression &quot;Start path&quot; [path_relative [&quot;$SAVEDIR&quot;, &quot;start&quot;], path_relative [&quot;$VIPSHOME&quot;, &quot;share&quot;, &quot;$PACKAGE&quot;, &quot;start&quot;]]\"/>\n            <Expression caption=\"Start path\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D28\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update sliders during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update sliders during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D29\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Update regions during drag\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Update regions during drag&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D30\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto workspace save&quot; true\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D42\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Auto-reload on file change&quot; false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D41\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Text display length (characters)&quot; 80\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D38\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Number &quot;Heap size (per workspace)&quot; 600000\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <Number/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D43\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of VIPS functions to memoise&quot; 20000\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D44\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Number &quot;Number of CPUs to use (0 for autodetect)&quot; 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D45\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Toggle &quot;Use GraphicsMagick for Magick menu&quot; false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "share/nip2/start/Tasks.def",
    "content": "Tasks_capture_item = class\n\tMenupullright \"_Capture\" \n\t\t\"useful stuff for capturing and preprocessing images\" {\n\n\tCsv_import_item = class\n\t\tMenuaction \"_CSV Import\" \"read a file of comma-separated values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tstart_line = Expression \"Start at line\" 1;\n\t\t\trows = Expression \"Lines to read (-1 for whole file)\" (-1);\n\t\t\twhitespace = String \"Whitespace characters\" \" \\\"\";\n\t\t\tseparator = String \"Separator characters\" \",;\\t\";\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_csv2vips filename)\n\t\t\t{\n\t\t\t\tfilename = search (expand path.value) ++ \":\" ++\n\t\t\t\t\t\"skip:\" ++ print (start_line.expr - 1) ++ \",\" ++\n\t\t\t\t\t\"whi:\" ++ escape whitespace.value ++ \",\" ++\n\t\t\t\t\t\"sep:\" ++ escape separator.value ++ \",\" ++\n\t\t\t\t\t\"line:\" ++ print rows.expr;\n\n\t\t\t\t// prefix any ',' with a '\\' in the separators line\n\t\t\t\tescape x \n\t\t\t\t\t= foldr prefix [] x\n\t\t\t\t{\n\t\t\t\t\tprefix x l\n\t\t\t\t\t\t= '\\\\' : x : l, x == ','\n\t\t\t\t\t\t= x : l;\n\t\t\t\t}\n\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tRaw_import_item = class\n\t\tMenuaction \"_Raw Import\" \"read a file of binary values\" {\n\t\taction = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tpath = Pathname \"File to load\" \"empty\";\n\t\t\tacross = Expression \"Pixels across\" 100;\n\t\t\tdown = Expression \"Pixels down\" 100;\n\t\t\tbytes = Expression \"Bytes per pixel\" 3;\n\t\t\tskip = Expression \"Skip over initial bytes\" 0;\n\n\t\t\t_result\n\t\t\t\t= Image blank, path.value == \"empty\"\n\t\t\t\t= Image (im_binfile path.value \n\t\t\t\t\tacross.expr down.expr bytes.expr skip.expr)\n\t\t\t{\n\t\t\t\tblank = image_new 1 1 1 \n\t\t\t\t\tImage_format.DOUBLE Image_coding.NOCODING Image_type.B_W \n\t\t\t\t\t0 0 0;\n\t\t\t}\n\t\t}\n\t}\n\n\t// interpret Analyze header for layout and calibration\n\tAnalyze7_header_item = class\n\t\tMenuaction \"_Interpret Analyze 7 Header\" \n\t\t\t\"examine the Analyze header and set layout and value\" {\n\t\taction x \n\t\t\t= x'''\n\t\t{\n\t\t\t// read bits of header\n\t\t\tdim n = get_header (\"dsr-image_dimension.dim[\" ++ print n ++ \"]\");\n\t\t\tdim0 = dim 0 x;\n\t\t\tdim1 = dim 1 x;\n\t\t\tdim2 = dim 2 x;\n\t\t\tdim3 = dim 3 x;\n\t\t\tdim4 = dim 4 x;\n\t\t\tdim5 = dim 5 x;\n\t\t\tdim6 = dim 6 x;\n\t\t\tdim7 = dim 7 x;\n\t\t\tglmax = get_header \"dsr-image_dimension.glmax\" x;\n\t\t\tcal_max = get_header \"dsr-image_dimension.cal_max\" x;\n\t\n\t\t\t// oops, now a nop\n\t\t\tx' = x;\n\t\n\t\t\t// lay out higher dimensions width-ways\n\t\t\tx'' \n\t\t\t\t= grid dim2 dim3 1 x', dim0 == 3\n\t\t\t\t= grid dim2 dim3 dim4 x', dim0 == 4\n\t\t\t\t= grid (dim2 * dim4) dim5 1 (grid dim2 dim3 dim4) x', dim0 == 5\n\t\t\t\t= grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4) x', dim0 == 6\n\t\t\t\t= grid (dim2 * dim4 * dim6) dim7 1 \n\t\t\t\t\t(grid (dim2 * dim4) dim5 dim6 (grid dim2 dim3 dim4)) x', \n\t\t\t\t\t\tdim0 == 7\n\t\t\t\t= error (_ \"unsupported dimension \" ++ dim0);\n\t\n\t\t\t// multiply by scale factor to get kBeq\n\t\t\tx''' = x'' * (cal_max / glmax);\n\t\t}\n\t}\n\n\tVideo_item = class \n\t\tMenuaction \"Capture _Video Frame\" \"capture a frame of still video\" {\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdevice = prefs.VIDEO_DEVICE;\n\t\t\tchannel = Option \"Input channel\" [\n\t\t\t\t\"TV\",\n\t\t\t\t\"Composite 1\",\n\t\t\t\t\"Composite 2\",\n\t\t\t\t\"Composite 3\"\n\t\t\t] prefs.VIDEO_CHANNEL;\n\t\t\tb = Scale \"Brightness\" 0 32767 prefs.VIDEO_BRIGHTNESS;\n\t\t\tcol = Scale \"Colour\" 0 32767 prefs.VIDEO_COLOUR;\n\t\t\tcon = Scale \"Contrast\" 0 32767 prefs.VIDEO_CONTRAST;\n\t\t\thue = Scale \"Hue\" 0 32767 prefs.VIDEO_HUE;\n\t\t\tframes = Scale \"Frames to average\" 0 100 prefs.VIDEO_FRAMES;\n\t\t\tmono = Toggle \"Monochrome grab\" prefs.VIDEO_MONO;\n\t\t\tcrop = Toggle \"Crop image\" prefs.VIDEO_CROP;\n\n\t\t\t// grab, but hide it ... if we let the crop edit\n\t\t\t_raw_grab = Image (im_video_v4l1 device channel.value\n\t\t\t\tb.value col.value con.value \n\t\t\t\thue.value frames.value);\n\n\t\t\tedit_crop\n\t\t\t\t= Region _raw_grab left top width height\n\t\t\t{\n\t\t\t\tleft = prefs.VIDEO_CROP_LEFT;\n\t\t\t\ttop = prefs.VIDEO_CROP_TOP;\n\t\t\t\twidth = min_pair \n\t\t\t\t\tprefs.VIDEO_CROP_WIDTH (_raw_grab.width + left);\n\t\t\t\theight = min_pair\n\t\t\t\t\tprefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top);\n\t\t\t}\n\n\t\t\taspect_ratio = Expression \"Stretch vertically by\"\n\t\t\t\tprefs.VIDEO_ASPECT;\n\n\t\t\t_result \n\t\t\t\t= frame'\n\t\t\t{\n\t\t\t\tframe \n\t\t\t\t\t= edit_crop, crop\n\t\t\t\t\t= _raw_grab;\n\n\t\t\t\tframe' \n\t\t\t\t\t= colour_transform_to Image_type.B_W frame, mono\n\t\t\t\t\t= frame;\n\t\t\t}\n\t\t}\n\t}\n\n\tSmooth_image_item = class \n\t\tMenuaction \"_Smooth\" \"remove small features from image\" {\n\t\taction in = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tfeature = Scale \"Minimum feature size\" 1 50 20;\n\n\t\t\t_result = map_unary (smooth feature.value) in;\n\t\t}\n\t}\n\n\tLight_correct_item = class\n\t\tMenuaction \"_Flatfield\" \"use white image w to flatfield image i\" {\n\t\taction w i\n\t\t\t= map_binary wc w i\n\t\t{\n\t\t\twc w i\n\t\t\t\t= clip2fmt i.format (w' * i)\n\t\t\t{\n\t\t\t\tfac = mean w / max w;\n\t\t\t\tw' = fac * (max w / w);\n\t\t\t}\n\t\t}\n\t}\n\n\tImage_rank_item = Filter_rank_item.Image_rank_item;\n\n\tTilt_item = Filter_tilt_item;\n\n\tsep1 = Menuseparator;\n\n\tWhite_balance_item = class\n\t\tMenuaction \"_White Balance\" \n\t\t\t\"use average of small image to set white of large image\" {\n\t\taction a b = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\twhite_hint = \"Set image white to:\";\n\t\t\twhite = Colour_picker \"Lab\" [100, 0, 0];\n\n\t\t\t_result\n\t\t\t\t\t= map_binary wb a b\n\t\t\t{\n\t\t\t\twb a b\n\t\t\t\t\t= colour_transform_to (get_type image) image_xyz'\n\t\t\t\t{\n\t\t\t\t\tarea x = x.width * x.height;\n\t\t\t\t\tlarger x y = area x > area y;\n\t\t\t\t\t[image, patch] = sortc larger [a, b];\n\t\t\t\t\tto_xyz = colour_transform_to Image_type.XYZ;\n\t\t\t\n\t\t\t\t\t// white balance in XYZ\n\t\t\t\t\tpatch_xyz = to_colour (to_xyz patch);\n\t\t\t\t\twhite_xyz = to_xyz white;\n\n\t\t\t\t\tfacs = (mean patch_xyz / mean white_xyz) * \n\t\t\t\t\t\t(white_xyz / patch_xyz);\n\n\t\t\t\t\timage_xyz = to_xyz image;\n\t\t\t\t\timage_xyz' = image_xyz * facs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tGamma_item = Image_levels_item.Gamma_item;\n\n\tTone_item = Image_levels_item.Tone_item;\n\n\tsep2 = Menuseparator;\n\n\tCrop_item = Image_crop_item;\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tRubber_item = Image_transform_item.Image_rubber_item;\n\n\tsep3 = Menuseparator;\n\n\tICC_item = Colour_icc_item;\n\n\tTemp_item = Colour_temperature_item;\n\n\tFind_calib_item = class \n\t\tMenuaction \"Find _Colour Calibration\" \n\t\t\t\"find an RGB -> XYZ transform from an image of a colour chart\" {\n\t\taction image = class\n\t\t\t_result {\n\t\t\t_check_args = [\n\t\t\t\t[image, \"image\", check_Image]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tmeasure = Scale (_ \"Measure area (%)\") 1 100 50; \n\n\t\t\tsample = measure_draw 6 4 (to_real measure) image;\n\n\t\t\t// get macbeth data file to use\n\t\t\tmacbeth = Pathname \"Pick a Macbeth data file\" \n\t\t\t\t\"$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat\";\n\n\t\t\tmode = Option \"Input LUT\" [\n\t\t\t\t\"Linearize from chart greyscale\",\n\t\t\t\t\"Fit intercept from chart greyscale\",\n\t\t\t\t\"Linear input, set brightness from chart\",\n\t\t\t\t\"Linear input\"\n\t\t\t] 0;\n\n\t\t\t// get max of input image\n\t\t\t_max_value = Image_format.maxval image.format;\n\n\t\t\t// measure chart image\n\t\t\t_camera = measure_sample 6 4 (to_real measure) image;\n\n\t\t\t// load true values\n\t\t\t_true_Lab = Matrix_file macbeth.value;\n\t\t\t_true_XYZ = colour_transform \n\t\t\t\tImage_type.LAB Image_type.XYZ _true_Lab;\n\n\t\t\t// get Ys of greyscale\n\t\t\t_true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value);\n\n\t\t\t// camera greyscale (all bands)\n\t\t\t_camera_grey = drop 18 _camera.value;\n\n\t\t\t// normalise both to 0-1 and combine\n\t\t\t_camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey;\n\t\t\t_true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y;\n\t\t\t_comb \n\t\t\t\t= Matrix (map2 cons _true_grey_Y' _camera_grey'), mode == 0\n\t\t\t\t= Matrix [0: intercepts, replicate (_camera.width + 1) 1], \n\t\t\t\t\tmode == 1\n\t\t\t\t= Matrix [[0, 0], [1, 1]]\n\t\t\t{\n\t\t\t\tintercepts = [(linreg _true_grey_Y' cam).intercept :: \n\t\t\t\t\tcam <- transpose _camera_grey'];\n\t\t\t}\n\n\t\t\t// make a linearising lut ... zero on left\n\t\t\t_linear_lut = im_invertlut _comb (_max_value + 1);\n\n\t\t\t// and display it\n\t\t\t// plot from 0 explicitly so we see the effect of mode1 (intercept\n\t\t\t// from greyscale)\n\t\t\tlinearising_lut = Plot [$ymin => 0] _linear_lut;\n\n\t\t\t// map an image though the lineariser\n\t\t\tlinear x\n\t\t\t\t= hist_map linearising_lut.value x, mode == 0 || mode == 1\n\t\t\t\t= x;\n\n\t\t\t// map the chart measurements though the lineariser\n\t\t\t_camera' = (to_matrix @ linear @ to_image) _camera;\n\n\t\t\t// solve for RGB -> XYZ\n\t\t\t// normalise: the 2nd row is what makes Y, so divide by that to\n\t\t\t// get Y in 0-1.\n\t\t\t_pinv = (transpose _camera' * _camera') ** -1;\n\t\t\t_full_M = transpose (_pinv * (transpose _camera' * _true_XYZ));\n\t\t\tM = _full_M / scale;\n\t\t\tscale = sum _full_M.value?1;\n\n\t\t\t// now turn the camera to LAB and calculate dE76\n\t\t\t_camera'' = (to_matrix @ \n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @ \n\t\t\t\trecomb M @ \n\t\t\t\tmultiply scale @\n\t\t\t\tto_image) _camera';\n\n\t\t\t_dEs = map abs_vec (_camera'' - _true_Lab).value;\n\t\t\tavg_dE76 = mean _dEs;\n\t\t\t_max_dE = foldr max_pair 0 _dEs;\n\t\t\t_worst = index (equal _max_dE) _dEs;\n\t\t\tworst_patch \n\t\t\t\t= name _worst ++ \" (patch \" ++ \n\t\t\t\t\tprint (_worst + 1) ++ \", \" ++ \n\t\t\t\t\tprint _max_dE ++ \" dE)\"\n\t\t\t{\n\t\t\t\tname i \n\t\t\t\t\t= macbeth_names?i, i >= 0 && i < len macbeth_names\n\t\t\t\t\t= \"Unknown\";\n\t\t\t}\n\n\t\t\t// normalise brightness ... in linear mode, we optionally don't\n\t\t\t// set the brightness from the Macbeth chart\n\t\t\tnorm x \n\t\t\t\t= x * scale, mode != 3\n\t\t\t\t= x;\n\n\t\t\t// convert RGB camera to Lab\n\t\t\t_result = (Image @\n\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\tnorm @\n\t\t\t\trecomb M @\n\t\t\t\tcast_float @\n\t\t\t\tlinear) image.value;\n\t\t}\n\t}\n\n\tApply_calib_item = class \n\t\tMenuaction \"_Apply Colour Calibration\" \n\t\t\t\"apply an RGB -> LAB transform to an image\" {\n\t\taction a b = class\n\t\t\t(map_binary process a b) {\n\t\t\tprocess a b\n\t\t\t\t= result, is_instanceof calib_name calib && is_Image image\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"Calibrate_image\")\n\t\t\t{\n\t\t\t\t// the name of the calib object we need\n\t\t\t\tcalib_name = \"Tasks_capture_item.Find_calib_item.action\";\n\n\t\t\t\t// get the Calibrate_chart arg first\n\t\t\t\t[image, calib] = sortc (const (is_instanceof calib_name)) \n\t\t\t\t\t[a, b];\n\n\t\t\t\tresult = (Image @\n\t\t\t\t\tcolour_transform Image_type.XYZ Image_type.LAB @\n\t\t\t\t\tcalib.norm @\n\t\t\t\t\trecomb calib.M @\n\t\t\t\t\tcast_float @\n\t\t\t\t\tcalib.linear) image.value;\n\t\t\t}\n\t\t}\n\t}\n\n\tsep4 = Menuseparator;\n\n\tGraph_hist_item = Hist_find_item;\n\n\tGraph_bands_item = class\n\t\tMenuaction \"Plot _Bands\" \"show image bands as a graph\" {\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tstyle = Option_enum \"Style\" Plot_style.names \"Line\";\n\n\t\t\tauto = Toggle \"Auto Range\" true;\n\t\t\tymin = Expression \"Y range minimum\" 0;\n\t\t\tymax = Expression \"Y range maximum\" 1;\n\n\t\t\t_result\n\t\t\t\t= Plot options (to_image (bands (image x))).value\n\t\t\t{\n\t\t\t\toptions\n\t\t\t\t\t= [$style => style.value] ++ \n\t\t\t\t\t\tif auto then [] else \n\t\t\t\t\t\t\t[$ymin => ymin.expr, $ymax => ymax.expr]; \n\n\t\t\t\t// try to make something image-like from it\n\t\t\t\timage x\n\t\t\t\t\t= extract_area x.left x.top 1 1 x.image, is_Mark x\n\t\t\t\t\t= get_image x, has_image x\n\t\t\t\t\t= get_image (to_image x);\n\n\t\t\t\t// get as [[1],[2],[3]]\n\t\t\t\tbands x\n\t\t\t\t\t= transpose [map mean (bandsplit x)];\n\t\t\t}\n\t\t}\n\t}\n}\n\nTasks_mosaic_item = class\n\tMenupullright \"_Mosaic\" \"build image mosaics\" {\n\t/* Check and group a point list by image.\n\t */\n\tmosaic_sort_test l\n\t\t= error \"mosaic: not all points\",\n\t\t\t!is_listof is_Mark l\n\t\t= error \"mosaic: points not on two images\",\n\t\t\t!is_list_len 2 images\n\t\t= error \"mosaic: images do not match in format and coding\",\n\t\t\t!all_equal (map get_format l) || !all_equal (map get_coding l)\n\t\t= error \"mosaic: not same number of points on each image\",\n\t\t\t!foldr1 equal (map len l') \n\t\t= l'\n\t{\n\t\t// test for all elements of a list equal\n\t\tall_equal l = all (map (equal (hd l)) (tl l));\n\t\n\t\t// all the different images\n\t\timages = mkset pointer_equal (map get_image l);\n\t\n\t\t// find all points defined on image\n\t\ttest_image image p = (get_image p) === image;\n\t\tfind l image = filter (test_image image) l;\n\t\n\t\t// group point list by image\n\t\tl' = map (find l) images;\n\t}\n\n\t/* Sort a point group to get right before left, and within each group to \n\t * get above before below.\n\t */\n\tmosaic_sort_lr l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tabove a b = a.top < b.top;\n\t\tl' = map (sortc above) l;\n\t\n\t\t// sort to get right group before left group\n\t\tright a b = a?0.left > b?0.left;\n\t\tl'' = sortc right l';\n\t}\n\n\t/* Sort a point group to get top before bottom, and within each group to \n\t * get left before right.\n\t */\n\tmosaic_sort_tb l\n\t\t= l''\n\t{\n\t\t// sort to get upper point first\n\t\tleft a b = a.left < b.left;\n\t\tl' = map (sortc left) l;\n\t\n\t\t// sort to get right group before left group\n\t\tbelow a b = a?0.top > b?0.top;\n\t\tl'' = sortc below l';\n\t}\n\t\n\t/* Put 'em together! Group by image, sort vertically (or horizontally) with\n\t * one of the above, transpose to get pairs matched up, and flatten again.\n\t */\n\tmosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test;\n\n\tMosaic_1point_item = class \n\t\tMenupullright \"_One Point\" \"join two images with a single tie point\" {\n\t\tcheck_ab_args a b = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tlr_mos _refine a b = class \n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_lrmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_lrmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_lr [a, b];\n\t\t\t}\n\t\t}\n\n\t\ttb_mos _refine a b = class\n\t\t\tImage _result {\n\t\t\t_check_args = check_ab_args a b;\n\t\n\t\t\tbw = blend_width_widget;\n\t\t\trefine = _refine;\n\t\n\t\t\t_result \n\t\t\t\t= im_tbmosaic a'.image.value b'.image.value 0 \n\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t(object_size / 2) (search_area / 2) 0 bw.value,\n\t\t\t\t\t\trefine\n\t\t\t\t= im_tbmerge a'.image.value b'.image.value\n\t\t\t\t\t(b'.left - a'.left) (b'.top - a'.top) bw.value\n\t\t\t{\n\t\t\t\t[a', b'] = mosaic_sort mosaic_sort_tb [a, b];\n\t\t\t}\n\t\t}\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a single tie point\" {\n\t\t\taction a b = lr_mos refine_widget a b;\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a single tie point\" {\n\t\t\taction a b = tb_mos refine_widget a b;\n\t\t}\n\t\n\t\tsep1 = Menuseparator;\n\n\t\tLeft_right_manual_item = class \n\t\t\tMenuaction \"Manual L_eft to Right\" \n\t\t\t\t\"join left-right, no auto-adjust of tie points\" {\n\t\t\taction a b = lr_mos false a b;\n\t\t}\n\n\t\tTop_bottom_manual_item = class \n\t\t\tMenuaction \"Manual T_op to Bottom\" \n\t\t\t\t\"join top-bottom, no auto-adjust of tie points\" {\n\t\t\taction a b = tb_mos false a b;\n\t\t}\n\t}\n\n\tMosaic_2point_item = class \n\t\tMenupullright \"_Two Point\" \"join two images with two tie points\" {\n\t\tcheck_abcd_args a b c d = [\n\t\t\t[a, \"a\", check_Mark],\n\t\t\t[b, \"b\", check_Mark],\n\t\t\t[c, \"c\", check_Mark],\n\t\t\t[d, \"d\", check_Mark]\n\t\t];\n\t\n\t\t// shortcut to prefs\n\t\tprefs = Workspaces.Preferences;\n\t\tsearch_area = prefs.MOSAIC_WINDOW_SIZE;\n\t\tobject_size = prefs.MOSAIC_OBJECT_SIZE;\n\t\tblend_width_widget = Scale \"Maximum blend width\" 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH;\n\t\trefine_widget = Toggle \"Refine selected tie-points\" prefs.MOSAIC_REFINE;\n\n\t\tLeft_right_item = class \n\t\t\tMenuaction \"_Left to Right\" \n\t\t\t\t\"join two images left-right with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_lrmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_lrmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_lr [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tTop_bottom_item = class \n\t\t\tMenuaction \"_Top to Bottom\" \n\t\t\t\t\"join two images top-bottom with a pair of tie points\" {\n\t\t\taction a b c d = class \n\t\t\t\tImage _result {\n\t\t\t\t_check_args = check_abcd_args a b c d;\n\t\n\t\t\t\tbw = blend_width_widget;\n\t\t\t\trefine = refine_widget;\n\t\n\t\t\t\t_result \n\t\t\t\t\t= im_tbmosaic1 a'.image.value b'.image.value 0\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\t(object_size / 2) (search_area / 2)\n\t\t\t\t\t\t0 bw.value,\n\t\t\t\t\t\t\trefine\n\t\t\t\t\t= im_tbmerge1 a'.image.value b'.image.value\n\t\t\t\t\t\ta'.left a'.top b'.left b'.top\n\t\t\t\t\t\tc'.left c'.top d'.left d'.top\n\t\t\t\t\t\tbw.value\n\t\t\t\t{\n\t\t\t\t\t[a', b', c', d'] = mosaic_sort mosaic_sort_tb [a, b, c, d];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\tsep1 = Menuseparator;\n\n\tBalance_item = class \n\t\tMenuaction \"Mosaic _Balance\" \n\t\t\t\"disassemble mosaic, scale brightness to match, reassemble\" {\n\t\taction x \n\t\t\t= map_unary balance x\n\t\t{\n\t\t\tbalance x\n\t\t\t\t= oo_unary_function balance_op x, is_class x\n\t\t\t\t= im_global_balancef x \n\t\t\t\t\tWorkspaces.Preferences.MOSAIC_BALANCE_GAMMA, \n\t\t\t\t\tis_image x\n\t\t\t\t= error (_ \"bad arguments to \" ++ \"balance\")\n\t\t\t{\n\t\t\t\tbalance_op = Operator \"balance\" balance \n\t\t\t\t\tOperator_type.COMPOUND_REWRAP false;\n\t\t\t}\n\t\t}\n\t}\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nManual_balance_item = class\n\tMenupullright \"Manual B_alance\" \"balance tonality of user defined areas\" {\n\tprefs = Workspaces.Preferences;\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_find_item = class\n\t\tMenuaction \"_Find Values\"\n\t\t\t \"calculates values required to scale and offset balance user defined areas in a given image\"\n\t\t\t /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary \n\t\t\t  * structure in an X-ray image.  Takes an X-ray image an 8-bit control mask and a list of \n\t\t\t  * 8-bit reference masks, where the masks are white on a black background.\n\t\t\t  */\n\t{\n\t\taction im_in m_control m_group = class\n\t\t\tMatrix values{\n\t\t\t_vislevel = 1;\n\n\t\t\t_control_im = if m_control then im_in else 0;\n\t\t\t_control_meanmax = so_meanmax _control_im;\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\n\t\t\tprocess m_current mat_in = mat_out\n\t\t\t\t{so_values  = so_calculate _control_meanmax im_in m_current;\n\t\t\t\t mat_out = join [so_values] mat_in;}\n\t\t\n\t\t\tvalues = (foldr process [] _m_list);\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_check_item = class \n\t\tMenuaction \"_Check Values\"\n\t\t\t \"allows calculated set of scale and offset values to be checked and adjusted if required\" \n\t\t\t /* Outputs adjusted matrix of scale and offset values and scale and offset image maps.\n\t\t\t  * Eg. Check values required to balance the secondary structure in an X-ray image.  \n\t\t\t  * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, \n\t\t\t  * where the masks are white on a black background. \n\t\t\t  */\n\t{\n\t\taction im_in m_matrix m_group = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 3;\n\t\t\t\n\t\t\tblur = Scale \"Blur\" 1 10 1;\n\t\t\t_blur = (blur.value/2 + 0.5), blur.value > 1\n\t\t\t\t  =  1;\n\t\t\n\t\t\t_group_check = is_Group m_group;\n\t\t\t_m_list = m_group.value, _group_check\n\t\t     \t\t= m_group;\n\t\t\t\t\t\t\n\t\t\tadjust = Matrix_rec mat_a\n\t\t\t\t{\n\t\t\t\tno_masks = len _m_list;\n\t\t\t\tmat_a = replicate no_masks [0, 0];\n\t\t\t\t}\n\t\t\t\n\t\t// Apply the user defined adjustments to the inputted matrix of scale and offset values\t \n\t\t\t_adjusted = map2 fn_adjust m_matrix.value adjust.value;\n\t\t\t\tfn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))];\n\t\t\t\t\n\t\t\t_scaled_ims = map (fn_so_apply im_in) _adjusted;\n\t\t\t\tfn_so_apply im so = map_unary adj im\n\t\t\t\t\t{adj im = im * (so?0) + (so?1);}\t\t\t\n\t\t\t_im_pairs = zip2 _m_list _scaled_ims;\n\t\t\t\n\t\t// Prepare black images as starting point. ////////////\n\t\t\t_blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0;\n\t\t\t_pair_start = [(_blank + 1), _blank];\n\t\t\t\n\t\t\tBuild = Toggle \"Build Scale and Offset Correction Images\" false;\n\t\t\t\n\t\t\tOutput = class\n\t\t\t\t{ \n\t\t\t\t_vislevel = 1;\n\t\t\t\tscale_im = _build?0;\n\t\t\t\toffset_im = _build?1;\t\n\t\t\t\tso_values = Matrix _adjusted;\n\t\t\t\t\n\t\t\t\t_build = [Image so_images?0, Image so_images?1], Build\n\t\t\t\t       = [\"Scale image not built.\", \"Offset image not built.\"]\n\t\t\t\t\t{\n\t\t\t\t\tm_list' = transpose [_m_list];\t\t\t\n\t\t\t\t\tm_all = map2 join m_list' _adjusted;\t\t\t\t\t\n\t\t\t\t\tso_images = foldr process_2 _pair_start m_all;\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t  \n\t\t\tvalue = (foldr process_1 im_in_b _im_pairs).value\n\t\t\t\t{im_in_b = map_unary cast_float im_in;}\n\t\t\t\t\n\t\t\tprocess_1 m_current im_start \n\t\t\t\t= im_out\n\t\t\t\t{ \n\t\t\t\tbl_mask    = convsep (matrix_blur _blur) (get_image m_current?0);\n\t\t\t\tblended_im  = im_blend bl_mask (m_current?1).value im_start.value;\n\t\t\t\tim_out      = Image (clip2fmt im_start.format blended_im);\n\t\t\t\t}\t\t\t\n\t\t\t\n\t\t\t// Process for building scale and offset image. \n\t\t\tprocess_2 current p_start \n\t\t\t\t= p_out\n\t\t\t\t{ \n\t\t\t\tim_s = if ((current?0) > 128) then current?1 else _blank;\n\t\t\t\tim_o = if ((current?0) > 128) then current?2 else _blank;\n\t\t\t\t\n\t\t\t\tim_s' = convsep (matrix_blur _blur) (im_s != 0);\n\t\t\t\tim_o' = convsep (matrix_blur _blur) (im_o != 0);\n\t\t\t\t\n\t\t\t\tim_s'' = im_blend im_s'.value im_s.value p_start?0;\n\t\t\t\tim_o'' = im_blend im_o'.value im_o.value p_start?1;\n\t\t\t\t\n\t\t\t\tp_out  = [im_s'', im_o''];\n\t\t\t\t}\n\t\t}\n\t}\n\t\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBalance_apply_item = class \n\t\tMenuaction \"_Apply Values\" \n\t\t\t \"apply scale and offset corrections, defined as image maps, to a given image\" \n\t\t\t /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image.  Takes an \n\t\t\t  * X-ray image an 32-bit float scale image and a 32-bit offset image.\n\t\t\t  */\n\t{\n\t\taction im_in scale_im offset_im = class\n\t\t\tImage value \n\t\t\t{\n\t\t\t_vislevel = 1;\n\n\t\t\txfactor = im_in.width/scale_im.width;\n\t\t\tyfactor = im_in.height/scale_im.height;\n\t\t\t\n\t\t\t_scale_im = resize Kernel_linear xfactor yfactor scale_im;\n\t\t\t_offset_im = resize Kernel_linear xfactor yfactor offset_im;\n\t\t\t\n\t\t\tvalue = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) +  _offset_im ) ); \t\n\t\t\t}\n\t\t}\n}\n\n    Tilt_item = Filter_tilt_item;\n\n\tsep2 = Menuseparator;\n\n\tRebuild_item = class \n\t\tMenuaction \"_Rebuild\" \n\t\t\t\"disassemble mosaic, substitute image files and reassemble\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\told = String \"In each filename, replace\" \"foo\";\n\t\t\tnew = String \"With\" \"bar\";\n\t\n\t\t\t_result\n\t\t\t\t= map_unary remosaic x\n\t\t\t{\n\t\t\t\tremosaic image \n\t\t\t\t\t= Image (im_remosaic image.value old.value new.value);\n\t\t\t}\n\t\t}\n\t}\n\n\tsep3 = Menuseparator;\n\nClone_area_item = class\n   Menuaction \"_Clone Area\"\n       \"replace dark or light section of im1 with pixels from im2\"\n   {\n   action im1 im2 = class\n       _result {\n       _check_args = [\n           [im1, \"im1\", check_Image],\n           [im2, \"im2\", check_Image]\n       ];\n                 _vislevel = 3;                            /* Region on first\nimage placed in the top left hand corner,\n        * positioned and size relative to the height and width of im1.\n        */\n       r1 = Region_relative im1 0.05 0.05 0.05 0.05;\n             /* Mark on second image placed in the top left hand corner,\n        * positioned relative to the height and width of im2. Used to\n        * define _r2, the region from which the section of image is cloned\n        * from.\n        */\n       p2 = Mark_relative im2 0.05 0.05;              _r2 = Region im2 p2.left\np2.top r1.width r1.height;\n             mask = [r1 <= Options.sc, r1 >=\nOptions.sc]?(Options.replace);\n                 Options = class\n           {\n           _vislevel = 3;\n                     pause = Toggle \"Pause process\" true;\n                         /* Option toggle used to define whether the user is\n            * replacing a dark or a light area.\n            */\n           replace = Option \"Replace\" [ \"A Dark Area\", \"A Light Area\" ] 1;\n\n           // Used to select the area to be replaced.\n            sc = Scale \"Scale cutoff\" 0.01 mx (mx / 2)\n               {mx = Image_format.maxval im1.format;}\n             //Allows replacement with scale&offset balanced gaussian noise.\n           balance = Toggle \"Balance cloned data to match surroundings.\" true;\n                             //Allows replacement with scale&offset balanced\n                             //gaussian noise.\n           process = Toggle \"Replace area with Gaussian noise.\" false;\n           }\n                     _result    = im1, Options.pause\n               = Image (im_insert im1.value patch r1.left r1.top)\n           {              r2 = Region im2 p2.left p2.top r1.width r1.height;\n           ref_meanmax = so_meanmax (if mask then 0 else r1);\n                     mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255],\n[255, 255, 255]];\n           mask_a = map_unary (dilate mask8) mask;\n           mask_b = convsep (matrix_blur 2) mask_a;\n                     patch = so_balance ref_meanmax r1 r2 mask_b\nOptions.process, Options.balance\n                 = so_balance ref_meanmax r1 r2 mask_b Options.process,\nOptions.process\n                 = im_blend (get_image mask_b) (get_image r2) (get_image r1);\n           }\n       }\n   } \n}\n\nTasks_frame_item = Frame_item;\n\nTasks_print_item = class\n\tMenupullright \"_Print\" \"useful stuff for image output\" {\n\n\tRotate_item = Image_transform_item.Rotate_item;\n\n\tFlip_item = Image_transform_item.Flip_item;\n\n\tResize_item = Image_transform_item.Resize_item;\n\n\tTone_item = Image_levels_item.Tone_item; \n\n\tSharpen_item = class \n\t\tMenuaction \"_Sharpen\" \n\t\t\t\"unsharp filter tuned for typical inkjet printers\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\t\n\t\t\ttarget_dpi = Option \"Sharpen for print at\" [\n\t\t\t\t\"400 dpi\",\n\t\t\t\t\"300 dpi\",\n\t\t\t\t\"150 dpi\",\n\t\t\t\t\"75 dpi\"\n\t\t\t] 1;\n\t\n\t\t\t_result\n\t\t\t\t= map_unary process x\n\t\t\t{\n\t\t\t\tprocess image\n\t\t\t\t\t= sharpen params?0 params?1 \n\t\t\t\t\t\tparams?2 params?3 params?4 params?5\n\t\t\t\t\t\t(colour_transform_to Image_type.LABQ image)\n\t\t\t\t{\n\t\t\t\t\t// sharpen params for various dpi\n\t\t\t\t\t// just change the size of the area we search\n\t\t\t\t\tparam_table = [\n\t\t\t\t\t\t[7, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[5, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[3, 2.5, 40, 20, 0.5, 1.5],\n\t\t\t\t\t\t[11, 2.5, 40, 20, 0.5, 1.5]\n\t\t\t\t\t];\n\t\t\t\t\tparams = param_table?target_dpi;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tsep1 = Menuseparator;\n\n\tTemp_item = Colour_temperature_item;\n\n\tICC_item = Colour_icc_item;\n}\n"
  },
  {
    "path": "share/nip2/start/Widgets.def",
    "content": "Widget_slider_item = class \n\tMenuaction \"_Scale\" \"make a new scale widget\" {\n\ticon = \"nip-slider-16.png\";\n\taction = Scale \"untitled scale\" 0 255 128;\n}\n\nWidget_toggle_item = class \n\tMenuaction \"_Toggle\" \"make a new toggle widget\" {\n\taction = Toggle \"untitled toggle\" false;\n}\n\nWidget_option_item = class \n\tMenuaction \"_Option\" \"make a new option widget\" {\n\taction = Option \"untitled option\" [\"option0\", \"option1\"] 0;\n}\n\nWidget_string_item = class \n\tMenuaction \"St_ring\" \"make a new string widget\" {\n\taction = String \"Enter a string\" \"sample text\";\n}\n\nWidget_number_item = class \n\tMenuaction \"_Number\" \"make a new number widget\" {\n\taction = Number \"Enter a number\" 42;\n}\n\nWidget_expression_item = class \n\tMenuaction \"_Expression\" \"make a new expression widget\" {\n\taction = Expression \"Enter an expression\" 42;\n}\n\nWidget_pathname_item = class \n\tMenuaction \"_File Chooser\" \"make a new file chooser widget\" {\n\taction = Pathname \"Pick a file\" \n\t\t\"$VIPSHOME/share/$PACKAGE/data/print_test_image.v\";\n}\n\nWidget_font_item = class \n\tMenuaction \"F_ont Chooser\" \"make a new font chooser widget\" {\n\taction = Fontname \"Pick a font\"  Workspaces.Preferences.PAINTBOX_FONT;\n}\n\nWidget_clock_item = class \n\tMenuaction \"_Clock\" \"make a new clock widget\" {\n\taction = Clock 1 1;\n}\n"
  },
  {
    "path": "share/nip2/start/_Object.def",
    "content": "/* Lots of little arg checks. Global for convenience.\n */\n\ncheck_any = [(const true), _ \"any\"];\ncheck_bool = [is_bool, _ \"boolean\"];\ncheck_real = [is_real, _ \"real\"];\ncheck_ureal = [is_ureal, _ \"unsigned real\"];\ncheck_preal = [is_preal, _ \"positive real\"];\ncheck_list = [is_list, _ \"list\"];\ncheck_real_list = [is_real_list, _ \"list of real\"];\ncheck_string = [is_string, _ \"string\"];\ncheck_string_list = [is_string_list, _ \"list of string\"];\ncheck_int = [is_int, _ \"integer\"];\ncheck_uint = [is_uint, _ \"unsigned integer\"];\ncheck_pint = [is_pint, _ \"positive integer\"];\ncheck_matrix = [is_matrix, _ \"rectangular array of real\"];\ncheck_matrix_display = [Matrix_display.is_display, _ \"0|1|2|3\"];\ncheck_image = [is_image, _ \"image\"];\ncheck_xy_list = [is_xy_list, _ \"list of form [[1, 2], [3, 4], [5, 6], ...]\"];\ncheck_instance name = [is_instanceof name, name];\ncheck_Image = check_instance \"Image\";\ncheck_Matrix = [is_Matrix, _ \"Matrix\"];\ncheck_colour_space = [is_colour_space, \n\tjoin_sep \"|\" Image_type.colour_spaces.names];\ncheck_rectangular = [is_rectangular, _ \"rectangular [[*]]\"];\ncheck_Guide = [is_Guide, _ \"HGuide|VGuide\"];\ncheck_Colour = check_instance (_ \"Colour\");\ncheck_Mark = check_instance (_ \"Mark\");\n\n/* Check a set of args to a class. Two members to look at: _check_args and\n * _check_all.\n *\n * - each line in _check_args is [arg, \"arg name\", [test_fn, \"arg type\"]]\n *   same number of lines as there are args\n *\n *   stuff like \"arg 2 must be real\"\n *\n * - each line in _check_all is [test, \"description\"]\n *   any number of lines \n *\n *   stuff like \"to must be greater than from\"\n *\n * generate an error dialog with a helpful message on failure.\n *\n * Have as a separate function to try to keep the size of _Object down.\n */\ncheck_args x\n\t= error message, badargs != [] || badalls != []\n\t= x\n{\n\targcheck = x._check_args;\n\tallcheck = x._check_all;\n\n\t// indent string\n\tindent = \"    \";\n\n\t// test for a condition in a check line fails\n\ttest_fail x = ! x?0;\n\n\t// set of failed argcheck indexes\n\tbadargs = map (extract 1) \n\t\t(filter test_fail (zip2 (map testarg argcheck) [0..]))\n\t{\n\t\ttestarg x = x?2?0 x?0;\n\t}\n\n\t// set of failed allcheck indexes\n\tbadalls = map (extract 1) \n\t\t(filter test_fail (zip2 (map hd allcheck) [0..]));\n\n\t// the error message\n\tmessage = _ \"bad properties for \" ++ \"\\\"\" ++ x.name ++ \"\\\"\\n\" ++\n\t\targmsg ++ allmsg ++ \"\\n\" ++\n\t\t_ \"where\" ++ \"\\n\" ++ arg_types ++ extra;\n\n\t// make the failed argcheck messages ... eg.  \"\"value\" should be \n\t// real, you passed <function>\" etc.\n\targmsg = concat (map fmt badargs)\n\t{\n\t\tfmt n = indent ++ \"\\\"\" ++ argcheck?n?1 ++ \"\\\"\" ++\n\t\t\t_ \" should be of type \" ++ argcheck?n?2?1 ++ \", \" ++\n\t\t\t_ \"you passed\" ++ \":\\n\" ++ \n\t\t\tindent ++ indent ++ print argcheck?n?0 ++ \"\\n\";\n\t}\n\n\t// make the failed allcheck messages ... eg \"condition failed:\n\t// x < y\" ... don't make a message if any typechecks have \n\t// failed, as we'll probably error horribly\n\tallmsg \n\t\t= [], badargs != []\n\t\t= concat (map fmt badalls) ++ \n\t\t\t_ \"you passed\" ++ \"\\n\" ++\n\t\t\tconcat (map fmt_arg argcheck)\n\t{\n\t\tfmt n = _ \"condition failed\" ++ \": \" ++ allcheck?n?1 ++ \"\\n\";\n\t\tfmt_arg l = indent ++ l?1 ++ \" = \" ++ print l?0 ++ \"\\n\";\n\t}\n\n\t// make arg type notes\n\targ_types = join_sep \"\\n\" (map fmt argcheck)\n\t{\n\t\tfmt l = indent ++ l?1 ++ \" is of type \" ++ l?2?1;\n\t}\n\n\t// extra bit at the bottom, if we have any conditions\n\textra \n\t\t= [], allcheck == []\n\t\t= \"\\n\" ++ _ \"and\" ++ \"\\n\" ++ all_desc;\n\n\t// make a list of all the allcheck descriptions, with a few \n\t// spaces in front\n\tall_desc_list = map (join indent @ extract 1) allcheck;\n\n\t// join em up to make a set of condition notes\n\tall_desc = join_sep \"\\n\" all_desc_list;\n}\n\n/* Operator overloading stuff.\n */\n\nOperator_type = class {\n\tARITHMETIC = 1;\t\t\t// eg. add\n\tRELATIONAL = 2;\t\t\t// eg. less\n\tCOMPOUND = 3;\t\t\t// eg. max/mean/etc.\n\tCOMPOUND_REWRAP = 4;\t// eg. transpose\n}\n\nOperator op_name fn type symmetric = class {\n}\n\n/* Form the converse of an Operator.\n */\noo_converse op \n\t= Operator (converse_name op.op_name) \n\t\t(converse op.fn) op.type op.symmetric\n{\n\tconverse_name x\n\t\t= init x, last x == last \"'\"\n\t\t= x ++ \"'\";\n}\n\n/* Given an operator name, look up the definition.\n */\noo_binary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown binary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\tOperator \"add\" add \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"subtract\" subtract \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"remainder\" remainder \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"power\" power \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"subscript\" subscript \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"left_shift\" left_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"right_shift\" right_shift \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"divide\" divide \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"join\" join \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"multiply\" multiply \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_and\" logical_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"logical_or\" logical_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_and\" bitwise_and \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"bitwise_or\" bitwise_or \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"eor\" eor \n\t\t\tOperator_type.ARITHMETIC true,\n\t\tOperator \"comma\" comma \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"if_then_else\" if_then_else \n\t\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"equal\" equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"not_equal\" not_equal \n\t\t\tOperator_type.RELATIONAL true,\n\t\tOperator \"less\" less \n\t\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"less_equal\" less_equal \n\t\t\tOperator_type.RELATIONAL false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Given an operator name, look up a function that implements that\n * operator.\n */\noo_unary_lookup op_name\n\t= matches?0, matches != []\n\t= error (_ \"unknown unary operator\" ++ \": \" ++ print op_name)\n{\n\toperator_table = [\n\t\t/* Operators.\n\t\t */\n\t\tOperator \"cast_signed_char\" cast_signed_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_char\" cast_unsigned_char \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_short\" cast_signed_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_short\" cast_unsigned_short \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_signed_int\" cast_signed_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_unsigned_int\" cast_unsigned_int \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_float\" cast_float \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double\" cast_double \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_complex\" cast_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"cast_double_complex\" cast_double_complex \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_minus\" unary_minus \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"negate\" negate \n\t\tOperator_type.RELATIONAL false,\n\t\tOperator \"complement\" complement \n\t\tOperator_type.ARITHMETIC false,\n\t\tOperator \"unary_plus\" unary_plus \n\t\tOperator_type.ARITHMETIC false,\n\n\t\t/* Built in projections.\n \t\t */\n\t\tOperator \"re\" re Operator_type.ARITHMETIC false,\n\t\tOperator \"im\" im Operator_type.ARITHMETIC false,\n\t\tOperator \"hd\" hd Operator_type.ARITHMETIC false,\n\t\tOperator \"tl\" tl Operator_type.ARITHMETIC false,\n\n\t\t/* Maths builtins.\n\t\t */\n\t\tOperator \"sin\" sin Operator_type.ARITHMETIC false,\n\t\tOperator \"cos\" cos Operator_type.ARITHMETIC false,\n\t\tOperator \"tan\" tan Operator_type.ARITHMETIC false,\n\t\tOperator \"asin\" asin Operator_type.ARITHMETIC false,\n\t\tOperator \"acos\" acos Operator_type.ARITHMETIC false,\n\t\tOperator \"atan\" atan Operator_type.ARITHMETIC false,\n\t\tOperator \"log\" log Operator_type.ARITHMETIC false,\n\t\tOperator \"log10\" log10 Operator_type.ARITHMETIC false,\n\t\tOperator \"exp\" exp Operator_type.ARITHMETIC false,\n\t\tOperator \"exp10\" exp10 Operator_type.ARITHMETIC false,\n\t\tOperator \"ceil\" ceil Operator_type.ARITHMETIC false,\n\t\tOperator \"floor\" floor Operator_type.ARITHMETIC false\n\t];\n\n\tmatches = filter test_name operator_table;\n\ttest_name x = x.op_name == op_name;\n}\n\n/* Find the matching methods in a method table.\n */\noo_method_lookup table = map (extract 0) (filter (extract 1) table);\n\n/* A binary op: a is a class, b may be a class ... eg. \"add\" a b\n\n   two obvious ways to find a method:\n\n   - a.oo_binary_search \"add\" (+) b\n   - b.oo_binary_search \"add'\" (converse (+)) a, is_class b\n\n   if these fail but op is a symmetric operator (eg. a + b == b + a), we can\n   also try reversing the args\n\n   - a.oo_binary_search \"add'\" (converse (+)) b\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if those fail as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary_function op a b\n\t= matches1?0, \n\t\tmatches1 != []\n\t= matches2?0, \n\t\tis_class b && matches2 != []\n\t= matches3?0, \n\t\top.symmetric && matches3 != []\n\t= matches4?0, \n\t\top.symmetric && is_class b && matches4 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (a.oo_binary_table op b);\n\tmatches2 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches3 = oo_method_lookup (a.oo_binary_table (oo_converse op) b);\n\tmatches4 = oo_method_lookup (b.oo_binary_table op a);\n}\n\n/* A binary op: a is not a class, b is a class ... eg. \"subtract\" a b\n\n   only one way to find a method:\n\n   - b.oo_binary_search \"subtract'\" (converse (-)) a\n\n   if this fails but op is a symmetric operator (eg. a + b == b + a), we can\n   try reversing the args\n\n   - b.oo_binary_search \"add\" (+) a, is_class b\n\n   if that fails as well, but this is ==, do pointer equals as a fallback\n\n */\noo_binary'_function op a b\n\t= matches1?0, matches1 != []\n\t= matches2?0, op.symmetric && matches2 != []\n\t= pointer_equal a b,\n\t\top.op_name == \"equal\" || op.op_name == \"equal'\"\n\t= not_pointer_equal a b,\n\t\top.op_name == \"not_equal\" || op.op_name == \"not_equal'\"\n\t= error (_ \"No method found for binary operator.\" ++ \"\\n\" ++\n\t\t_ \"left\" ++ \" = \" ++ print a ++ \"\\n\" ++\n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"right\" ++ \" = \" ++ print b)\n{\n\tmatches1 = oo_method_lookup (b.oo_binary_table (oo_converse op) a);\n\tmatches2 = oo_method_lookup (b.oo_binary_table op a);\n}\n\noo_unary_function op x\n\t= matches?0, matches != []\n\t= error (_ \"No method found for unary operator.\" ++ \"\\n\" ++ \n\t\t_ \"operator\" ++ \" = \" ++ op.op_name ++ \"\\n\" ++\n\t\t_ \"argument\" ++ \" = \" ++ print x)\n{\n\tmatches = oo_method_lookup (x.oo_unary_table op);\n}\n\n/* Base class for nip's built-in classes ... base check function, base\n * operator overload functions.\n */\n_Object = class {\n\tcheck = check_args this;\n\n\t// these should always be defined\n\t_check_args = [];\n\t_check_all = [];\n\n\t/* Operator overloading stuff.\n\t */\n\too_binary op x = oo_binary_function (oo_binary_lookup op) this x;\n\too_binary' op x = oo_binary'_function (oo_binary_lookup op) x this;\n\too_unary op = oo_unary_function (oo_unary_lookup op) this;\n\n\too_binary_table op x = [];\n\too_unary_table op = [];\n}\n"
  },
  {
    "path": "share/nip2/start/_convert.def",
    "content": "\n/* Try to make a Matrix ... works for Vector/Image/Real, plus image/real\n */\nto_matrix x\n\t= to_matrix x.expr, is_Expression x\n\t= x, is_Matrix x\n\t= oo_unary_function to_matrix_op x, is_class x\n\t= tom x\n{\n\tto_matrix_op = Operator \"to_matrix\" tom Operator_type.COMPOUND false;\n\n\ttom x\n\t\t= Matrix (itom x), is_image x\n\t\t= Matrix [[x]], is_real x\n\t\t= Matrix [x], is_real_list x\n\t\t= Matrix x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_matrix\");\n\n\titom i\n\t\t= (im_vips2mask ((double) i)).value, is_image i \n\t\t= error (_ \"not image\");\n}\n\n/* Try to make a Vector ... works for Vector/Image/Real, plus image/real\n */\nto_vector x\n\t= to_vector x.expr, is_Expression x\n\t= x, is_Vector x\n\t= oo_unary_function to_vector_op x, is_class x\n\t= tov x\n{\n\tto_vector_op = Operator \"to_vector\" tov Operator_type.COMPOUND false;\n\n\ttov x\n\t\t= Vector (itov x), is_image x\n\t\t= Vector [x], is_real x\n\t\t= Vector x, is_real_list x\n\t\t= Vector x?0, is_matrix x && len x == 1\n\t\t= Vector (transpose x)?0, is_matrix x && len x?0 == 1\n\t\t= error (_ \"bad arguments to \" ++ \"to_vector\");\n\n\titov i\n\t\t= v, is_image i \n\t\t= error (_ \"not image\")\n\t{\n\t\tm = im_vips2mask ((double) i);\n\t\tv \n\t\t\t= m.value?0, m.height == 1\n\t\t\t= (transpose m.value)?0, m.width == 1\n\t\t\t= error (_ \"image is not 1xN or Nx1\");\n\t}\n}\n\n/* Try to make an Image ... works for Vector/Matrix/Real, plus image/real\n * Special case for Colour ... pull out the colour_space and set Type in the\n * image.\n */\nto_image x\n\t= to_image x.expr, is_Expression x\n\t= Image x.value, is_Plot x\n\t= x, is_Image x\n\t= Image (image_set_type \n\t\t\t(Image_type.colour_spaces.lookup 0 1 x.colour_space)\n\t\t\t(mtoi [x.value])),\n\t\tis_Colour x\n\t= oo_unary_function to_image_op x, is_class x\n\t= toi x\n{\n\tto_image_op = Operator \"to_image\" toi Operator_type.COMPOUND false;\n\n\ttoi x\n\t\t= Image x, is_image x\n\t\t= Image (mtoi [[x]]), is_real x\n\t\t= Image (mtoi [x]), is_real_list x\n\t\t= Image (mtoi x), is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_image\");\n\n\t// [[real]] -> image\n\tmtoi m\n\t\t= im_mask2vips (Matrix m), width != 3\n\t\t= joinup (im_mask2vips (Matrix m))\n\t{\n\t\twidth = len m?0;\n\t\theight = len m;\n\t\tjoinup i\n\t\t\t= b1 ++ b2 ++ b3\n\t\t{\n\t\t\tb1 = extract_area 0 0 1 height i;\n\t\t\tb2 = extract_area 1 0 1 height i;\n\t\t\tb3 = extract_area 2 0 1 height i;\n\t\t}\n\t}\n}\n\n// like to_image, but we do 1x1 pixel + x, then embed it up\n// always make an unwrapped image for speed ... this gets used by ifthenelse\n// and stuff like that\n// format can be NULL, meaning set format from x\nto_image_size width height bands format x\n\t= x, is_image x\n\t= x.value, is_Image x\n\t= im''\n{\n\t// we want x to set the target format if we don't have one, so we\n\t// can't use image_new\n\tim = im_black 1 1 bands + x;\n\tim'\n\t\t= clip2fmt format im, format != NULL\n\t\t= im;\n\tim'' = embed 1 0 0 width height im';\n}\n\n/* Try to make a Colour.\n */\nto_colour x\n\t= to_colour x.expr, is_Expression x\n\t= x, is_Colour x\n\t= to_colour (extract_area x.left x.top 1 1 x.image), is_Mark x\n\t= oo_unary_function to_colour_op x, is_class x\n\t= toc x\n{\n\tto_colour_op = Operator \"to_colour\" toc Operator_type.COMPOUND false;\n\n\ttoc x\n\t\t= Colour (colour_space (get_type x)) \n\t\t\t(map mean (bandsplit (get_image x))),\n\t\t\thas_image x && has_type x\n\t\t= Colour \"sRGB\" [x, x, x], is_real x\t// since Colour can't do mono\n\t\t= Colour \"sRGB\" x, is_real_list x && is_list_len 3 x\n\t\t= map toc x, is_matrix x\n\t\t= error (_ \"bad arguments to \" ++ \"to_colour\");\n\n\tcolour_space type\n\t\t= table.get_name type, table.has_name type\n\t\t= error (_ \"unable to make Colour from \" ++ table.get_name type ++ \n\t\t\t_ \" image\")\n\t{\n\t\ttable = Image_type.colour_spaces;\n\t}\n}\n\n/* Try to make a real. (not a Real!)\n */\nto_real x\n\t= to_real x.expr, is_Expression x\n\t= oo_unary_function to_real_op x, is_class x\n\t= tor x\n{\n\tto_real_op = Operator \"to_real\" tor Operator_type.COMPOUND false;\n\n\ttor x\n\t\t= x, is_real x\n\t\t= abs x, is_complex x\n\t\t= 1, is_bool x && x\n\t\t= 0, is_bool x && !x\n\t\t= error (_ \"bad arguments to \" ++ \"to_real\");\n}\n\nto_int x = (int) (to_real x);\n\n/* Try to make a list ... ungroup, basically. We remove the innermost layer of\n * Groups.\n */\nto_list x\n\t= x.value, is_Group x && !contains_Group x.value\n\t= Group (map to_list x.value), is_Group x\n\t= x;\n\n/* Try to make a group. The outermost list objects become Group()'d.\n */\nto_group x\n\t= Group x, is_list x \n\t= Group (map to_group x.value), is_Group x\n\t= x;\n\n/* Parse a positive integer.\n */\nparse_pint l\n\t= foldl acc 0 l\n{\n\tacc sofar ch = sofar * 10 + parse_c ch;\n\n\t/* Turn a char digit to a number.\n\t */\n\tparse_c ch\n\t\t= error (_ \"not a digit\"), !is_digit ch\n\t\t= (int) ch - (int) '0';\n}\n\n/* Parse an integer, with an optional sign character.\n */\nparse_int l\n\t= error (_ \"badly formed number\"), !is_list_len 2 parts \n\t= sign * n\n{\n\tparts = splitpl [member \"+-\", is_digit] l;\n\n\tn = parse_pint parts?1;\n\tsign\n\t\t= 1, parts?0 == [] || parts?0 == \"+\"\n\t\t= -1;\n}\n\n/* Parse a float. \n *\t[+-]?[0-9]*([.][0-9]*)?(e[0-9]+)?\n */\nparse_float l\n\t= err, !is_list_len 4 parts \n\t= sign * (abs ipart + fpart) * 10 ** exp\n{\n\terr = error (_ \"badly formed number\");\n\n\tparts = splitpl [\n\t\tmember \"+-0123456789\", \n\t\tmember \".0123456789\",\n\t\tmember \"eE\", \n\t\tmember \"+-0123456789\"\n\t] l;\n\n\tipart = parse_int parts?0;\n\tsign \n\t\t= 1, ipart >= 0\n\t\t= -1;\n\tfpart\n\t\t= 0, parts?1 == [];\n\t\t= err, parts?1?0 != '.'\n\t\t= parse_pint (tl parts?1) / 10 ** (len parts?1 - 1);\n\texp\n\t\t= 0, parts?2 == [] && parts?3 == []\n\t\t= err, parts?2 == [] \n\t\t= parse_int parts?3;\n\n}\n\n/* Parse a time in \"hh:mm:ss\" into seconds.\n\nWe could do this in one line :)\n\n\t= (sum @ map2 multiply (iterate (multiply 60) 1) @ reverse @ map\n\tparse_pint @ map (subscript (splitpl [is_digit, equal ':', is_digit,\n\tequal ':', is_digit] l))) [0,2,4];\n\nbut it's totally unreadable.\n\n */\nparse_time l\n\t= error (_ \"badly formed time\"), !is_list_len 5 parts \n\t= s + 60 * m + 60 * 60 * h\n{\n\tparts = splitpl [is_digit, equal ':', is_digit, equal ':', is_digit] l;\n\th = parse_int parts?0;\n\tm = parse_int parts?2;\n\ts = parse_int parts?4;\n}\n\n/* matrix to convert D65 XYZ to D50 XYZ ... direct conversion, found by\n * measuring a macbeth chart in D50 and D65 and doing a LMS to get a matrix\n */\nD652D50_direct = Matrix\n\t[[ 1.13529, -0.0604663, -0.0606321 ],\n\t [ 0.0975399, 0.935024, -0.0256156 ],\n\t [ -0.0336428, 0.0414702, 0.994135 ]];\n\nD502D65_direct = D652D50_direct ** -1;\n\n/* Convert normalised XYZ to bradford RGB.\n */\nXYZ2RGBbrad = Matrix\n\t[[0.8951,  0.2664, -0.1614],\n\t [-0.7502,  1.7135,  0.0367],\n\t [0.0389, -0.0685,  1.0296]];\n\n/* Convert bradford RGB to normalised XYZ.\n */\nRGBbrad2XYZ = XYZ2RGBbrad ** -1;\n\nD93_whitepoint = Vector [89.7400, 100, 130.7700];\nD75_whitepoint = Vector [94.9682, 100, 122.5710];\nD65_whitepoint = Vector [95.0470, 100, 108.8827];\nD55_whitepoint = Vector [95.6831, 100, 92.0871];\nD50_whitepoint = Vector [96.4250, 100, 82.4680];\nA_whitepoint = Vector [109.8503, 100, 35.5849]; \t// 2856K\nB_whitepoint = Vector [99.0720, 100, 85.2230];\t\t// 4874K\nC_whitepoint = Vector [98.0700, 100, 118.2300];\t\t// 6774K\nE_whitepoint = Vector [100, 100, 100];\t\t\t// ill. free\nD3250_whitepoint = Vector [105.6590, 100, 45.8501];\n\nWhitepoints = Enum [\n\t$D93 => D93_whitepoint,\n\t$D75 => D75_whitepoint,\n\t$D65 => D65_whitepoint,\n\t$D55 => D55_whitepoint,\n\t$D50 => D50_whitepoint,\n\t$A => A_whitepoint,\n\t$B => B_whitepoint,\n\t$C => C_whitepoint,\n\t$E => E_whitepoint,\n\t$D3250 => D3250_whitepoint\n];\n\n/* Convert D50 XYZ to D65 using the bradford chromatic adaptation approx.\n */\nim_D502D65 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D50_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb / Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\t// back to D65\n\txyz''' = xyz'' * D65_whitepoint;\n}\n\n/* Convert D65 XYZ to D50 using the bradford approx.\n */\nim_D652D50 xyz\n\t= xyz'''\n{\n\txyz' = xyz / D65_whitepoint;\n\n\trgb = recomb XYZ2RGBbrad xyz';\n\n\t// move white in bradford RGB\n\trgb' = rgb * Vector [0.94, 1.02, 1.33];\n\n\txyz'' = recomb RGBbrad2XYZ rgb';\n\n\txyz''' = xyz'' * D50_whitepoint;\n}\n\n/* Convert D50 XYZ to Lab.\n */\nim_D50XYZ2Lab xyz\n\t= im_XYZ2Lab_temp xyz \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\nim_D50Lab2XYZ lab\n\t= im_Lab2XYZ_temp lab \n\t\tD50_whitepoint.value?0 \n\t\tD50_whitepoint.value?1 \n\t\tD50_whitepoint.value?2;\n\n/* ... and mono conversions\n */\nim_sRGB2mono in \n\t= (image_set_type Image_type.B_W @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_mono2sRGB in \n\t= image_set_type Image_type.sRGB (in ++ in ++ in);\n\nim_sRGB2Lab = im_XYZ2Lab @ im_sRGB2XYZ;\n\nim_Lab2sRGB = im_XYZ2sRGB @ im_Lab2XYZ;\n\n// from the 16 bit RGB and GREY formats\nim_1628 x = im_clip (x >> 8);\nim_162f x = x / 256;\n\nim_8216 x = (im_clip2us x) << 8;\nim_f216 x = im_clip2us (x * 256);\n\nim_RGB162GREY16 in \n\t= (image_set_type Image_type.GREY16 @ \n\t\tclip2fmt (get_header \"BandFmt\" in) @ \n\t\t\trecomb (Matrix [[.3, .6, .1]])) in;\nim_GREY162RGB16 in \n\t= image_set_type Image_type.RGB16 (in ++ in ++ in);\n\n/* The vips8 scRGB functions.\n */\n\nim_sRGB2scRGB in\n\t= out\n{\n\t[out] = vips_call \"sRGB2scRGB\" [in] [];\n}\n\nim_scRGB2sRGB in\n\t= out\n{\n\t[out] = vips_call \"scRGB2sRGB\" [in] [];\n}\n\nim_scRGB2XYZ in\n\t= out\n{\n\t[out] = vips_call \"scRGB2XYZ\" [in] [];\n}\n\nim_XYZ2scRGB in\n\t= out\n{\n\t[out] = vips_call \"XYZ2scRGB\" [in] [];\n}\n\n/* apply a func to an image ... make it 1 or 3 bands, and reapply other bands\n * on the way out. Except if it's LABPACK.\n */\ncolour_apply fn x\n\t= fn x, b == 1 || b == 3 || c == Image_coding.LABPACK\n\t= x''\n{\n\tb = get_bands x;\n\tc = get_coding x;\n\n\tfirst\n\t\t= extract_bands 0 3 x, b > 3\n\t\t= extract_bands 0 1 x;\n\ttail \n\t\t= extract_bands 3 (b - 3) x, b > 3\n\t\t= extract_bands 1 (b - 1) x;\n\tx' = fn first;\n\tx'' = x' ++ clip2fmt (get_format x') tail;\n}\n\n/* Any 1-ary colour op, applied to Vector/Image/Matrix or image\n */\ncolour_unary fn x\n\t= oo_unary_function colour_op x, is_class x\n\t= colour_apply fn x, is_image x\n\t= colour_apply fn [x], is_real x\n\t= error (_ \"bad arguments to \" ++ \"colour_unary\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\tcolour_op = Operator \"colour_unary\" \n\t\tcolour_object Operator_type.COMPOUND_REWRAP false;\n\n\tcolour_object x\n\t\t= colour_real_list x, is_real_list x\n\t\t= map colour_real_list x, is_matrix x \n\t\t= colour_apply fn x, is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"colour_unary\");\n\n\tcolour_real_list l\n\t\t= (to_matrix (fn (float) (to_image (Vector l)).value)).value?0;\n}\n\n/* Any symmetric 2-ary colour op, applied to Vector/Image/Matrix or image ...\n * name is op name for error messages etc.\n */\ncolour_binary name fn x y\n\t= oo_binary_function colour_op x y, is_class x\n\t= oo_binary'_function colour_op x y, is_class y\n\t= fn x y, is_image x && is_image y\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tcolour_op = Operator name \n\t\tcolour_object Operator_type.COMPOUND_REWRAP true;\n\n\tcolour_object x y\n\t\t= fn x y, is_image x && is_image y\n\t\t= colour_real_list fn x y, is_real_list x && is_real_list y\n\t\t= map (colour_real_list fn x) y, is_real_list x && is_matrix y \n\t\t= map (colour_real_list (converse fn) y) x, \n\t\t\tis_matrix x && is_real_list y \n\t\t= map2 (colour_real_list fn) x y, is_matrix x && is_matrix y \n\t\t= error (_ \"bad arguments to \" ++ name);\n\n\tcolour_real_list fn l1 l2\n\t\t= (to_matrix (fn i1 i2)).value?0\n\t{\n\t\ti1 = (float) (to_image (Vector l1)).value;\n\t\ti2 = (float) (to_image (Vector l2)).value;\n\t}\n}\n\n_colour_conversion_table = [\n\t/* Lines are [space-from, space-to, conversion function]. Could do\n\t * this as a big array, but table lookup feels safer.\n\t */\n\t[B_W, B_W, image_set_type B_W],\n\t[B_W, XYZ, im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, LAB, im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_mono2sRGB @ im_clip],\n\t[B_W, sRGB, im_mono2sRGB @ im_clip],\n\t[B_W, scRGB, im_sRGB2scRGB @ im_mono2sRGB @ im_clip],\n\t[B_W, RGB16, image_set_type RGB16 @ im_8216 @ im_mono2sRGB],\n\t[B_W, GREY16, image_set_type GREY16 @ im_8216],\n\t[B_W, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_mono2sRGB @ im_clip],\n\t[B_W, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab @ \n\t\tim_mono2sRGB @ im_clip],\n\n\t[XYZ, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, XYZ, image_set_type XYZ],\n\t[XYZ, YXY, im_XYZ2Yxy @ im_clip2f],\n\t[XYZ, LAB, im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LCH, im_Lab2LCh @ im_XYZ2Lab],\n\t[XYZ, UCS, im_XYZ2UCS @ im_clip2f],\n\t[XYZ, RGB, im_XYZ2disp @ im_clip2f],\n\t[XYZ, sRGB, im_XYZ2sRGB @ im_clip2f],\n\t[XYZ, scRGB, im_XYZ2scRGB @ im_clip2f],\n\t[XYZ, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\t[XYZ, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_clip2f],\n\n\t[YXY, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, XYZ, im_Yxy2XYZ @ im_clip2f],\n\t[YXY, YXY, image_set_type YXY],\n\t[YXY, LAB, im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, UCS, im_XYZ2UCS @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, RGB, im_XYZ2disp @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, sRGB, im_XYZ2sRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, scRGB, im_XYZ2scRGB @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @ im_clip2f],\n\t[YXY, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_XYZ2Lab @ im_Yxy2XYZ @\n\t\tim_clip2f],\n\n\t[LAB, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, XYZ, im_Lab2XYZ @ im_clip2f],\n\t[LAB, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LAB, image_set_type LAB @ im_clip2f],\n\t[LAB, LCH, im_Lab2LCh @ im_clip2f],\n\t[LAB, UCS, im_Lab2UCS @ im_clip2f],\n\t[LAB, RGB, im_Lab2disp @ im_clip2f],\n\t[LAB, sRGB, im_Lab2sRGB @ im_clip2f],\n\t[LAB, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_clip2f],\n\t[LAB, LABQ, im_Lab2LabQ @ im_clip2f],\n\t[LAB, LABS, im_Lab2LabS @ im_clip2f],\n\n\t[LCH, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, XYZ, im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LAB, im_LCh2Lab @ im_clip2f],\n\t[LCH, LCH, image_set_type LCH],\n\t[LCH, UCS, im_LCh2UCS @ im_clip2f],\n\t[LCH, RGB, im_Lab2disp @ im_LCh2Lab @ im_clip2f],\n\t[LCH, sRGB, im_Lab2sRGB @ im_LCh2Lab @ im_clip2f],\n\t[LCH, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABQ, im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\t[LCH, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_LCh2Lab @ im_clip2f],\n\n\t[UCS, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_UCS2XYZ @ im_clip2f],\n\t[UCS, XYZ, im_UCS2XYZ @ im_clip2f],\n\t[UCS, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LAB, im_UCS2Lab @ im_clip2f],\n\t[UCS, LCH, im_UCS2LCh @ im_clip2f],\n\t[UCS, UCS, image_set_type UCS],\n\t[UCS, RGB, im_Lab2disp @ im_UCS2Lab @ im_clip2f],\n\t[UCS, sRGB, im_Lab2sRGB @ im_UCS2Lab @ im_clip2f],\n\t[UCS, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABQ, im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\t[UCS, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_UCS2Lab @ im_clip2f],\n\n\t[RGB, B_W, im_sRGB2mono @ im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, XYZ, im_disp2XYZ @ im_clip],\n\t[RGB, YXY, im_XYZ2Yxy @ im_disp2XYZ @ im_clip],\n\t[RGB, LAB, im_disp2Lab @ im_clip],\n\t[RGB, LCH, im_Lab2LCh @ im_disp2Lab @ im_clip],\n\t[RGB, UCS, im_Lab2UCS @ im_disp2Lab @ im_clip],\n\t[RGB, RGB, image_set_type RGB],\n\t[RGB, sRGB, im_XYZ2sRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, scRGB, im_XYZ2scRGB @ im_disp2XYZ @ im_clip],\n\t[RGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[RGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[RGB, LABQ, im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\t[RGB, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_disp2Lab @ im_clip],\n\n\t[sRGB, B_W, im_sRGB2mono],\n\t[sRGB, XYZ, im_sRGB2XYZ @ im_clip],\n\t[sRGB, YXY, im_XYZ2Yxy @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, LAB, im_sRGB2Lab @ im_clip],\n\t[sRGB, LCH, im_Lab2LCh @ im_sRGB2Lab @ im_clip],\n\t[sRGB, UCS, im_XYZ2UCS @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, RGB, im_XYZ2disp @ im_sRGB2XYZ @ im_clip],\n\t[sRGB, sRGB, image_set_type sRGB],\n\t[sRGB, scRGB, im_sRGB2scRGB @ im_clip],\n\t[sRGB, RGB16, image_set_type RGB16 @ im_8216],\n\t[sRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono],\n\t[sRGB, LABQ, im_Lab2LabQ @ im_sRGB2Lab @ im_clip],\n\t[sRGB, LABS, im_Lab2LabS @ im_sRGB2Lab @ im_clip],\n\n\t[scRGB, B_W, im_sRGB2mono @ im_scRGB2sRGB],\n\t[scRGB, XYZ, im_scRGB2XYZ],\n\t[scRGB, YXY, im_XYZ2Yxy @ im_scRGB2XYZ],\n\t[scRGB, LAB, im_XYZ2Lab @ im_scRGB2XYZ],\n\t[scRGB, LCH, im_Lab2LCh @ im_XYZ2Lab @ im_scRGB2XYZ],\n\t[scRGB, UCS, im_XYZ2UCS @ im_scRGB2XYZ],\n\t[scRGB, RGB, im_XYZ2disp @ im_scRGB2XYZ],\n\t[scRGB, sRGB, im_scRGB2sRGB],\n\t[scRGB, scRGB, image_set_type scRGB],\n\t[scRGB, RGB16, image_set_type RGB16 @ im_8216 @ im_scRGB2sRGB],\n\t[scRGB, GREY16, image_set_type GREY16 @ im_8216 @ im_sRGB2mono @ \n\t\tim_scRGB2sRGB],\n\t[scRGB, LABQ, im_Lab2LabQ @ im_XYZ2Lab @ im_scRGB2XYZ],\n\t[scRGB, LABS, im_Lab2LabS @ im_XYZ2Lab @ im_scRGB2XYZ],\n\n\t[RGB16, B_W, im_1628 @ im_sRGB2mono],\n\t[RGB16, RGB, image_set_type RGB @ im_1628],\n\t[RGB16, sRGB, image_set_type sRGB @ im_1628],\n\t[RGB16, scRGB, im_sRGB2scRGB],\n\t[RGB16, RGB16, image_set_type RGB16],\n\t[RGB16, GREY16, im_RGB162GREY16],\n\t[RGB16, LABS, im_LabQ2LabS @ im_Lab2LabQ @ im_sRGB2Lab],\n\n\t[GREY16, B_W, image_set_type B_W @ im_1628],\n\t[GREY16, RGB, im_mono2sRGB @ im_1628],\n\t[GREY16, sRGB, im_mono2sRGB @ im_1628],\n\t[GREY16, scRGB, im_sRGB2scRGB @ im_mono2sRGB],\n\t[GREY16, RGB16, im_GREY162RGB16],\n\t[GREY16, GREY16, image_set_type GREY16],\n\n\t[LABQ, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, XYZ, im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, YXY, im_XYZ2Yxy @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LAB, im_LabQ2Lab],\n\t[LABQ, LCH, im_Lab2LCh @ im_LabQ2Lab],\n\t[LABQ, UCS, im_Lab2UCS @ im_LabQ2Lab],\n\t[LABQ, RGB, im_LabQ2disp],\n\t[LABQ, sRGB, im_Lab2sRGB @ im_LabQ2Lab],\n\t[LABQ, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_LabQ2Lab],\n\t[LABQ, LABQ, image_set_type LABQ],\n\t[LABQ, LABS, im_LabQ2LabS],\n\n\t[LABS, B_W, im_sRGB2mono @ im_Lab2sRGB @ im_LabQ2Lab @ \n\t\tim_LabS2LabQ @ im_clip2s],\n\t[LABS, XYZ, im_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, YXY, im_XYZ2Yxy @ \n\t\tim_Lab2XYZ @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, LAB, im_LabS2Lab],\n\t[LABS, LCH, im_Lab2LCh @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, UCS, im_Lab2UCS @ im_LabQ2Lab @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, RGB, im_LabQ2disp @ im_LabS2LabQ @ im_clip2s],\n\t[LABS, sRGB, im_XYZ2sRGB @ im_Lab2XYZ @ im_LabS2Lab @ im_clip2s],\n\t[LABS, scRGB, im_XYZ2scRGB @ im_Lab2XYZ @ im_LabS2Lab @ im_clip2s],\n\t[LABS, LABQ, im_LabS2LabQ @ im_clip2s],\n\t[LABS, LABS, image_set_type LABS]\n]\n{\n\t/* From Image_type ... repeat here for brevity. Use same ordering as\n\t * in Colour menu for consistency.\n\t */\n\tB_W = 1;\n\tXYZ = 12;\n\tYXY = 23;\n\tLAB = 13;\n\tLCH = 19;\n\tUCS = 18;\n\tRGB = 17;\n\tsRGB = 22;\n\tscRGB = 28;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tLABQ = 16;\n\tLABS = 21;\n}\n\n/* Transform between two colour spaces.\n */\ncolour_transform from to in\n\t= colour_unary _colour_conversion_table?i?2 in, i >= 0\n\t= error (_ \"unable to convert \" ++ Image_type.type_names.get_name from ++ \n\t\t_ \" to \" ++ Image_type.type_names.get_name to)\n{\n\tmatch x = x?0 == from && x?1 == to;\n\ti = index match _colour_conversion_table;\n}\n\n/* Transform to a colour space, assuming the type field in the input is\n * correct \n */\ncolour_transform_to to in = colour_transform (get_type in) to in;\n\n/* String for path separator on this platform.\n */\npath_separator = expand \"$SEP\";\n\n/* Form a relative pathname. \n * \tpath_relative [\"home\", \"john\"] == \"home/john\"\n * \tpath_relative [] == \"\"\n */\npath_relative l = join_sep path_separator l;\n\n/* Form an absolute pathname. \n * \tpath_absolute [\"home\", \"john\"] == \"/home/john\"\n * \tpath_absolute [] == \"/\"\n * If the first component looks like 'A:', don't add an initial separator.\n */\npath_absolute l\n\t= path_relative l,\n\t\tlen l?0 > 1 && is_letter l?0?0 && l?0?1 == ':'\n\t= path_separator ++ path_relative l;\n\n/* Parse a pathname.\n *\tpath_parse \"/home/john\" == [\"home\", \"john\"]\n *\tpath_parse \"home/john\" == [\"home\", \"john\"]\n */\npath_parse str\n\t= split (equal path_separator?0) str;\n\n/* Return $PATH, reformatted as [[\"comp1\", \"comp2\"], [\"comp1\", \"comp2\"] ..]\n */\nsystem_search_path\n\t= [vipsbin] ++\n\t\tmap path_parse (split (equal path_sep) (expand \"$PATH\"))\n{\n\t/* On some platforms we ship vips with a few extra progs. Search\n \t * $VIPSHOME/bin first.\n\t */\n\tvipsbin = path_parse (expand \"$VIPSHOME\") ++ [\"bin\"];\n\n\tpath_sep\n\t\t= ':', expand \"$SEP\" == \"/\"\n\t\t= ';';\n}\n\n/* Search $PATH for the first occurence of name, or \"\". \n */\nsearch_for name\n\t= hits?0, hits != []\n\t= \"\"\n{\n\texe_name = name ++ expand \"$EXEEXT\";\n\tform_path p = path_absolute (p ++ [exe_name]);\n\tpaths = map form_path system_search_path;\n\thits = dropwhile (equal []) (map search paths);\n}\n\n/* Search $PATH for the first occurence of name, error on failure. \n */\nsearch_for_error name\n\t= path, path != \"\"\n\t= error (exe_name ++ \" not found on your search path. \" ++\n\t\t\"Check you have installed the program and it is on your PATH.\")\n{\n\texe_name = name ++ expand \"$EXEEXT\";\n\tpath = search_for name;\n}\n\n"
  },
  {
    "path": "share/nip2/start/_generate.def",
    "content": "\n/* make an image of size x by y whose pixels are their coordinates.\n */\nmake_xy x y = im_make_xy (to_real x) (to_real y);\n\n/* make an image with the specified properties ... pixel is (eg.) \n * Vector [0, 0, 0], or 12. If coding == labq, we ignore bands, format and\n * type, generate a 3 band float image, and lab2labq it before handing it\n * back.\n */\nimage_new w h b fmt coding type pixel xoff yoff\n\t= embed 1 0 0 w h im''''\n{\n\tb'\n\t\t= 3, coding == Image_coding.LABPACK\n\t\t= b;\n\tfmt'\n\t\t= Image_format.FLOAT, coding == Image_coding.LABPACK\n\t\t= fmt;\n\ttype'\n\t\t= Image_type.LAB, coding == Image_coding.LABPACK\n\t\t= type;\n\n\tim = im_black 1 1 (to_real b') + pixel;\n\n\tim' = clip2fmt fmt' im;\n\n\tim'' \n\t\t= im_Lab2LabQ im', coding == Image_coding.LABPACK;\n\t\t= im';\n\n\tim''' = image_set_type type' im'';\n\tim'''' = image_set_origin xoff yoff im''';\n}\n\nmkim options x y b\n    = Image (image_new x y b\n        (opt $format) (opt $coding) (opt $type)\n        (opt $pixel)\n        (opt $xoffset) (opt $yoffset))\n{\n    opt = get_option options [\n        $format => Image_format.UCHAR,\n        $coding => Image_coding.NOCODING,\n        $type => Image_type.sRGB,\n        $pixel => 0,\n        $xoffset => 0,\n        $yoffset => 0\n    ];\n}\n\n/* generate a slice of LAB space size x size pixels for L* == l\n */\nlab_slice size l \n\t= image_set_type Image_type.LAB im\n{\n    L = image_new size size 1\n\t\tImage_format.FLOAT Image_coding.NOCODING Image_type.B_W l 0 0;\n\tA1 = im_fgrey (to_real size) (to_real size);\n\n\t/* im_fgrey always makes 0-1, so these ranges can be wired in.\n\t */\n\tA2 = A1 * 256 - 128;\n\n\tA4 = im_rot90 A2;\n\tim = image_set_origin (size / 2) (size / 2) (L ++ A2 ++ A4);\n}\n\n/* Look at Image, try to make a Colour (failing that, a Vector) which is white\n * for that image type.\n */\nimage_white im\n\t= colour_transform_to type white_lab,\n\t\tbands == 3 && coding == Image_coding.NOCODING &&\n\t\tcolour_spaces.present 1 type\n\t= white_lab,\n\t\tcoding == Image_coding.LABPACK\n\t= Vector (replicate bands (max_value.lookup 1 0 format))\n{\n\tbands = im.bands;\n\ttype = im.type;\n\tformat = im.format;\n\tcoding = im.coding;\n\tcolour_spaces = Image_type.colour_spaces;\n\n\t// white as LAB\n\twhite_lab = Colour \"Lab\" [100, 0, 0];\n\n\t// maximum value for this numeric type\n\tmax_value = Table [\n\t\t[255, Image_format.DPCOMPLEX],\n\t\t[255, Image_format.DOUBLE],\n\t\t[255, Image_format.COMPLEX],\n\t\t[255, Image_format.FLOAT],\n\t\t[2 ** 31 - 1, Image_format.INT],\n\t\t[2 ** 32 - 1, Image_format.UINT],\n\t\t[2 ** 15 - 1, Image_format.SHORT],\n\t\t[2 ** 16 - 1, Image_format.USHORT],\n\t\t[2 ** 7 - 1, Image_format.CHAR],\n\t\t[2 ** 8 - 1, Image_format.UCHAR]\n\t];\n}\n\n/* Make a seperable gaussian mask.\n */\nmatrix_gaussian_blur radius\n        = im_gauss_imask_sep (radius / 3) 0.2;\n\n/* Make a seperable square mask.\n */\nmatrix_blur radius\n        = Matrix_con (sum mask_sq_line) 0 [mask_sq_line]\n{\n        mask_sq_line = replicate (2 * radius - 1) 1; \n}\n\n/* Make a colour from a temperature.\n */\ncolour_from_temp T\n\t= error (_ \"T out of range\"), T < 1667 || T > 25000\n\t= Colour \"Yxy\" [50, x, y]\n{\n\t// Kim et all approximation\n\t// see eg. http://en.wikipedia.org/wiki/Planckian_locus#Approximation\n\tx\n\t\t= -0.2661239 * 10 ** 9 / T ** 3 - 0.2343580 * 10 ** 6 / T ** 2 +\n\t\t\t0.8776956 * 10 ** 3 / T + 0.179910, T < 4000\n\t\t= -3.0258469 * 10 ** 9 / T ** 3 + 2.1070379 * 10 ** 6 / T ** 2 +\n\t\t\t0.2226347 * 10 ** 3 / T + 0.240390;\n\n\ty \n\t\t= -1.1063814 * x ** 3 - 1.34811020 * x ** 2 + \n\t\t\t2.18555832 * x - 0.20219638, T < 2222\n\t\t= -0.9549476 * x ** 3 - 1.37418593 * x ** 2 + \n\t\t\t2.09137015 * x - 0.16748867, T < 4000\n\t\t=  3.0817580 * x ** 3 - 5.87338670 * x ** 2 +\n\t\t\t3.75112997 * x - 0.37001483;\n}\n\ntemp_from_colour z\n\t= T\n{\n\tc = colour_transform_to Image_type.YXY (to_colour z);\n\tx = c.value?1;\n\ty = c.value?2;\n\n\t// McCamy's approximation, see eg. \n\t// http://en.wikipedia.org/wiki/Color_temperature#Approximation\n\n\txe = 0.332;\n\tye = 0.1858;\n\tn = (x - xe) / (y - ye);\n\tT = -449 * n ** 3 + 3525 * n ** 2 - 6823.3 * n + 5520.33;\n}\n\n"
  },
  {
    "path": "share/nip2/start/_joe_extra.def",
    "content": "////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nFrame_item = class\n\tMenupullright \"Picture _Frame\" \"working with images of frames\"\n\t{\n\t////////////////////////////////////////////////////////////////////////////////////\n\tBuild_frame_item = class\n\tMenupullright \"_Build Frame From\" \"builds a new frame from image a and places it around image b\"\n\t\t{\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tFrame_corner_item = class\n\t\t\tMenuaction \"_Frame Corner\" \n\t\t\t\"copies and extends a frame corner, a, to produce a complete frame to fit round a given image, b\" \n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = corner_frame _a _im_w _im_h _ov _cs _ms _bf;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tSimple_frame_item = class\n\t\t\tMenuaction \"_Simple Frame\" \n\t\t\t\t\"extends or shortens the central sections of a simple frame, a,  to fit round a given image, b\"\n\t\t\t{\n\t\t\tprefs = Workspaces.Preferences;\n\n\t\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 0;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t//Scale frame image if required.\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.mount_colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = simple_frame _a _im_w _im_h _ov _cs _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t////////////////////////////////////////////////////////////////////////////////////\n\t\tComplex_frame_item = class\n\t\t\tMenuaction \"_Complex Frame\" \n\t\t\t\"extends or shortens the central sections of a frame a, preserving any central edge details, to fit image b\" {\n\t\tprefs = Workspaces.Preferences;\n\n\t\taction a b = class\n\t\t\t_result\n\t\t\t{\n\t\t\t_check_args = [\n\t\t\t\t[a, \"a\", check_Image],\n\t\t\t\t[b, \"b\", check_Image]\n\t\t\t\t];\n\t\t\t_check_all = [\n\t\t\t\t[a.coding == b.coding && a.bands == b.bands,\n\t\t\t\t\t\"a.coding == b.coding && a.bands == b.bands\"]\n\t\t\t\t];\n\t\t\t_vislevel = 3;\n\n\t\t\tppcm = Expression \"Number of pixels per cm\" 25;\n\n\t\t\t/* Given the value of ppcm, distance between the inner edge of the frame\n\t\t\t * and the outer edge of the image.  +ve values mean the frame overlaps\n\t\t\t * the image.\n\t\t\t */\n\t\t\toverlap = Expression \"Size of frame overlap in cm\" 0;\n\t\t\tvariables = Frame_variables 1;\n\n\t\t\t_type = Image_type.colour_spaces.get_name b.type;\n\n\t\t\t//If applied the count colour be seen for -ve values of overlap\n\t\t\tmount_options = Mount_options _type ppcm.expr;\n\n\t\t\t_cs = variables.corner_section.value;\n\t\t\t_es = variables.edge_section.value;\n\t\t\t_ms = variables.middle_section.value;\n\t\t\t_ov = ppcm.expr * overlap.expr;\n\t\t\t_sf = variables.scale_factor.expr;\n\t\t\t_bf = variables.blend_fraction.value;\n\n\t\t\t_a = a, _sf == 1;\n\t\t\t   = a, _sf == 0;\n\t\t\t   = Image (resize Kernel_linear _sf _sf a.value);\n\n\t\t\t_im_w = b.width;\n\t\t\t_im_h = b.height + mount_options._los, mount_options.apply\n\t\t\t\t  = b.height;\n\t\t\t_os = mount_options._los, mount_options.apply\n\t\t\t\t= 0;\n\t\t\t_cl = Vector mount_options.colour.value, mount_options.apply\n\t\t\t\t= 0;\n\n\n\t\t\t//Produce scaled and resized frame.\n\t\t\tframe = complex_frame _a _im_w _im_h _ov _cs _es _ms _bf variables.option;\n\t\t\t//Resize image canvas and applied mount colour as required.\n\t\t\t_pos_im = frame_position_image b frame _os _cl;\n\t\t\t//Wrap frame round image.\n\t\t\t_result = if (frame == 0) then _pos_im else frame;\n\t\t\t}\n\t\t}\n\t}\t\n////////////////////////////////////////////////////////////////////////////////////\t\n\tStraighten_frame_item = class\n\t\tMenuaction \"_Straighten Frame\" \"uses four points to square up distorted images of frames\" {\n\t\taction a = Perspective_item.action a;\n\t\t}\n};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nSelect_item = class\n\tMenupullright \"_Select\"\n\t\t\"select user defined areas of an image\" {\n\tprefs = Workspaces.Preferences;\n\n\t/* Option toggle used to define whether the user is replacing a\n\t * dark or a light area.\n\t */\n\t_control = Option \"Make\" [\n\t\t\"Selection Brighter\",\n\t \t\"Selection Darker\",\n\t \t\"Selection Black\",\n\t \t\"Selection White\",\n\t \t\"Background Black\",\n\t \t\"Background White\",\n\t\t\"Mask\" \n\t] 4;\n\n\tcontrol_selection mask im no\n\t\t= [\n\t\t\tif mask then im * 1.2 else im * 1,\n\t\t\tif mask then im * 0.8 else im * 1,\n\t\t\tif mask then 0 else im,\n\t\t\tif mask then 255 else im,\n\t\t\tif mask then im else 0,\n\t\t\tif mask then im else 255,\n\t\t\tmask\n\t\t]?no;\n\n\tRectangle = class\n        Menuaction \"_Rectangle\"\n            \"use an Arrow or Region x to define a rectangle\"\n        {\n        action x = class\n            _result {\n            _vislevel = 3;\n\n            control = _control;   \n\n            _result = control_selection mask im control\n                  {\n                \tim = x.image;\n                \tmask = Image m\n                    {\n\t\t\t\t\t\trx     \n\t\t\t\t\t\t\t= x.region_rect, is_Region x\n\t\t\t\t\t\t\t= x;\n\t\t\t\t\t\tb     = image_new im.width im.height 1 0 0 1 0 0 0;\n\t\t\t\t\t\tw     = image_new rx.nwidth rx.nheight 1 0 0 1 255 0 0;\n\t\t\t\t\t\tm     = insert_noexpand rx.nleft rx.ntop w b; \n                     }\n                   }\n            }\n        }\n\n\tElipse = class\n\t\tMenuaction \"_Ellipse\"\n\t\t\t\"use a line/arrow x to define the center point radius and direction of an ellipse\"\n\t\t{\n\t\taction x = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\t\t\twidth = Scale \"Width\" 0.01 1 0.5;\n\n\t\t\t_result = control_selection mask im control\n  \t\t\t\t{\n\t\t\t\tmask = select_ellipse x width.value;\n\t\t\t\tim = x.image;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tTetragon = class\n\t\tMenuaction \"_Tetragon\"\n\t\t\t\"selects the convex area defined by four points\"\n\t\t{\n\t\taction a b c d = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_tetragon a b c d;\n\t\t\t\tim = get_image a;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\tPolygon = class\n\t\tMenuaction \"_Polygon\"\n\t\t\t\"selects a polygon from an ordered group of points\"\n\t\t{\n\t\taction pt_list = class\n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tcontrol = _control;\n\n\t\t\t_result = control_selection mask im control\n\t\t\t\t{\n\t\t\t\tmask = select_polygon pt_list;\n\t\t\t\tim = get_image ((pt_list.value)?0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tsep1 = Menuseparator;\n\n\tThreshold_item = class \n\t\tMenuaction \"Thres_hold\" \"simple image threshold\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt \n\t\t\t\t= Scale \"Threshold\" 0 mx (mx / 2)\n\t\t\t{\n\t\t\t\tmx \n\t\t\t\t\t= Image_format.maxval x.format, is_Image x\n\t\t\t\t\t= 255;\n\t\t\t}\n\n\t\t\t_result = map_unary (more t.value) x;\n\t\t}\n\t}\n\n\tThreshold_percent_item = class \n\t\tMenuaction \"Per_cent Threshold\" \"threshold at a percentage of pixels\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tt = Scale \"Percentage of pixels\" 0 100 50;\n\n\t\t\t_result \n\t\t\t\t= map_unary (more (hist_thresh (t.value / 100) x)) x;\n\t\t}\n\t}\n\n\tsep2 = Menuseparator;\n\n\tSegment_item = class\n\t\tMenuaction \"_Segment\" \"break image into disjoint regions\" {\n\t\taction x = class \n\t\t\t_result {\n\t\t\t_vislevel = 3;\n\n\t\t\tsegments\n\t\t\t\t= Expression \"Number of disjoint regions\" \n\t\t\t\t\t(map_unary (get_header \"n-segments\") _result);\n\n\t\t\t_result = map_unary segment x;\n\t\t}\n\t}\n\n\tFill_item = class\n\t\tMenuaction \"_Fill\" \"fill zero pixels with the nearest non-zero\" {\n\t\taction x = class \n\t\t\tImage _result {\n\t\t\t_vislevel = 3;\n\n\t\t\tdistance = Image _distance;\n\n\t\t\t[_result, _distance] = vips_call \"fill_nearest\" [x.value] [\n\t\t\t\t\"distance\" => true\n\t\t\t];\n\t\t}\n\t}\n\nfill_nearest x \n\t= oo_unary_function nearest_op x, is_class x\n\t= near x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fill_nearest\")\n{\n\tnearest_op = Operator \"fill_nearest\" \n\t\tfill_nearest Operator_type.COMPOUND_REWRAP false;\n\n\tnear x\n\t\t= [out, distance]\n\t{\n\t\t[out, distance] = vips_call \"fill_nearest\" [x] [\n\t\t\t\"distance\" => true\n\t\t];\n\t}\n}\n\n\n\n\n\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\n\nPerspective_match_item = class\n\tMenuaction \"_Perspective Match\" \n\t\t\"rotate, scale and skew one image to match another\" {\n\taction x y = class\n\t\t_result {\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\t\t_b = find_image y;\n\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.1 0.9;\n\t\tap4 = Mark_relative _a 0.9 0.9;\n\t\t\t\n\t\tbp1 = Mark_relative _b 0.1 0.1;\n\t\tbp2 = Mark_relative _b 0.9 0.1;\n\t\tbp3 = Mark_relative _b 0.1 0.9;\n\t\tbp4 = Mark_relative _b 0.9 0.9;\n\n\t\t_result = map_binary process x y\n\t\t\t{\n\t\t\tf1 = _a.width / _b.width;\n\t\t\tf2 = _a.height / _b.height;\n\n\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\tpl = sort_pts_clockwise [bp1, bp2, bp3, bp4];\n\n\t\t\tto = [\n\t\t\t\trl?0.left, rl?0.top, \n\t\t\t\trl?1.left, rl?1.top,\n\t\t\t\trl?2.left, rl?2.top, \n\t\t\t\trl?3.left, rl?3.top\n\t\t\t];\n\n\t\t\tfrom = [\n\t\t\t\tpl?0.left * f1, pl?0.top * f2, \n\t\t\t\tpl?1.left * f1, pl?1.top * f2,\n\t\t\t\tpl?2.left * f1, pl?2.top * f2, \n\t\t\t\tpl?3.left * f1, pl?3.top * f2\n\t\t\t];\n\t\t\t\n\t\t\ttrans = perspective_transform to from;\n\t\t\t\n\t\t\tprocess a b = transform 1 0 trans b2\n\t\t\t\t{\n\t\t\t\tb2 = resize Kernel_linear f1 f2 b, (f1 >= 1 && f2 >= 1) || (f1 >= 1 && f2 >= 1)\n\t\t\t    \t= resize Kernel_linear f1 1 b1\n\t\t\t\t\t{b1 = resize Kernel_linear 1 f2 b;}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////\nPerspective_item = class\n\tMenuaction \"Pe_rspective Distort\"\n\t\t\"rotate, scale and skew an image with respect to defined points\" {\n\taction x = class\n\t\t_result\t{\n\t\t_vislevel = 3;\n\n\t\t// try to find an image ... for a group, get the first item\n\t\tfind_image x\n\t\t\t= x, is_Image x\n\t\t\t= find_image x?0, is_list x\n\t\t\t= find_image x.value, is_class x && has_value x\n\t\t\t= error \"unable to find image\";\n\n\t\t_a = find_image x;\n\n\t\tdir = Option \"Select distort direction\" [ \"Distort to points\", \"Distort to corners\" ] 1;\n\t\tap1 = Mark_relative _a 0.1 0.1;\n\t\tap2 = Mark_relative _a 0.9 0.1;\n\t\tap3 = Mark_relative _a 0.9 0.9;\n\t\tap4 = Mark_relative _a 0.1 0.9;\n\t\t\n\t\t_result = map_unary process x\n\t\t\t{\t\t\t\n\t\t\ttrans = [perspective_transform to from, perspective_transform from to]?(dir.value)\n\t\t\t\t{\n\t\t\t\trl = sort_pts_clockwise [ap1, ap2, ap3, ap4];\n\t\t\t\tto = [(rl?0).left, (rl?0).top, (rl?1).left, (rl?1).top,\n\t\t\t    \t  (rl?2).left, (rl?2).top, (rl?3).left, (rl?3).top];\n\t\t\t\tfrom=[0, 0, (_a.width - 1), 0, \n\t\t\t\t\t  (_a.width - 1), (_a.height - 1), 0, (_a.height - 1)];\n\t\t\t\t}\n\n\t\t\tprocess a = transform 1 0 trans a;\n\t\t\t}\n\t\t}\n\t};\n\n"
  },
  {
    "path": "share/nip2/start/_joe_utilities.def",
    "content": "/*  ******Functions included in start/_NG_utilities.def:******\n *\n *  so_balance ref_meanmax im1 im2 mask blur gauss *\n *  nonzero_mean im = no_out *\n *  so_meanmax im = result *\n *  so_calculate ref_meanmax im mask = result *\n *  simple_frame frame im_w im_h ov cs ms bf option = result *\n *  corner_frame frame im_w im_h ov cs ms bf = result *\n *  build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result *\n *  complex_frame frame im_w im_h ov cs es ms bf option= result *\n *  complex_edge ra rb t bl d = rc *\n *  frame_lr_min r_l r_r target bw = result *\n *  frame_tb_min r_t r_b target bw = result *\n *  frame_position_image im ref os colour= result *\n *  merge_array bw arr = result *\n *  merge_to_scale im target blend dir = result *\n *  select_ellipse line width = mask *\n *  select_tetragon p1 p2 p3 p4 = mask *\n *  select_polygon pt_list = mask *\n *  perspective_transform to from = trans'' *\n *  sort_pts_clockwise l = l'' *\n */\n\n/* Called from:\n* _NG_Extra.def Clone_area_item\n*/\nso_balance ref_meanmax im1 im2 mask gauss\n   = result\n   {\n   //ref_meanmax = so_meanmax im1;\n   so_values = so_calculate ref_meanmax im2 mask;\n   im2_cor_a = clip2fmt im2.format im2'', has_member \"format\" im2\n             = im2''\n           {im2'' = im2 * (so_values?0) + (so_values?1);}\n         // Option to convert replacement image to scaled gaussian noise\n         im2_cor = im2_cor_a, gauss == false\n           = clip2fmt im2_cor_a.format gauss_im\n       {gauss_im =\n           gaussnoise im2_cor_a.width im2_cor_a.height ref_meanmax?0\n(deviation im2_cor_a);}\n                           result = im_blend (get_image mask) (get_image\nim2_cor) (get_image im1);\n   };\n\n////////////////////////////////////////////////////////////////////////////////\t\n/* Calculates the mean of the non zero pixels.\n * \n * Called from:\n * _NG_utilities so_meanmax\n */\nnonzero_mean im = no_out\n\t{\n\tzero_im = (im == 0);\n\tzero_mean = mean zero_im;              \n\tno_mean = mean im;\n\tno_out = no_mean/(1 - (zero_mean/255));\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the max and nonzero mean of an image\n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_utilities so_calculate\n * _NG_Extra.def Clone_area_item\n * _NG_Extra.def Balance_item.Balance_find_item\n */\nso_meanmax im = result\n\t{\n\tmean_of_im = nonzero_mean im;\n\tadjusted_im = im - mean_of_im;\n\tmax_of_im = max adjusted_im;\n\t\t\n\tresult = [mean_of_im, max_of_im];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Calculates the scale and offset required to match a reference mean and max \n * \n * Called from:\n * _NG_utilities so_balance\n * _NG_Extra.def Balance_item.Balance_find_item\n */\t\nso_calculate ref_meanmax im mask = result\n\t{\n\tim' = if mask then im else 0;\n\tim_values = so_meanmax im';\n\n\tmean_of_ref = ref_meanmax?0; \n\tmean_of_im  = im_values?0;\n\t\t\n\tmax_of_ref = ref_meanmax?1; \n\tmax_of_im  = im_values?1;\n\t\t\n\tscale = (max_of_ref)/(max_of_im);\n\toffset = mean_of_ref - (mean_of_im * scale);\n\tresult = [ scale, offset ];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a simple frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Simple_frame_item\n */\nsimple_frame frame im_w im_h ov cs ms bf option = result\n\t\t{\n\t\tcs' = (1 - cs);\n\t\tms' = (0.5 - (ms/2));\n\t\tms'' = (1 - cs);\n\n\t\t//Regions\n\t\tr_tl = Region_relative frame 0 0 cs cs;\n\t\tr_tr = fliplr r_tl, option == true\n\t\t\t  = Region_relative frame cs' 0 cs cs;\n\t\tr_bl = Region_relative frame 0 cs' cs cs;\n\t\tr_br = fliplr r_bl, option == true\n\t\t       = Region_relative frame cs' cs' cs cs;\n\n\t\tr_mt = Region_relative frame ms' 0 ms cs;\n\t\tr_mb = Region_relative frame ms' ms'' ms cs;\n\t\tr_ml = Region_relative frame 0 ms' cs ms;\n\t\tr_mr = fliplr r_ml, option == true\n\t\t       = Region_relative frame ms'' ms' cs ms;\n\n\t\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Copies and extends a simple frame corner to produce a complete frame to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n */\ncorner_frame frame im_w im_h ov cs ms bf = result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\n\t//Regions\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl;\n\tr_bl = fliptb r_tl;\n\tr_br = fliplr r_bl;\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = fliptb r_mt;\n\tr_ml = Region_relative frame 0 ms' cs ms;;\n\tr_mr = fliplr r_ml;\n\tresult = build_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf;\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Completes the frame building process for simple_frame and corner_frame.\n *\n * _NG_utilities simple_frame\n * _NG_utilities corner_frame\n */\nbuild_frame r_tl r_tr r_bl r_br r_mt r_mb r_ml r_mr im_w im_h ov bf = result\n\t{\n\t//Find pixel thickness of frames section\n\ts_width = r_ml.width - mean (im_profile (map_unary fliplr (r_ml.value)?0) 1);\n\ts_height = r_mt.height - mean (im_profile (map_unary fliptb (r_mt.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\n\tblend = bf * r_tl.width;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend), w_target > (2 * r_tl.width)\n\t\t\t  = w_target;\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend), h_target > (2 * r_tl.height)\n\t\t\t  = h_target;\n\n\t//Use regions to produce sections\n\ttop \t= merge_to_scale r_mt cw_target blend 0;\n\tbottom \t= merge_to_scale r_mb cw_target blend 0;\n\tleft \t= merge_to_scale r_ml ch_target blend 1;\n\tright \t= merge_to_scale r_mr ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new cw_target ch_target left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build sections into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t \t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\n/* Extends or shortens the central sections of a frame, preserving any central details on each\n * edge, to fit round a given image.\n * \n * Called from:\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\ncomplex_frame frame im_w im_h ov cs es ms bf option= result\n\t{\n\tcs' = (1 - cs);\n\tms' = (0.5 - (ms/2));\n\tes' = (0.25 - (es/2));\n\n\tr_tl = Region_relative frame 0 0 cs cs;\n\tr_tr = fliplr r_tl, option == true\n\t   \t = Region_relative frame cs' 0 cs cs;\n\tr_bl = Region_relative frame 0 cs' cs cs;\n\tr_br = fliplr r_bl, option == true\n\t\t = Region_relative frame cs' cs' cs cs;\n\n\tr_mt = Region_relative frame ms' 0 ms cs;\n\tr_mb = Region_relative frame ms' cs' ms cs;\n\tr_ml = Region_relative frame 0 ms' cs ms;\n\tr_mr = fliplr r_ml, option == true\n\t     = Region_relative frame cs' ms' cs ms;\n\n\tr_et = Region_relative frame es' 0 es cs;\n\tr_eb = Region_relative frame es' cs' es cs;\n\tr_el = Region_relative frame 0 es' cs es;\n\tr_er = fliplr r_el, option == true\n\t     = Region_relative frame cs' es' cs es;\n\n\t//Find pixel thickness of frames section\n\ts_width = r_el.width - mean (im_profile (map_unary fliplr (r_el.value)?0) 1);\n\ts_height = r_et.height - mean (im_profile (map_unary fliptb (r_et.value)?0) 0);\n\n\tw_target = im_w + (2 * (s_width - ov));\n\th_target = im_h + (2 * (s_height - ov));\n\tmin_size = foldr1 min_pair [r_tl.width, r_tl.height,\n\t\t\t\t\t\t\t\tr_mt.width, r_mt.height,\n\t\t\t\t\t\t\t\tr_et.width, r_et.height];\n\tblend = bf * min_size;\n\n\tcw_target = w_target - (2 * r_tl.width) + (2 * blend);\n\tch_target = h_target - (2 * r_tl.height) + (2 * blend);\n\n\ttop \t= complex_edge r_mt r_et cw_target blend 0;\n\tbottom \t= complex_edge r_mb r_eb cw_target blend 0;\n\tleft\t= complex_edge r_ml r_el ch_target blend 1;\n\tright\t= complex_edge r_mr r_er ch_target blend 1;\n\tmiddle  = Image \n\t\t(image_new top.width left.height left.bands left.format left.coding left.type 0 0 0);\n\n\t//Build regions into full frame.\n\trow_1 = frame_lr_min r_tl r_tr w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_tl, top, r_tr]];\n\trow_2 = frame_lr_min left right w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[left, middle, right]];\n\trow_3 = frame_lr_min r_bl r_br w_target blend, ( w_target < (r_tl.width * 2))\n\t\t  = merge_array blend [[r_bl, bottom, r_br]];\n\tresult = frame_tb_min row_1 row_3 h_target blend, (h_target < (r_tl.height * 2))\n\t\t   = merge_array blend [[row_1], [row_2], [row_3]];\n\t};\n\n////////////////////////////////////////////////////////////////////////////////\t\n/*  Function called by complex frame, used to produce section\n * \n * Called from:\n * _NG_utilities.def complex_frame\n */\ncomplex_edge ra rb t bl d = rc\n\t{\n\te1 = ceil (ra.width - t)/2, d == 0\n\t   = 0;\n\te2 = 0, d == 0\n\t   = ceil (ra.height - t)/2;\n\te3 = t, d == 0\n       = ra.width;\n\te4 = ra.height, d == 0\n\t   = t;\n\t\n\tcheck = ra.width, d == 0;\n    \t  = ra.height;\n\t\t\n\trai = get_image ra;\n\n\tt2 = (t - ra.width + (2 * bl))/2, d == 0\n\t   = (t - ra.height + (2 * bl))/2;\n\n\trc = ra , t <= 0\n\t   = Image (im_extract_area rai e1 e2 e3 e4), t <= check\n\t   = merge_array bl [[rb',ra,rb']], d == 0\n\t   = merge_array bl [[rb'],[ra],[rb']]\n\t   \t{rb' = merge_to_scale rb t2 bl d;}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images left/right to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_lr_min r_l r_r target bw = result\n\t{\n\t//Calculating the new widh required for each image.\n\tno = (target/2 + bw);\n\tn_w = no, (r_l.width > no)\n\t\t= r_l.width;\n\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_l = im_extract_area r_l.value 0 0 n_w r_l.height;\n\tn_r = im_extract_area r_r.value (r_r.width - n_w) 0 n_w r_l.height;\n\n\t//Merge the two image together with a bw*2 pixel overlap.\n\tresult = Image (im_lrmerge n_l n_r ((bw*2) - n_w) 0 bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Blends two images top/bottom to produce an image a specific width.\n *\n * _NG_utilities build_frame\n * _NG_utilities complex_frame\n */\nframe_tb_min r_t r_b target bw = result\n\t{\n\t//Calculating the new height required for each image.\n\tno = (target/2 + bw);\n\tn_h = no, (r_t.height > no)\n\t\t= r_t.height;\n\t\t\n\t//Removing excess from what will be the middle of the final image.\n\tn_t = im_extract_area r_t.value 0 0 r_t.width n_h;\n\tn_b = im_extract_area r_b.value 0 (r_b.height - n_h) r_b.width n_h;\n\n\t//Merge the two image together with a 50 pixel overlap.\n\tresult = Image (im_tbmerge n_t n_b 0 ((bw*2) -n_h) bw);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Resixe canvas of an image to accomodate a frame and possible mount \n *\n * Called from:\n * _NG_Extra.def Frame_item.Frame_corner_item\n * _NG_Extra.def Frame_item.Simple_frame_item\n * _NG_Extra.def Frame_item.Complex_frame_item\n */\nframe_position_image im ref os colour= result\n\t{\n\tbackground = image_new ref.width ref.height\n\t\t\t\t\tim.bands im.format im.coding im.type colour 0 0;\n\n\tresult = insert_noexpand xp yp im background\n\t\t{\n\t\txp = (ref.width - im.width)/2;\n\t\typ = (ref.height - im.height - os)/2;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Merges an array of images together according to blend width bw \n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_frame\n * _NG_Utilites.def complex_edge\n */\t\nmerge_array bw arr = result\n\t{\n\tmerge_lr bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Xsize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_lrmerge (get_image im1) (get_image im2) bw'' 0 bw;\n\t\t}\n\tmerge_tb bw im1 im2 = im3\n\t\t{\n\t\tbw' = get_header \"Ysize\" (get_image im1);\n\t\tbw'' = -(bw' - bw);\n\t\tim3 = im_tbmerge (get_image im1) (get_image im2) 0 bw'' bw;\n\t\t}\n\n\tim_out \t= (image_set_origin 0 0 @ \n\t\t\tfoldl1 (merge_tb bw) @\n\t\t\tmap (foldl1 (merge_lr bw))) arr;\n\tresult = Image im_out;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Repeatably top/bottom add clones of im, with a defined overlap, until final height > target\n *\n * Called from:\n * _NG_Utilites.def build_frame\n * _NG_Utilites.def complex_edge\n */\nmerge_to_scale im target blend dir = result\n\t{\n\tblend' = floor blend;\n\t\n\t//allow fir lr or tb process\n\tvar_a = im.width, dir == 0\n\t\t  = im.height;\n\t\n\tvar_w = im.width, dir == 1\n\t      = target, target > blend'\n\t\t  = blend';\n\tvar_h = im.height, dir == 0\n\t      = target, target > blend'\n\t\t  = blend';\n\n\t//total numner of copies of im requires, taking overlap into account.\n\tno_loops = ceil ((log ((target - blend')/(var_a - blend')))/(log 2));\n\t\n\tprocess im no = result\n\t\t{\n\t\tpr_a = get_header \"Xsize\" (get_image im), dir == 0\n\t    \t = get_header \"Ysize\" (get_image im);\n\t\tpr_b = -(pr_a - blend' + 1);\n\t\n\t\tim' = im_lrmerge (get_image im) (get_image im) pr_b 0 blend', dir == 0\n\t    \t= im_tbmerge (get_image im) (get_image im) 0 pr_b blend';\n\t\tno' = no - 1;\n\t\t\n\t\tresult = im', no' < 1\n\t\t       = process im' no';\n\t\t}\n\t\t\n\tim_tmp \t= im.value, var_a > target\n\t\t    = process im no_loops;\n\n\tresult = Image (im_extract_area (get_image im_tmp) 0 0 var_w var_h);\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects an elispe based on a line and a width\n *\n * Called from:\n * _NG_Extra.def Select_item.Elipse\n */  \nselect_ellipse line width = mask\n\t{\n\tim = Image (get_image line);\n\t\n\t//Make a 2 band image whose value equals its coordinates.\n\tim_coor = Image (make_xy im.width im.height);\t\n\n\t//Adjust the values to center tham on (line.left, line.top)\n\tim_cent = im_coor - Vector [line.left,line.top];\n\n\tw = line.width;\n\th = line.height;\n\t\t\n\tangle\t= 270, w == 0 && h < 0\n\t\t\t= 90, w == 0 && h >= 0\n\t\t\t= 360 + atan (h/w), w > 0 && h < 0\n\t \t\t= atan (h/w), w > 0 && h >= 0\n\t \t\t= 180 + atan (h/w);\n\n\ta = ( (h ** 2) + (w ** 2) )**0.5;\n\tb = a * width;\n\n\tx' = ( (cos angle) * im_cent?0) + ( (sin angle) * im_cent?1);\n\ty' = ( (cos angle) * im_cent?1) - ( (sin angle) * im_cent?0);\n\t\n\tmask =  ( (b**2) * (x'**2) ) +  ( (a**2) * (y'**2) ) <= (a * b)**2;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Tetragon\n * _NG_Extra.def Perspective_item\n */  \nselect_tetragon p1 p2 p3 p4 = mask\n\t{\n\t//Put points in clockwise order starting at the top left.\n\tpt_list = sort_pts_clockwise [p1, p2, p3, p4];\n\t\t\t\t\n\tpair_list = [\n    \t[ pt_list?0, pt_list?1 ],\n    \t[ pt_list?1, pt_list?2 ],\n    \t[ pt_list?2, pt_list?3 ],\n    \t[ pt_list?3, pt_list?0 ] ];\n\n\t//Make xy image the same size as p1.image;\n   \tim_xy = Image (make_xy p1.image.width p1.image.height);\n\twhite = Image (image_new p1.image.width p1.image.height 1 0 Image_coding.NOCODING 1 255 0 0);\n\t\n\tmask = foldl process white pair_list;\n\t\n\t/* Treat each pair of point as a vector going from p1 to p2,\n\t * then select all to right of line. This is done for each pair,\n\t * the results are all combined to select the area defined by\n\t * the four points.\n\t */\n\tprocess im_in pair = im_out\n\t\t{\n\t\tx = (pair?0).left;\n\t\ty = (pair?0).top;\n\t\tx'= (pair?1).left;\n\t\ty'= (pair?1).top;\n\n\t\tw = x' - x;\n\t\th = y' - y;\n\t\t\n\t\tm = 0, x == x'\n\t\t  = (y-y')/(x-x');\n\t\tc = 0, x == x'\n\t\t  = ((y*x') - (y'*x))/(x' - x);\n\n\t\tmask=  im_xy?1 - (im_xy?0 * m)  >= c, w > 0\n\t\t\t=  im_xy?1 - (im_xy?0 * m)  <= c, w < 0\n\t\t\t=  im_xy?0 <= x, w == 0 && h > 0\n\t\t\t=  im_xy?0 >= x;\n\t\n\t\tim_out = im_in & mask;\n\t\t}\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Select_item.Polygon\n */ \t\nselect_polygon pt_list = mask\n\t{\n\tgroup_check = is_Group pt_list;\n\tpt_l = pt_list.value, group_check\n\t\t = pt_list;\n\t\t\t \n\tim = Image (get_image (pt_l?0));\n\tim_xy = Image (make_xy im.width im.height);\n\tblack = Image (image_new im_xy.width im_xy.height 1 0 Image_coding.NOCODING 1 0 0 0);\n\n\tx = im_xy?0;\n\ty = im_xy?1;\n\n\tpt_l' = grp_trip pt_l;\n\t\n\tmask = foldl process black pt_l';\n\t\t\t\t\n\t/*Takes a group adds the first two the end and then creates a lists of \n\t *lists [[a, b, c], [b, c, d] .... [x, a, b]]\n \t */\n\tgrp_trip l = l''\n\t\t{\n\t\tpx = take 2 l;\n\t\tl' = join l px;\n\t\tstart = [(take 3 l')];\n\t\trest = drop 3 l';\n\n\t\tprocess a b = c\n\t\t\t{\n\t\t\tx = (last a)?1;\n\t\t\tx'= (last a)?2;\n\t\t\tx'' = [[x, x', b]];\n\t\t\tc = join a x'';\n\t\t\t}\n\t\t\t\t\n\t\tl'' = foldl process start rest;\n\t\t};\n\t\t\t\t\t\n\tprocess im_in triplet = im_out\n\t\t{\n\t\tp1 = triplet?0;\n\t\tp2 = triplet?1;\n\t\tp3 = triplet?2;\t\n\t\t\t\t\t\n\t\t//check for change in x direction between p1-p2 and p2 -p3\n\t\tdir_1 = sign (p2.left - p1.left);\n\t\tdir_2 = sign (p3.left - p2.left);\n\t\tdir = dir_1 + dir_2;\n\n\t\t//define min x limit.\n\t\tmin_x = p1.left, p1.left < p2.left\n\t\t\t  = p2.left + 1, dir != 0\n\t\t\t  = p2.left;\n\t\t\n\t\t//define max x limit.\n\t\tmax_x = p1.left, p1.left > p2.left\n\t       \t  = p2.left - 1, dir != 0\n\t\t\t  = p2.left; \n\n\t\t//equation of line defined by p1 and p2\n\t\tm = line_m p1 p2;\n\t\tc = line_c p1 p2;\n\t\t\n\t\t//Every thing below the line\n\t\tim_test = ((y >= (m * x) + c) & (x >= min_x) & (x <= max_x));\t\t\n\n\t\tim_out = im_in ^ im_test;\n\t\t}\n\t\t\n\tline_c p1 p2 = c\n\t\t{m = line_m p1 p2;\n\t\t c = p1.top - (m * p1.left);};\n\n\tline_m p1 p2 = (p2.top - p1.top)/(p2.left - p1.left), p2.left != p1.left\n\t    \t\t = 0;\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Selects a tetragon based on four points.\n *\n * Called from:\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nperspective_transform to from = trans''\n\t{\n\t/*\n\t *  Tramsformation matrix is calculated on the bases of the following functions:\n\t *\t\tx' = c0x + c1y + c2xy + c3\n\t *\t\ty' = c4x + c5y + c6xy + c7\n\t *\n\t *  The functions used in vips im_transform works based on the functions:\n\t *\t\tx = x' + b0 + b2x' + b4y' + b6x'y'\n\t *\t\ty = y' + b1 + b3x' + b5y' + b7x'y'\n\t *\n\t *  and is applied in the form of the matrix:\n\t *\n\t *  \t[[b0, b1],\n\t *   \t [b2, b3],\n\t *   \t [b4, b5],\n\t *   \t [b6, b7]]\n\t *\n\t * Therefore our required calculated matrix will be\n\t *\n\t *  \t[[ c3\t\t, c7],\n\t *   \t [(c0 - 1)\t, c4],\n\t *   \t [ c1\t\t, (c5 - 1)],\n\t *   \t [ c2\t\t, c6]]\n\t *\n\t * to = [x1, y1, x2, y2, x3, y3, x4, y4]\n\t * from = [x1', y1', x2', y2', x3', y3', x4', y4']\n\t * trans = [[c0], [c1], [c2], [c3], [c4], [c5], [c6], [c7]]\n\t *\n\t */\n\n\tto' = Matrix\n\t   [[to?0, to?1, ((to?0)*(to?1)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?0, to?1, ((to?0)*(to?1)), 1],\n\t\t[to?2, to?3, ((to?2)*(to?3)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?2, to?3, ((to?2)*(to?3)), 1],\n\t\t[to?4, to?5, ((to?4)*(to?5)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?4, to?5, ((to?4)*(to?5)), 1],\n\t\t[to?6, to?7, ((to?6)*(to?7)), 1, 0, 0, 0, 0],\n\t\t[0, 0, 0, 0, to?6, to?7, ((to?6)*(to?7)), 1]];\n\n\tfrom' = Matrix (transpose [from]);\n\n\tto'' = to' ** (-1);\n\n\ttrans = to'' * from';\n\ttrans' = trans.value;\n\ttrans''= Matrix [[(trans'?3)?0, \t  (trans'?7)?0\t\t],\n\t\t\t\t\t [((trans'?0)?0 - 1), (trans'?4)?0\t\t],\n\t\t\t\t\t [(trans'?1)?0, \t  ((trans'?5)?0 - 1)],\n\t\t\t\t\t [(trans'?2)?0, \t  (trans'?6)?0\t\t]];\n\t};\n\n//////////////////////////////////////////////////////////////////////////////\n/* Sort a list of points into clockwise order.\n *\n * Called from:\n * _NG_utilities.def select_tetragon\n * _NG_Extra.def Perspective_match_item\n * _NG_Extra.def Perspective_item\n */ \t\nsort_pts_clockwise l = l''\n\t\t{\n\t\t// sort functions:\n\t\tf_top a b = a.top < b.top;\n\t\tf_left a b = a.left < b.left;\n\t\tf_right a b = a.left > b.left;\n\n\t\tl' = sortc f_top l;\n\t\tl'_a = take 2 l';\n\t\tl'_b = drop 2 l';\n\n\t\tl''_a = sortc f_left l'_a;\n\t\tl''_b = sortc f_right l'_b;\n\t\tl'' = join l''_a l''_b;\n\t\t};\n\nMount_options _ctype _ppcm = class \n  {\n  _vislevel = 3;\n  apply = Toggle \"Apply mount options\" false;\n  ls = Expression \"Lower mount section bigger by (cm)\" 0;\n  mount_colour = Colour _ctype [0, 0, 0];\n  _los = ls.expr * _ppcm;\n  };\n\nFrame_variables comp = class\n  {\n  _vislevel = 3;\n\n  scale_factor = Expression \"scale the size of the frame by\" 1;\n\n  /* These sliders define the fraction of the frames width or height is extracted\n   * to produce each of the particular regions.\n   */\n  corner_section = Scale \"Corner section\" 0.1 1 0.5;\n  edge_section = Scale \"Edge section\" 0.1 1 0.2, comp > 0\n\t\t\t\t  = \"Only required for complex frames\";\n  middle_section = Scale \"Middle section\" 0.1 1 0.2;\n  blend_fraction = Scale \"Blend fraction\" 0.1 0.9 0.1;\n  option = Toggle \"Use mirror of left-side to make right\" true;\n  };\n\n"
  },
  {
    "path": "share/nip2/start/_list.def",
    "content": "/* any l: or all the elements of list l together\n *\n * any (map (equal 0) list) == true, if any element of list is zero.\n * any :: [bool] -> bool\n */\nany = foldr logical_or false;\n\n/* all l: and all the elements of list l together\n *\n * all (map (==0) list) == true, if every element of list is zero.\n * all :: [bool] -> bool\n */\nall = foldr logical_and true;\n\n/* concat l: join a list of lists together\n *\n * concat [\"abc\",\"def\"] == \"abcdef\".\n * concat :: [[*]] -> [*]\n */\nconcat l = foldr join [] l;\n\n/* delete eq x l: delete the first x from l\n *\n * delete equal 'b' \"abcdb\" == \"acdb\"\n * delete :: (* -> bool) -> * -> [*] -> [*]\n */\ndelete eq a l\n\t= [], l == []\n\t= y, eq a b\n\t= b : delete eq a y\n{\n\tb:y = l;\n}\n\n/* difference eq a b: delete b from a\n *\n * difference equal \"asdf\" \"ad\" == \"sf\"\n * difference :: (* -> bool) -> [*] -> [*] -> [*]\n */\ndifference = foldl @ converse @ delete;\n\n/* drop n l: drop the first n elements from list l\n *\n * drop 3 \"abcd\" == \"d\"\n * drop :: num -> [*] -> [*]\n */\ndrop n l \n\t= l, n <= 0 || l == []\n\t= drop (n - 1) (tl l);\n\n/* dropwhile fn l: drop while fn is true\n *\n * dropwhile is_digit \"1234pigs\" == \"pigs\"\n * dropwhile :: (* -> bool) -> [*] -> [*]\n */\ndropwhile fn l\n\t= [], l == []\n\t= dropwhile fn x, fn a\n\t= l\n{\n\ta:x = l;\n}\n\n/* extract n l: extract element at index n from list l\n */\nextract = converse subscript;\n\n/* filter fn l: return all elements of l for which predicate fn holds\n *\n * filter is_digit \"1one2two3three\" = \"123\"\n * filter :: (* -> bool) -> [*] -> [*]\n */\nfilter fn l\n\t= foldr addif [] l\n{\n\taddif x l\n\t\t= x : l, fn x;\n\t\t= l;\n}\n\n/* flatten x: flatten a list of lists of things into a simple list\n *\n * flatten :: [[*]] -> [*]\n */\nflatten x\n\t= foldr flat [] x, is_list x\n\t= x\n{\n\tflat x sofar\n\t\t= foldr flat sofar x, is_list x\n\t\t= x : sofar;\n}\n\n/* foldl fn st l: fold list l from the left with function fn and start st\n *\n * Start from the left hand end of the list (unlike foldr, see below). \n * foldl is less useful (and much slower).\n *\n * foldl fn start [a,b .. z] = ((((st fn a) fn b) ..) fn z)\n * foldl :: (* -> ** -> *) -> * -> [**] -> * \n */\nfoldl fn st l\n\t= st, l == []\n\t= foldl fn (fn st x) xs\n{\n\tx:xs = l;\n}\n\n/* foldl1 fn l: like foldl, but use the 1st element as the start value\n *\n * foldl1 fn [1,2,3] == ((1 fn 2) fn 3)\n * foldl1 :: (* -> * -> *) -> [*] -> *\n */\nfoldl1 fn l\n\t= [], l == []\n\t= foldl fn x xs\n{\n\tx:xs = l;\n}\n\n/* foldr fn st l: fold list l from the right with function fn and start st\n *\n * foldr fn st [a,b..z] = (a fn (b fn (.. (z fn st))))\n * foldr :: (* -> ** -> **) -> ** -> [*] -> **\n */\nfoldr fn st l\n\t= st, l == []\n\t= fn x (foldr fn st xs)\n{\n\tx:xs = l;\n}\n\n/* foldr1 fn l: like foldr, but use the last element as the start value\n *\n * foldr1 fn [1,2,3,4] == (1 fn (2 fn (3 fn 4)))\n * foldr1 :: (* -> * -> *) -> [*] -> *\n */\nfoldr1 fn l\n\t= [], l == []\n\t= x, xs == []\n\t= fn x (foldr1 fn xs)\n{\n\tx:xs = l;\n}\n\n/* Search a list for an element, returning its index (or -1)\n *\n * index (equal 12) [13,12,11] == 1\n * index :: (* -> bool) -> [*] -> real\n */\nindex fn list\n\t= search list 0\n{\n\tsearch l n\n\t\t= -1, l == []\n\t\t= n, fn x\n\t\t= search xs (n + 1)\n\t\t{\n\t\t\tx:xs = l;\n\t\t}\n}\n\n/* init l: remove last element of list l\n *\n * The dual of tl.\n * init [1,2,3] == [1,2]\n * init :: [*] -> [*]\n */\ninit l\n\t= error \"init of []\", l == [];\n\t= [], tl l == [];\n\t= x : init xs\n{\n\tx:xs = l;\n}\n\n/* iterate f x: repeatedly apply f to x\n *\n * return the infinite list [x, f x, f (f x), ..].\n * iterate (multiply 2) 1 == [1, 2, 4, 8, 16, 32, 64 ... ]\n * iterate :: (* -> *) -> * -> [*]\n */\niterate f x = x : iterate f (f x);\n\n/* join_sep sep l: join a list with a separator\n *\n * join_sep \", \" (map print [1 .. 4]) == \"1, 2, 3, 4\"\n * join_sep :: [*] -> [[*]] -> [*]\n */\njoin_sep sep l\n\t= foldl1 fn l\n{\n\tfn a b = a ++ sep ++ b;\n}\n\n/* last l: return the last element of list l\n *\n * The dual of hd. last [1,2,3] == 3\n * last :: [*] -> [*]\n */\nlast l\n\t= error \"last of []\", l == []\n\t= x, xs == []\n\t= last xs\n{\n\tx:xs = l;\n}\n\n/* len l: length of list l\n * (see also is_list_len and friends in predicate.def)\n *\n * len :: [*] -> num\n */\nlen l\n\t= 0, l == []\n\t= 1 + len (tl l);\n\n/* limit l: return the first element of l which is equal to its predecessor\n *\n * useful for checking for convergence\n * limit :: [*] -> *\n */\nlimit l\n\t= error \"incorrect use of limit\", \n\t\tl == [] || tl l == [] || tl (tl l) == []\n\t= a, a == b\n\t= limit (b : x)\n{\n\ta:b:x = l;\n}\n\n/* Turn a function of n args into a function which takes a single arg of an \n * n-element list.\n */\nlist_1ary fn x = fn x?0;\nlist_2ary fn x = fn x?0 x?1;\nlist_3ary fn x = fn x?0 x?1 x?2;\nlist_4ary fn x = fn x?0 x?1 x?2 x?3;\nlist_5ary fn x = fn x?0 x?1 x?2 x?3 x?4;\nlist_6ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5;\nlist_7ary fn x = fn x?0 x?1 x?2 x?3 x?4 x?5 x?6;\n\n/* map fn l: map function fn over list l\n *\n * map :: (* -> **) -> [*] -> [**]\n */\nmap f l\n\t= [], l == [];\n\t= f (hd l) : map f (tl l);\n\n/* map2 fn l1 l2: map two lists together with fn \n *\n * map2 :: (* -> ** -> ***) -> [*] -> [**] -> [***]\n */\nmap2 fn l1 l2 = map (list_2ary fn) (zip2 l1 l2);\n\n/* map3 fn l1 l2 l3: map three lists together with fn \n *\n * map3 :: (* -> ** -> *** -> ****) -> [*] -> [**] -> [***] -> [****]\n */\nmap3 fn l1 l2 l3 = map (list_3ary fn) (zip3 l1 l2 l3);\n\n/* member l x: true if x is a member of list l\n *\n * is_digit == member \"0123456789\"\n * member :: [*] -> * -> bool\n */\nmember l x = any (map (equal x) l);\n\n/* merge b l r: merge two lists based on a bool list\n *\n * merge :: [bool] -> [*] -> [*] -> [*]\n */\nmerge p l r\n\t= [], p == [] || l == [] || r == []\n\t= a : merge z x y, c\n\t= b : merge z x y\n{\n\ta:x = l;\n\tb:y = r;\n\tc:z = p;\n}\n\n/* mkset eq l: remove duplicates from list l using equality function\n *\n * mkset :: (* -> bool) -> [*] -> [*]\n */\nmkset eq l\n\t= [], l == []\n\t= a : filter (not @ eq a) (mkset eq x)\n{\n\ta:x = l;\n}\n\n/* postfix l r: add r to the end of list l\n *\n * The dual of ':'.\n * postfix :: [*] -> ** -> [*,**]\n */\npostfix l r = l ++ [r];\n\n/* repeat x: make an infinite list of xes\n *\n * repeat :: * -> [*]\n */\nrepeat x = map (const x) [1..];\n\n/* replicate n x: make n copies of x in a list\n *\n * replicate :: num -> * -> [*]\n */\nreplicate n x = take n (repeat x);\n\n/* reverse l: reverse list l\n *\n * reverse :: [*] -> [*]\n */\nreverse l = foldl (converse cons) [] l;\n\n/* scanl fn st l: apply (foldl fn r) to every initial segment of a list\n *\n * scanl add 0 [1,2,3] == [1,3,6]\n * scanl :: (* -> ** -> *) -> * -> [**] -> [*]\n */\nscanl fn st l\n\t= st, l == []\n\t= st' : scanl fn st' xs\n{\n\tx:xs = l;\n\tst' = fn st x;\n}\n\n/* sort l: sort list l into ascending order\n *\n * sort :: [*] -> [*]\n */\nsort l = sortc less_equal l;\n\n/* sortc comp l: sort list l into order using a comparision function\n *\n * Uses merge sort (n log n behaviour)\n * sortc :: (* -> * -> bool) -> [*] -> [*]\n */\nsortc comp l\n\t= l, n <= 1\n\t= merge (sortc comp (take n2 l)) (sortc comp (drop n2 l))\n{\n\tn = len l;\n\tn2 = (int) (n / 2);\n\n\t/* merge l1 l2: merge sorted lists l1 and l2 to make a single \n\t * sorted list\n\t */\n\tmerge l1 l2\n\t\t= l2, l1 == []\n\t\t= l1, l2 == []\n\t\t= a : merge x (b : y), comp a b\n\t\t= b : merge (a : x) y\n\t{\n\t\ta:x = l1;\n\t\tb:y = l2;\n\t}\n}\n\n/* sortpl pl l: sort by a list of predicates\n *\n * sortpl :: (* -> bool) -> [*] -> [*]\n */\nsortpl pl l\n\t= sortc (test pl) l\n{\n\t/* Comparision function ... put true before false, if equal move on to\n\t * the next predicate.\n\t */\n\ttest pl a b\n\t\t= true, pl == []\n\t\t= ta, ta != tb\n\t\t= test (tl pl) a b\n\t{\n\t\tta = pl?0 a;\n\t\ttb = pl?0 b;\n\t}\n}\n\n/* sortr l: sort list l into descending order\n *\n * sortr :: [*] -> [*]\n */\nsortr l = sortc more l;\n\n/* split fn l: break a list into sections separated by many fn\n *\n * split is_space \"  hello world \" == [\"hello\", \"world\"]\n * split is_space \"  \" == []\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplit fn l\n        = [], l == [] || l' == []\n        = head : split fn tail\n{ \n        nfn = not @ fn;\n\n        l' = dropwhile fn l;\n        head = takewhile nfn l';\n        tail = dropwhile nfn l';\n}   \n\n/* splits fn l: break a list into sections separated by a single fn\n *\n * split (equal ',') \",,1\" == [\"\", \"\", \"1\"]\n * split :: (* -> bool) -> [*] -> [[*]]\n */\nsplits fn l\n        = [], l == [] \n        = head : splits fn tail\n{ \n        fn' = not @ fn;\n\tdropif x \n\t\t= [], x == []\n\t\t= tl x;\n\n        head = takewhile fn' l;\n        tail = dropif (dropwhile fn' l);\n}   \n\n/* splitpl fnl l: split a list up with a list of predicates\n *\n * splitpl [is_digit, is_letter, is_digit] \"123cat\" == [\"123\", \"cat\", []]\n * splitpl :: [* -> bool] -> [*] -> [[*]]\n */\nsplitpl fnl l \n        = l, fnl == []\n        = head : splitpl (tl fnl) tail\n{\n        head = takewhile (hd fnl) l;\n        tail = dropwhile (hd fnl) l;\n}\n\n/* split_lines n l: split a list into equal length lines\n *\n * split_lines 4 \"1234567\" == [\"1234\", \"567\"]\n * splitl :: int -> [*] -> [[*]]\n */\nsplit_lines n l\n        = [], l == []\n        = take n l : split_lines n (drop n l);\n\n/* take n l: take the first n elements from list l\n * take :: num -> [*] -> [*]\n */\ntake n l \n\t= [], n <= 0\n\t= [], l == []\n\t= hd l : take (n-1) (tl l);\n\n/* takewhile fn l: take from the front of a list while predicate fn holds\n *\n * takewhile is_digit \"123onetwothree\" == \"123\"\n * takewhile :: (* -> bool) -> [*] -> [*]\n */\ntakewhile fn l\n\t= [], l == []\n\t= hd l : takewhile fn (tl l), fn (hd l)\n\t= [];\n\n/* zip2 l1 l2: zip two lists together \n *\n * zip2 [1,2] ['a', 'b', 'c'] == [[1,'a'],[2,'b']]\n * zip2 :: [*] -> [**] -> [[*,**]]\n */\nzip2 l1 l2\n\t= [], l1 == [] || l2 == []\n\t= [hd l1, hd l2] : zip2 (tl l1) (tl l2);\n\n/* zip3 l1 l2 l3: zip three lists together\n *\n * zip3 [1,2] ['a', 'b', 'c'] [true] == [[1,'a',true]]\n * zip3 :: [*] -> [**] ->[***] -> [[*,**,***]]\n */\nzip3 l1 l2 l3\n\t= [], l1 == [] || l2 == [] || l3 == []\n\t= [hd l1, hd l2, hd l3] : zip3 (tl l1) (tl l2) (tl l3);\n"
  },
  {
    "path": "share/nip2/start/_magick.def",
    "content": "/* \n\n   ImageMagick operations edited by Alan Gibson (aka \"snibgo\"; snibgo at earthling dot net).\n\n   1-Apr-2014\n     Minor corrections to Geometry_widget and Alpha.\n     Added loads of widgets and Menuactions.\n     Not fully tested.\n   5-Apr-2014\n     Many more menu actions.\n     Reorganised Magick menu.\n   10-Apr-2014\n     Many more menu actions.\n   11-Apr-2014 jcupitt\n     Split to separate _magick.def\n\t Add 0-ary and 2-ary system\n\t Put utility funcs into a Magick class\n   11-Apr-2014 snibgo\n     Added VirtualPixelBack for cases where background is only relevant when VP=Background\n   17-Apr-2014 snibgo\n     Many small changes.\n   2-May-2014 jcupitt\n     Added Magick.version\n   30-June-2014\n   \t Put single-quotes around command exe to help win\n   1-July-2014\n     Automatically fall back to gm if we can't find convert\n   17-July-2014\n     better GM support\n\n\n   Last update: 17-July-2014.\n\n   For details of ImageMagick operations, see http://www.imagemagick.org/script/command-line-options.php etc.\n\n*/\n\n/* Put these in a class to avoid filling the main namespace with IM stuff.\n */\n\nMagick = class {\n\n\t// first gm on path, or \"\"\n\tgm_path = search_for \"gm\";\n\n\t// first convert on $PATH, or \"\"\n\t// we check for the convert we ship first\n\tconvert_path \n\t\t= vips_convert, vips_convert != \"\"\n\t\t= search_for \"convert\"\n\t{\n\t\t// the convert we ship with the vips binary on some platforms, or \"\"\n\t\tvips_convert \n\t\t\t= search (path_absolute convert)\n\t\t{\n\t\t\tvipshome = path_parse (expand \"$VIPSHOME\");\n\t\t\tconvert = vipshome ++ [\"bin\", \"convert\" ++ expand \"$EXEEXT\"];\n\t\t}\n\t}\n\n\tuse_gm_pref = Workspaces.Preferences.USE_GRAPHICSMAGICK;\n\n\t// Are we in GM or IM mode? \n\tuse_gm \n\t\t= true, use_gm_pref && gm_path != \"\"\n\t\t= false, !use_gm_pref && convert_path != \"\"\n\t\t= false, convert_path != \"\"\n\t\t= true, gm_path != \"\"\n\t\t= error \"neither IM nor GM executable found\";\n\n\tcommand_path\n\t\t= gm_path, use_gm\n\t\t= convert_path;\n\n\t// try to get the version as eg. [6, 7, 7, 10]\n\t// GM versions are smaller, typically [1, 3, 18]\n\tversion\n\t\t= map parse_int (split (member \".-\") version_string)\n\t{\n\t\t[output] = vips_call \"system\" \n\t\t\t[\"'\" ++ command_path ++ \"' -version\"] [$log=>true];\n\t\tversion_string \n\t\t\t= (split (equal ' ') output)?1, use_gm\n\t\t\t= (split (equal ' ') output)?2;\n\t}\n\n\t// make a command-line ... args is a [str] we join with spaces\n\tcommand args \n\t\t= \"'\" ++ command_path ++ \"' \" ++ join_sep \" \" args'\n\t{\n\t\targs'\n\t\t\t= [\"convert\"] ++ args, use_gm\n\t\t\t= args;\n\t}\n\n\t// capabilities ... different versions support different features, we \n\t// turn features on and off based on these\n\n\t// would probably be better to test for caps somehow\n\thas_intensity\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\thas_channel\n\t\t\t= false, use_gm\n\t\t\t= version?0 > 6 || version?1 > 7;\n\n\tsystem0 cmd = system_image0 cmd;\n\tsystem cmd x = map_unary (system_image cmd) x;\n\tsystem2 cmd x y = map_binary (system_image2 cmd) x y;\n\tsystem3 cmd x y z = map_trinary (system_image3 cmd) x y z;\n\n\tradius_widget = Scale \"Radius\" 0 100 10;\n\tsigma_widget = Scale \"Sigma\" 0.1 10 1;\n\tangle_widget = Scale \"Angle (degrees)\" (-360) 360 0;\n\ttext_widget = String \"Text to draw\" \"AaBbCcDdEe\";\n\n\tgamma_widget = Scale \"Gamma\" 0 10 1;\n\tcolors_widget = Scale \"Colors\" 1 10 3;\n\tresize_widget = Scale \"Resize (percent)\" 0 500 100;\n\tfuzz_widget = Scale \"Fuzz (percent)\" 0 100 0;\n\tblur_rad_widget = Scale \"Radius (0=auto)\" 0 100 0;\n\n\t// a colour with no enclosing quotes ... use this if we know there are\n\t// some quotes at an outer level\n\tprint_colour_nq triple\n\t\t= concat [\"#\", concat (map fmt triple)]\n\t{\n\t\tfmt x = reverse (take 2 (reverse (print_base 16 (x + 256))));\n\t}\n\n\t// we need the quotes because # is the comment character in *nix\n\tprint_colour triple = \"\\\"\" ++ print_colour_nq triple ++ \"\\\"\";\n\n\tForeground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-fill \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Foreground triple;\n\t}\n\tforeground_widget = Foreground [0, 0, 0];\n\n\tGeneralCol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = print_colour_nq triple;\n\n\t\tColour_edit space triple = this.GeneralCol triple;\n\t}\n\tgeneralcol_widget = GeneralCol [0, 0, 0];\n\n\tBackground triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" false;\n\n\t\t_flag = \"-background \" ++ if isNone then \"None\" else print_colour triple;\n\n\t\tColour_edit space triple = this.Background triple;\n\t}\n\tbackground_widget = Background [255, 255, 255];\n\n\tBordercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-bordercolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Bordercol triple;\n\t}\n\tbordercol_widget = Bordercol [0, 0, 0];\n\n\tMattecol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\t_flag = \"-mattecolor \" ++ print_colour triple;\n\n\t\tColour_edit space triple = this.Mattecol triple;\n\t}\n\tmattecol_widget = Mattecol [189, 189, 189];\n\n\t// FIXME: Undercolour, like many others, can have alpha channel.\n\t// How does user input this? With a slider?\n\tUndercol triple = class\n\t\tColour \"sRGB\" triple {\n\n\t\tisNone = Toggle \"None (transparent black)\" true;\n\n\t\t_flag = if isNone then \"\" else (\"-undercolor \" ++ print_colour triple);\n\n\t\tColour_edit space triple = this.Undercol triple;\n\t}\n\tundercol_widget = Undercol [0, 0, 0];\n\n\tchangeCol_widget = class {\n\t\t_vislevel = 3;\n\n\t\tcolour = GeneralCol [0, 0, 0];\n\t\tfuzz = fuzz_widget;\n\t\tnonMatch = Toggle \"change non-matching colours\" false;\n\t}\n\n\tAlpha alpha = class\n\t\tOption_string \"Alpha\" [\n\t\t\t\"On\", \n\t\t\t\"Off\", \n\t\t\t\"Set\", \n\t\t\t\"Opaque\", \n\t\t\t\"Transparent\", \n\t\t\t\"Extract\", \n\t\t\t\"Copy\", \n\t\t\t\"Shape\", \n\t\t\t\"Remove\", \n\t\t\t\"Background\"\n\t\t] alpha {\n\n\t\t_flag = \"-alpha \" ++ alpha;\n\n\t\tOption_edit caption labels value = this.Alpha labels?value;\n\t}\n\talpha_widget = Alpha \"On\";\n\n\tAntialias value = class\n\t\tToggle \"Antialias\" value {\n\n\t\t_flag\n\t\t\t= \"-antialias\", value\n\t\t\t= \"+antialias\";\n\n\t\tToggle_edit caption value = this.Antialias value;\n\t}\n\tantialias_widget = Antialias true;\n\n\tBuiltin builtin = class\n\t\tOption_string \"Builtin\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"rose:\",\n\t\t\t\"logo:\",\n\t\t\t\"wizard:\",\n\t\t\t\"granite:\",\n\t\t\t\"netscape:\"\n\t\t] builtin {\n\n\t\t_flag = builtin;\n\n\t\tOption_edit caption labels value = this.Builtin labels?value;\n\t}\n\tbuiltin_widget = Builtin \"rose:\";\n\n\n\tchannels_widget = class {\n\t\t// FIXME? Can we grey-out alpha when we have no alpha channel,\n\t\t//        show CMY(K) instead of RGB(K) etc?\n\t\t// Yes, perhaps we can create different widgets for RGB, RGBA, CMY, CMYK, CMYA, CMYKA.\n\t\tChanR valueR = class\n\t\t\tToggle \"Red\" valueR {\n\n\t\t\t_flag\n\t\t\t\t= \"R\", valueR\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueR = this.ChanR valueR;\n\t\t}\n\t\tchannelR = ChanR true;\n\n\t\tChanG valueG = class\n\t\t\tToggle \"Green\" valueG {\n\n\t\t\t_flag\n\t\t\t\t= \"G\", valueG\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueG = this.ChanG valueG;\n\t\t}\n\t\tchannelG = ChanG true;\n\n\t\tChanB valueB = class\n\t\t\tToggle \"Blue\" valueB {\n\n\t\t\t_flag\n\t\t\t\t= \"B\", valueB\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueB = this.ChanB valueB;\n\t\t}\n\t\tchannelB = ChanB true;\n\n\t\tChanK valueK = class\n\t\t\tToggle \"Black\" valueK {\n\n\t\t\t_flag\n\t\t\t\t= \"K\", valueK\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueK = this.ChanK valueK;\n\t\t}\n\t\tchannelK = ChanK true;\n\n\t\tChanA valueA = class\n\t\t\tToggle \"Alpha\" valueA {\n\n\t\t\t_flag\n\t\t\t\t= \"A\", valueA\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueA = this.ChanA valueA;\n\t\t}\n\t\tchannelA = ChanA false;\n\n\t\tChanSy valueSy = class\n\t\t\tToggle \"Sync\" valueSy {\n\n\t\t\t_flag\n\t\t\t\t= \",sync\", valueSy\n\t\t\t\t= \"\";\n\n\t\t\tToggle_edit caption valueSy = this.ChanSy valueSy;\n\t\t}\n\t\tchannelSy = ChanSy true;\n\n\t\t_rgbka = concat [channelR._flag,\n\t\t\t\tchannelG._flag,\n\t\t\t\tchannelB._flag,\n\t\t\t\tchannelK._flag,\n\t\t\t\tchannelA._flag\n\t\t\t];\n\n\t\t_flag\n\t\t\t= \"\", _rgbka == \"\" || !has_channel\n\t\t\t= concat [ \"-channel \",\n\t\t\t\t_rgbka,\n\t\t\t\tchannelSy._flag \n\t\t\t\t];\n\t}\n\n\tch_widget = channels_widget;\n\n\tColorspace colsp = class\n\t\tOption_string \"Colorspace\" [\n\t\t\t\"CIELab\",\n\t\t\t\"CMY\",\n\t\t\t\"CMYK\",\n\t\t\t\"Gray\",\n\t\t\t\"HCL\",\n\t\t\t\"HCLp\",\n\t\t\t\"HSB\",\n\t\t\t\"HSI\",\n\t\t\t\"HSL\",\n\t\t\t\"HSV\",\n\t\t\t\"HWB\",\n\t\t\t\"Lab\",\n\t\t\t\"LCH\",\n\t\t\t\"LCHab\",\n\t\t\t\"LCHuv\",\n\t\t\t\"LMS\",\n\t\t\t\"Log\",\n\t\t\t\"Luv\",\n\t\t\t\"OHTA\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601YCbCr\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709YCbCr\",\n\t\t\t\"RGB\",\n\t\t\t\"scRGB\",\n\t\t\t\"sRGB\",\n\t\t\t\"Transparent\",\n\t\t\t\"XYZ\",\n\t\t\t\"YCbCr\",\n\t\t\t\"YDbDr\",\n\t\t\t\"YCC\",\n\t\t\t\"YIQ\",\n\t\t\t\"YPbPr\",\n\t\t\t\"YUV\"\n\t\t] colsp {\n\n\t\t_flag = colsp;\n\n\t\tOption_edit caption labels value = this.Colorspace labels?value;\n\t}\n\tcolorspace_widget = Colorspace \"sRGB\";\n\n\tCompose comp = class\n\t\tOption_string \"Compose method\" [\n\t\t\t\"Atop\", \n\t\t\t\"Blend\", \n\t\t\t\"Blur\", \n\t\t\t\"Bumpmap\", \n\t\t\t\"ChangeMask\", \n\t\t\t\"Clear\", \n\t\t\t\"ColorBurn\", \n\t\t\t\"ColorDodge\", \n\t\t\t\"Colorize\", \n\t\t\t\"CopyBlack\", \n\t\t\t\"CopyBlue\", \n\t\t\t\"CopyCyan\", \n\t\t\t\"CopyGreen\", \n\t\t\t\"Copy\", \n\t\t\t\"CopyMagenta\", \n\t\t\t\"CopyOpacity\", \n\t\t\t\"CopyRed\", \n\t\t\t\"CopyYellow\", \n\t\t\t\"Darken\", \n\t\t\t\"DarkenIntensity\", \n\t\t\t\"DivideDst\", \n\t\t\t\"DivideSrc\", \n\t\t\t\"Dst\", \n\t\t\t\"Difference\", \n\t\t\t\"Displace\", \n\t\t\t\"Dissolve\", \n\t\t\t\"Distort\", \n\t\t\t\"DstAtop\", \n\t\t\t\"DstIn\", \n\t\t\t\"DstOut\", \n\t\t\t\"DstOver\", \n\t\t\t\"Exclusion\", \n\t\t\t\"HardLight\", \n\t\t\t\"Hue\", \n\t\t\t\"In\", \n\t\t\t\"Lighten\", \n\t\t\t\"LightenIntensity\", \n\t\t\t\"LinearBurn\", \n\t\t\t\"LinearDodge\", \n\t\t\t\"LinearLight\", \n\t\t\t\"Luminize\", \n\t\t\t\"Mathematics\", \n\t\t\t\"MinusDst\", \n\t\t\t\"MinusSrc\", \n\t\t\t\"Modulate\", \n\t\t\t\"ModulusAdd\", \n\t\t\t\"ModulusSubtract\", \n\t\t\t\"Multiply\", \n\t\t\t\"None\", \n\t\t\t\"Out\", \n\t\t\t\"Overlay\", \n\t\t\t\"Over\", \n\t\t\t\"PegtopLight\", \n\t\t\t\"PinLight\", \n\t\t\t\"Plus\", \n\t\t\t\"Replace\", \n\t\t\t\"Saturate\", \n\t\t\t\"Screen\", \n\t\t\t\"SoftLight\", \n\t\t\t\"Src\", \n\t\t\t\"SrcAtop\", \n\t\t\t\"SrcIn\", \n\t\t\t\"SrcOut\", \n\t\t\t\"SrcOver\", \n\t\t\t\"VividLight\", \n\t\t\t\"Xor\"\n\t\t] comp {\n\n\t\t_flag = \"-compose \" ++ comp;\n\n\t\tOption_edit caption labels value = this.Compose labels?value;\n\t}\n\tcompose_widget = Compose \"Over\";\n\t// FIXME: Some compose mehods (Displace, Distort, Mathematics) need a string.\n\n\t// FIXME: we could use a class that does both -compose and -intensity, for methods LightenIntensity, DarkenIntensity, CopyOpacity, CopyBlack\n\n\tcoordinate_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\n\t\t_flag = concat [print x.expr, \",\", print y.expr];\n\t};\n\n\tDistort distort = class\n\t\tOption_string \"Distort\" [\n\t\t\t\"Affine\",\n\t\t\t\"AffineProjection\",\n\t\t\t\"ScaleRotateTranslate\",\n\t\t\t\"SRT\",\n\t\t\t\"Perspective\",\n\t\t\t\"PerspectiveProjection\",\n\t\t\t\"BilinearForward\",\n\t\t\t\"BilinearReverse\",\n\t\t\t\"Polynomial\",\n\t\t\t\"Arc\",\n\t\t\t\"Polar\",\n\t\t\t\"DePolar\",\n\t\t\t\"Barrel\",\n\t\t\t\"BarrelInverse\",\n\t\t\t\"Shepards\",\n\t\t\t\"Resize\"\n\t\t] distort {\n\n\t\t_flag = distort;\n\n\t\tOption_edit caption labels value = this.Distort labels?value;\n\t}\n\tdistort_widget = Distort \"SRT\";\n\n\tDither dither = class\n\t\tOption_string \"Dither\" [\n\t\t\t\"None\",\n\t\t\t\"FloydSteinberg\",\n\t\t\t\"Riemersma\"\n\t\t] dither {\n\n\t\t_flag = \"-dither \" ++ dither;\n\n\t\tOption_edit caption labels value = this.Dither labels?value;\n\t}\n\tdither_widget = Dither \"FloydSteinberg\";\n\n\tEvaluate eval = class\n\t\tOption_string \"Evaluate operation\" [\n\t\t\t\"Abs\",\n\t\t\t\"Add\",\n\t\t\t\"AddModulus\",\n\t\t\t\"And\",\n\t\t\t\"Cos\",\n\t\t\t\"Cosine\",\n\t\t\t\"Divide\",\n\t\t\t\"Exp\",\n\t\t\t\"Exponential\",\n\t\t\t\"GaussianNoise\",\n\t\t\t\"ImpulseNoise\",\n\t\t\t\"LaplacianNoise\",\n\t\t\t\"LeftShift\",\n\t\t\t\"Log\",\n\t\t\t\"Max\",\n\t\t\t\"Mean\",\n\t\t\t\"Median\",\n\t\t\t\"Min\",\n\t\t\t\"MultiplicativeNoise\",\n\t\t\t\"Multiply\",\n\t\t\t\"Or\",\n\t\t\t\"PoissonNoise\",\n\t\t\t\"Pow\",\n\t\t\t\"RightShift\",\n\t\t\t\"Set\",\n\t\t\t\"Sin\",\n\t\t\t\"Sine\",\n\t\t\t\"Subtract\",\n\t\t\t\"Sum\",\n\t\t\t\"Threshold\",\n\t\t\t\"ThresholdBlack\",\n\t\t\t\"ThresholdWhite\",\n\t\t\t\"UniformNoise\",\n\t\t\t\"Xor\"\n\t\t] eval {\n\n\t\t_flag = \"-evaluate \" ++ eval;\n\n\t\tOption_edit caption labels value = this.Evaluate labels?value;\n\t}\n\tevaluate_widget = Evaluate \"Add\";\n\n\tFilter filt = class\n\t\tOption_string \"Filter\" [\n\t\t\t\"default\",\n\t\t\t\"Bartlett\",\n\t\t\t\"Blackman\",\n\t\t\t\"Bohman\",\n\t\t\t\"Box\",\n\t\t\t\"Catrom\",\n\t\t\t\"Cosine\",\n\t\t\t\"Cubic\",\n\t\t\t\"Gaussian\",\n\t\t\t\"Hamming\",\n\t\t\t\"Hann\",\n\t\t\t\"Hermite\",\n\t\t\t\"Jinc\",\n\t\t\t\"Kaiser\",\n\t\t\t\"Lagrange\",\n\t\t\t\"Lanczos\",\n\t\t\t\"Lanczos2\",\n\t\t\t\"Lanczos2Sharp\",\n\t\t\t\"LanczosRadius\",\n\t\t\t\"LanczosSharp\",\n\t\t\t\"Mitchell\",\n\t\t\t\"Parzen\",\n\t\t\t\"Point\",\n\t\t\t\"Quadratic\",\n\t\t\t\"Robidoux\",\n\t\t\t\"RobidouxSharp\",\n\t\t\t\"Sinc\",\n\t\t\t\"SincFast\",\n\t\t\t\"Spline\",\n\t\t\t\"Triangle\",\n\t\t\t\"Welch\"\n\t\t] filt {\n\n\t\t_flag = if filt == \"default\" then \"\" else \"-filter \" ++ filt;\n\n\t\tOption_edit caption labels value = this.Filter labels?value;\n\t}\n\tfilter_widget = Filter \"default\";\n\n\tFunction func = class\n\t\tOption_string \"Function\" [\n\t\t\t\"Polynomial\",\n\t\t\t\"Sinusoid\",\n\t\t\t\"Arcsin\",\n\t\t\t\"Arctan\"\n\t\t] func {\n\n\t\t_flag = func;\n\n\t\tOption_edit caption labels value = this.Function labels?value;\n\t}\n\tfunction_widget = Function \"Polynomial\";\n\n//  \"Polynomial (a[n], a[n-1], ... a[1], a[0])\",\n//  \"Sinusoid (freq, phase, amp, bias)\",\n//  \"Arcsin (width, centre, range, bias)\",\n//  \"Arctan (slope, centre, range, bias)\"\n\n\tGravity gravity = class\n\t\tOption_string \"Gravity\" [\n\t\t\t\"None\",\n\t\t\t\"Center\",\n\t\t\t\"East\",\n\t\t\t\"Forget\",\n\t\t\t\"NorthEast\",\n\t\t\t\"North\",\n\t\t\t\"NorthWest\",\n\t\t\t\"SouthEast\",\n\t\t\t\"South\",\n\t\t\t\"SouthWest\",\n\t\t\t\"West\",\n\t\t\t\"Static\"\n\t\t] gravity {\n\n\t\t_flag = \"-gravity \" ++ gravity;\n\n\t\tOption_edit caption labels value = this.Gravity labels?value;\n\t}\n\tgravity_widget = Gravity \"Center\";\n\n\tImageType imagetype = class\n\t\tOption_string \"Image type\" [\n\t\t\t\"Bilevel\",\n\t\t\t\"ColorSeparation\",\n\t\t\t\"ColorSeparationAlpha\",\n\t\t\t\"ColorSeparationMatte\",\n\t\t\t\"Grayscale\",\n\t\t\t\"GrayscaleAlpha\",\n\t\t\t\"GrayscaleMatte\",\n\t\t\t\"Optimize\",\n\t\t\t\"Palette\",\n\t\t\t\"PaletteBilevelAlpha\",\n\t\t\t\"PaletteBilevelMatte\",\n\t\t\t\"PaletteAlpha\",\n\t\t\t\"PaletteMatte\",\n\t\t\t\"TrueColorAlpha\",\n\t\t\t\"TrueColorMatte\",\n\t\t\t\"TrueColor\"\n\t\t] imagetype {\n\n\t\t_flag = \"-type \" ++ imagetype;\n\n\t\tOption_edit caption labels value = this.ImageType labels?value;\n\t}\n\timagetype_widget = ImageType \"TrueColor\";\n\n\tIntensity intensity = class\n\t\tOption_string \"Intensity (gray conversion)\" [\n\t\t\t\"Average\",\n\t\t\t\"Brightness\",\n\t\t\t\"Lightness\",\n\t\t\t\"MS\",\n\t\t\t\"Rec601Luma\",\n\t\t\t\"Rec601Luminance\",\n\t\t\t\"Rec709Luma\",\n\t\t\t\"Rec709Luminance\",\n\t\t\t\"RMS\"\n\t\t] intensity {\n\n\t\t_flag \n\t\t\t= \"-intensity \" ++ intensity, has_intensity\n\t\t\t= \"\";\n\n\t\tOption_edit caption labels value = this.Intensity labels?value;\n\t}\n\tintensity_widget = Intensity \"Rec709Luminance\";\n\n\tInterpolate interp = class\n\t\tOption_string \"Interpolate\" [\n\t\t\t\"default\",\n\t\t\t\"Average\",\n\t\t\t\"Average4\",\n\t\t\t\"Average9\",\n\t\t\t\"Average16\",\n\t\t\t\"Background\",\n\t\t\t\"Bilinear\",\n\t\t\t\"Blend\",\n\t\t\t\"Integer\",\n\t\t\t\"Mesh\",\n\t\t\t\"Nearest\",\n\t\t\t\"NearestNeighbor\",\n\t\t\t\"Spline\"\n\t\t] interp {\n\n\t\t_flag = if interp == \"default\" then \"\" else \"-interpolate \" ++ interp;\n\n\t\tOption_edit caption labels value = this.Interpolate labels?value;\n\t}\n\tinterpolate_widget = Interpolate \"default\";\n\n\tKernel kernel = class\n\t\tOption_string \"Kernel\" [\n\t\t\t\"Unity\",\n\t\t\t\"Gaussian\",\n\t\t\t\"DoG\",\n\t\t\t\"LoG\",\n\t\t\t\"Blur\",\n\t\t\t\"Comet\",\n\t\t\t\"Binomial\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Sobel\",\n\t\t\t\"FreiChen\",\n\t\t\t\"Roberts\",\n\t\t\t\"Prewitt\",\n\t\t\t\"Compass\",\n\t\t\t\"Kirsch\",\n\t\t\t\"Diamond\",\n\t\t\t\"Square\",\n\t\t\t\"Rectangle\",\n\t\t\t\"Disk\",\n\t\t\t\"Octagon\",\n\t\t\t\"Plus\",\n\t\t\t\"Cross\",\n\t\t\t\"Ring\",\n\t\t\t\"Peaks\",\n\t\t\t\"Edges\",\n\t\t\t\"Corners\",\n\t\t\t\"Diagonals\",\n\t\t\t\"LineEnds\",\n\t\t\t\"LineJunctions\",\n\t\t\t\"Ridges\",\n\t\t\t\"ConvexHull\",\n\t\t\t\"ThinSe\",\n\t\t\t\"Skeleton\",\n\t\t\t\"Chebyshev\",\n\t\t\t\"Manhattan\",\n\t\t\t\"Octagonal\",\n\t\t\t\"Euclidean\"\n\t\t\t// FIXME: custom kernel\n\t\t] kernel {\n\n\t\t_flag = kernel;\n\n\t\tOption_edit caption labels value = this.Kernel labels?value;\n\t}\n\tkernel_widget = Kernel \"Unity\";\n\n\tModColSp msp = class\n\t\tOption_string \"modulate colorspace\" [\n\t\t\t\"HCL\", \n\t\t\t\"HCLp\", \n\t\t\t\"HSB\", \n\t\t\t\"HSI\", \n\t\t\t\"HSL\", \n\t\t\t\"HSV\", \n\t\t\t\"HWB\", \n\t\t\t\"LCH\"\n\t\t] msp {\n\n\t\t_flag = \"-set option:modulate:colorspace \" ++ msp;\n\n\t\tOption_edit caption labels value = this.ModColSp labels?value;\n\t}\n\tModColSp_widget = ModColSp \"HSL\";\n\n\tMorphMeth morph = class\n\t\tOption_string \"Method\" [\n\t\t\t\"Correlate\",\n\t\t\t\"Convolve\",\n\t\t\t\"Dilate\",\n\t\t\t\"Erode\",\n\t\t\t\"Close\",\n\t\t\t\"Open\",\n\t\t\t\"DilateIntensity\",\n\t\t\t\"ErodeIntensity\",\n\t\t\t\"CloseIntensity\",\n\t\t\t\"OpenIntensity\",\n\t\t\t\"Smooth\",\n\t\t\t\"EdgeOut\",\n\t\t\t\"EdgeIn\",\n\t\t\t\"Edge\",\n\t\t\t\"TopHat\",\n\t\t\t\"BottomHat\",\n\t\t\t\"HitAndMiss\",\n\t\t\t\"Thinning\",\n\t\t\t\"Thicken\",\n\t\t\t\"Distance\",\n\t\t\t\"IterativeDistance\"\n\t\t] morph {\n\n\t\t_flag = morph;\n\n\t\tOption_edit caption labels value = this.MorphMeth labels?value;\n\t}\n\tmorphmeth_widget = MorphMeth \"Dilate\";\n\n\tNoise noise = class\n\t\tOption_string \"Noise\" [\n\t\t\t\"Gaussian\",\n\t\t\t\"Impulse\",\n\t\t\t\"Laplacian\",\n\t\t\t\"Multiplicative\",\n\t\t\t\"Poisson\",\n\t\t\t\"Random\",\n\t\t\t\"Uniform\"\n\t\t] noise {\n\n\t\t_flag = \"+noise \" ++ noise;\n\n\t\tOption_edit caption labels value = this.Noise labels?value;\n\t}\n\tnoise_widget = Noise \"Gaussian\";\n\n\tPattern pattern = class\n\t\tOption_string \"Noise\" [\n\t\t\t// See http://www.imagemagick.org/script/formats.php\n\t\t\t\"bricks\",\n\t\t\t\"checkerboard\",\n\t\t\t\"circles\",\n\t\t\t\"crosshatch\",\n\t\t\t\"crosshatch30\",\n\t\t\t\"crosshatch45\",\n\t\t\t\"gray0\",\n\t\t\t\"gray5\",\n\t\t\t\"gray10\",\n\t\t\t\"gray15\",\n\t\t\t\"gray20\",\n\t\t\t\"gray25\",\n\t\t\t\"gray30\",\n\t\t\t\"gray35\",\n\t\t\t\"gray40\",\n\t\t\t\"gray45\",\n\t\t\t\"gray50\",\n\t\t\t\"gray55\",\n\t\t\t\"gray60\",\n\t\t\t\"gray65\",\n\t\t\t\"gray70\",\n\t\t\t\"gray75\",\n\t\t\t\"gray80\",\n\t\t\t\"gray85\",\n\t\t\t\"gray90\",\n\t\t\t\"gray95\",\n\t\t\t\"gray100\",\n\t\t\t\"hexagons\",\n\t\t\t\"horizontal\",\n\t\t\t\"horizontal2\",\n\t\t\t\"horizontal3\",\n\t\t\t\"horizontalsaw\",\n\t\t\t\"hs_bdiagonal\",\n\t\t\t\"hs_cross\",\n\t\t\t\"hs_diagcross\",\n\t\t\t\"hs_fdiagonal\",\n\t\t\t\"hs_horizontal\",\n\t\t\t\"hs_vertical\",\n\t\t\t\"left30\",\n\t\t\t\"left45\",\n\t\t\t\"leftshingle\",\n\t\t\t\"octagons\",\n\t\t\t\"right30\",\n\t\t\t\"right45\",\n\t\t\t\"rightshingle\",\n\t\t\t\"smallfishscales\",\n\t\t\t\"vertical\",\n\t\t\t\"vertical2\",\n\t\t\t\"vertical3\",\n\t\t\t\"verticalbricks\",\n\t\t\t\"verticalleftshingle\",\n\t\t\t\"verticalrightshingle\",\n\t\t\t\"verticalsaw\"\n\t\t] pattern {\n\n\t\t_flag = \"pattern:\" ++ pattern;\n\n\t\tOption_edit caption labels value = this.Pattern labels?value;\n\t}\n\tpattern_widget = Pattern \"bricks\";\n\n\tResizeType resizet = class\n\t\tOption_string \"Resize type\" [\n\t\t\t\"resize\", \n\t\t\t\"scale\",\n\t\t\t\"sample\",\n\t\t\t\"adaptive-resize\"\n\t\t] resizet {\n\n\t\t_flag = resizet;\n\n\t\tOption_edit caption labels value = this.ResizeType labels?value;\n\t}\n\tResizeType_widget = ResizeType \"resize\";\n\n\tSize_widget = class {\n\t\t_vislevel = 3;\n\n\t\twidth = Expression \"Width (pixels)\" 64;\n\t\theight = Expression \"Height (pixels)\" 64;\n\n\t\t_flag = \"-size \" ++\n\t\t\tprint width.expr ++ \"x\" ++ print height.expr;\n\n\t};\n\n\tStatType statt = class\n\t\tOption_string \"Statistic type\" [\n\t\t\t\"Gradient\", \n\t\t\t\"Maximum\", \n\t\t\t\"Mean\", \n\t\t\t\"Median\", \n\t\t\t\"Minimum\", \n\t\t\t\"Mode\", \n\t\t\t\"Nonpeak\", \n\t\t\t\"StandardDeviation\"\n\t\t] statt {\n\n\t\t_flag = statt;\n\n\t\tOption_edit caption labels value = this.StatType labels?value;\n\t}\n\tStatType_widget = StatType \"Mean\";\n\n\tVirtualPixel vp = class\n\t\tOption_string \"Virtual pixel\" [\n\t\t\t\"Background\", \n\t\t\t\"Black\", \n\t\t\t\"CheckerTile\", \n\t\t\t\"Dither\", \n\t\t\t\"Edge\", \n\t\t\t\"Gray\", \n\t\t\t\"HorizontalTile\", \n\t\t\t\"HorizontalTileEdge\", \n\t\t\t\"Mirror\", \n\t\t\t\"None\",\n\t\t\t\"Random\",\n\t\t\t\"Tile\",\n\t\t\t\"Transparent\",\n\t\t\t\"VerticalTile\",\n\t\t\t\"VerticalTileEdge\",\n\t\t\t\"White\"\n\t\t] vp {\n\n\t\t_flag = \"-virtual-pixel \" ++ vp;\n\n\t\t_isBackground = (vp == \"Background\");\n\n\t\tOption_edit caption labels value = this.VirtualPixel labels?value;\n\t}\n\tVirtualPixel_widget = VirtualPixel \"Edge\";\n\n\tVirtualPixelBack_widget = class {\n\t\tvirtpix = Magick.VirtualPixel_widget;\n\t\tbackground = Magick.background_widget;\n\t\t_flag = (if virtpix._isBackground then (background._flag ++ \" \") else \"\")\n\t\t\t++ virtpix._flag;\n\t}\n\n\tGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"X\" 0;\n\t\ty = Expression \"Y\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tAnnotGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tshearX = Expression \"shear X (degrees)\" 0;\n\t\tshearY = Expression \"shear Y (degrees)\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print shearX.expr, \"x\", print shearY.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tOffsetGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag = concat [format hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tWhxyGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\thoffset = Expression \"Horizontal offset\" 0;\n\t\tvoffset = Expression \"Vertical offset\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat hoffset, format voffset]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFrameGeometry_widget = class {\n\t\t_vislevel = 3;\n\n\t\tx = Expression \"Width\" 0;\n\t\ty = Expression \"Height\" 0;\n\t\toutbev = Expression \"Outer bevel thickness\" 0;\n\t\tinbev = Expression \"Inner bevel thickness\" 0;\n\n\t\t_flag \n\t\t\t= concat [print x.expr, \"x\", print y.expr, \n\t\t\t\tformat outbev, format inbev]\n\t\t{\n\t\t\t// print an offset ... we want '+' in front of +ve strings\n\t\t\tformat offset \n\t\t\t\t= concat [\"+\", print offset.expr], offset.expr >= 0\n\t\t\t\t= print offset.expr;\n\t\t}\n\t};\n\n\tFont_widget = class {\n\t\t_vislevel = 3;\n\n\t\tfamily = Option_string \"Family\" [\n\t\t\t\"Arial\",\n\t\t\t\"ArialBlack\",\n\t\t\t\"AvantGarde\",\n\t\t\t\"BitstreamCharter\",\n\t\t\t\"Bookman\",\n\t\t\t\"CenturySchoolbook\",\n\t\t\t\"ComicSansMS\",\n\t\t\t\"Courier\",\n\t\t\t\"CourierNew\",\n\t\t\t\"DejaVuSans\",\n\t\t\t\"DejaVuSansMono\",\n\t\t\t\"DejaVuSerif\",\n\t\t\t\"Dingbats\",\n\t\t\t\"FreeMono\",\n\t\t\t\"FreeSans\",\n\t\t\t\"FreeSerif\",\n\t\t\t\"Garuda\",\n\t\t\t\"Georgia\",\n\t\t\t\"Helvetica\",\n\t\t\t\"HelveticaNarrow\",\n\t\t\t\"Impact\",\n\t\t\t\"LiberationMono\",\n\t\t\t\"LiberationSans\",\n\t\t\t\"LiberationSerif\",\n\t\t\t\"NewCenturySchlbk\",\n\t\t\t\"Palatino\",\n\t\t\t\"Purisa\",\n\t\t\t\"Symbol\",\n\t\t\t\"Times\",\n\t\t\t\"TimesNewRoman\",\n\t\t\t\"Ubuntu\",\n\t\t\t\"Verdana\",\n\t\t\t\"Webdings\"\n\t\t] \"Arial\";\n\t\tstyle = Option_string \"Style\" [\n\t\t\t\"Any\", \"Italic\", \"Normal\", \"Oblique\"\n\t\t] \"Normal\";\n\t\tweight = Scale \"Weight\" 1 800 400;\n\t\tsize = Scale \"Point size\" 1 100 12;\n\t\tstretch = Option_string \"Stretch\" [\n\t\t\t\"Any\", \"Condensed\", \"Expanded\", \"ExtraCondensed\", \"ExtraExpanded\", \n\t\t\t\"Normal\", \"SemiCondensed\", \"SemiExpanded\", \"UltraCondensed\", \n\t\t\t\"UltraExpanded\"\n\t\t] \"Normal\";\n\n\t\t_flag = join_sep \" \" [\n\t\t\t\t\"-family\", family.item,\n\t\t\t\t\"-weight\", print weight.value,\n\t\t\t\t\"-pointsize\", print size.value,\n\t\t\t\t\"-style\", style.item,\n\t\t\t\t\"-stretch\", stretch.item];\n\t}\n}\n\n"
  },
  {
    "path": "share/nip2/start/_predicate.def",
    "content": "\n/* is_colour_space str: is a string one of nip's colour space names\n */\nis_colour_space str = Image_type.colour_spaces.present 0 str;\n\n/* is_colour_type n: is a number one of VIPS's colour spaces\n */\nis_colour_type n = Image_type.colour_spaces.present 1 n;\n\n/* is_number: is a real or a complex number.\n */\nis_number a = is_real a || is_complex a;\n\n/* is_int: is an integer\n */\nis_int a = is_real a && a == (int) a;\n\n/* is_uint: is an unsigned integer\n */\nis_uint a = is_int a && a >= 0;\n\n/* is_pint: is a positive integer\n */\nis_pint a = is_int a && a > 0;\n\n/* is_preal: is a positive real\n */\nis_preal a = is_real a && a > 0;\n\n/* is_ureal: is an unsigned real\n */\nis_ureal a = is_real a && a >= 0;\n\n/* is_letter c: true if character c is an ASCII letter\n *\n * is_letter :: char -> bool\n */\nis_letter c = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');\n\n/* is_digit c: true if character c is an ASCII digit\n *\n * is_digit :: char->bool\n */\nis_digit x = '0' <= x && x <= '9';\n\n/* A whitespace character.\n *\n * is_space :: char->bool\n */\nis_space = member \" \\n\\t\";\n\n/* List str starts with section prefix.\n *\n * is_prefix \"hell\" \"hello world!\" == true\n * is_prefix :: [*] -> [*] -> bool\n */\nis_prefix prefix str = take (len prefix) str == prefix;\n\n/* List str ends with section suffix.\n *\n * is_suffix \"ld!\" \"hello world!\" == true\n * is_suffix :: [*] -> [*] -> bool\n */\nis_suffix suffix str = take (len suffix) (reverse str) == reverse suffix;\n\n/* List contains seqence.\n *\n * is_substr \"llo\" \"hello world!\" == true\n * is_substr :: [*] -> [*] -> bool\n */\nis_substr seq str = any (map (is_prefix seq) (iterate tl str));\n\n/* is_listof p s: true if finite list with p true for every element.\n */\nis_listof p l = is_list l && all (map p l);\n\n/* is_string s: true if finite list of char.\n */\nis_string s = is_listof is_char s;\n\n/* is_real_list l: is l a list of real numbers ... test each element,\n * so no infinite lists pls.\n */\nis_real_list l = is_listof is_real l;\n\n/* is_string_list l: is l a finite list of finite strings.\n */\nis_string_list l = is_listof is_string l;\n\n/* Test list length ... quicker than len x == n for large lists.\n */\nis_list_len n x\n\t= true, x == [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len (n - 1) (tl x);\n\nis_list_len_more n x\n\t= true, x != [] && n == 0\n\t= false, x == [] || n == 0\n\t= is_list_len_more (n - 1) (tl x);\n\nis_list_len_more_equal n x\n\t= true, n == 0\n\t= false, x == [] \n\t= is_list_len_more_equal (n - 1) (tl x);\n\n/* is_rectangular l: is l a rectangular data structure\n */\nis_rectangular l\n\t= true, !is_list l\n\t= true, all (map is_obj l)\n\t= true, all (map is_list l) &&\n\t\tall (map (not @ is_obj) l) &&\n\t\tall (map is_rectangular l) &&\n\t\tis_list_len_more 0 l &&\n\t\tall (map (is_list_len (len (hd l))) (tl l))\n\t= false\n{\n\t// treat strings as a base type, not [char]\n\tis_obj x = !is_list x || is_string x;\n}\n\n/* is_matrix l: is l a list of lists of real numbers, all the same length\n *\n * [[]] is the empty matrix, [] is the empty list ... disallow []\n */\nis_matrix l = l != [] && is_listof is_real_list l && is_rectangular l;\n\n/* is_square_matrix l: is l a matrix with width == height\n */\nis_square_matrix l\n      = true, l == [[]]\n      = is_matrix l && is_list_len (len (hd l)) l;\n\n/* is_oddmatrix l: is l a matrix with odd-length sides\n */\nis_oddmatrix l\n      = true, l == [[]]\n      = is_matrix l && len l % 2 == 1 && len l?0 % 2 == 1;\n\n/* is_odd_square_matrix l: is l a square_matrix with odd-length sides\n */\nis_odd_square_matrix l = is_square_matrix l && len l % 2 == 1;\n\n/* Is an item in a column of a table?\n */\nis_incolumn n table x = member (map (extract n) table) x;\n\n/* Is HGuide or VGuide.\n */\nis_HGuide x = is_instanceof \"HGuide\" x;\n\nis_VGuide x = is_instanceof \"VGuide\" x;\n\nis_Guide x = is_HGuide x || is_VGuide x;\n\nis_Mark x = is_instanceof \"Mark\" x;\n\nis_Group x = is_instanceof \"Group\" x;\n\nis_NULL x = is_instanceof \"NULL\" x;\n\nis_List x = is_instanceof \"List\" x;\n\nis_Image x = is_instanceof \"Image\" x;\n\nis_Plot x = is_instanceof \"Plot\" x;\n\nis_Region x = is_instanceof \"Region\" x;\n\nis_Real x = is_instanceof \"Real\" x;\n\nis_Matrix x = is_instanceof \"Matrix_base\" x;\n\nis_Vector x = is_instanceof \"Vector\" x;\n\nis_Colour x = is_instanceof \"Colour\" x;\n\nis_Arrow x = is_instanceof \"Arrow\" x;\n\nis_Bool x = is_instanceof \"Bool\" x;\n\nis_Scale x = is_instanceof \"Scale\" x;\n\nis_Rect x = is_instanceof \"Rect\" x;\n\nis_Number x = is_instanceof \"Number\" x;\n\nis_Expression x = is_instanceof \"Expression\" x;\n\nis_String x = is_instanceof \"String\" x;\n\n/* A list of the form [[1,2],[3,4],[5,6]...]\n */\nis_xy_list l \n\t= is_list l && all (map xy l)\n{\n\txy l = is_real_list l && is_list_len 2 l;\n}\n\n// does a nested list structure contain a Group object?\ncontains_Group l\n\t= true, is_list l && any (map is_Group l)\n\t= any (map contains_Group l), is_list l\n\t= false;\n\n/* Does an object have a sensible VIPS type?\n */\nhas_type x = is_image x || is_Image x || is_Arrow x || is_Colour x;\n\n/* Try to get a VIPS image type from an object.\n */\nget_type x\n\t= get_type_im x, is_image x\n\t= get_type_im x.value, is_Image x\n\t= get_type_im x.image.value, is_Arrow x\n\t= Image_type.colour_spaces.lookup 0 1 x.colour_space, is_Colour x\n\t// slightly odd ... but our display is always 0-255, so it makes sense for\n\t// a plain number to be in the same range\n\t= Image_type.sRGB, is_real x\n\t= oo_unary_function get_type_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_type\")\n{\n\tget_type_op = Operator \"get_type\" get_type \n\t\tOperator_type.COMPOUND false;\n\n\t// get the type from a VIPS image ... but only if it makes sense with\n\t// the rest of the image\n\n\t// we often have Type set wrong, hence the ugly guessing :-(\n\t// can have alpha, hence we let bands be one more than you might think\n\n\tget_type_im im\n\t\t= Image_type.LABQ, coding == Image_coding.LABPACK\n\t\t= Image_type.scRGB, coding == Image_coding.RAD\n\t\t= Image_type.GREY16, type == Image_type.GREY16 && is_bands 1\n\t\t= Image_type.HISTOGRAM, type == Image_type.HISTOGRAM && \n\t\t\t(width == 1 || height == 1)\n\t\t= Image_type.B_W, is_bands 1 \n\t\t= Image_type.CMYK, type == Image_type.CMYK && is_bands 4\n\t\t= type, is_colorimetric && is_bands 3\n\t\t= Image_type.sRGB, !is_colorimetric && is_bands 3\n\t\t= Image_type.MULTIBAND, !is_colorimetric && !is_bands 3\n\t\t= type\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tcoding = get_header \"Coding\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\twidth = get_header \"Xsize\" im;\n\t\theight = get_header \"Ysize\" im;\n\n\t\t// 3-band colorimetric types we allow ... the things which the \n\t\t// Colour/Convert To menu can make, excluding mono.\n\t\tok_types = [\n\t\t\tImage_type.sRGB, \n\t\t\tImage_type.scRGB, \n\t\t\tImage_type.RGB16, \n\t\t\tImage_type.LAB, \n\t\t\tImage_type.LABQ, \n\t\t\tImage_type.LABS, \n\t\t\tImage_type.LCH, \n\t\t\tImage_type.XYZ, \n\t\t\tImage_type.YXY, \n\t\t\tImage_type.UCS\n\t\t];\n\t\tis_colorimetric = member ok_types type;\n\n\t\t// is bands n, with an optional alpha (ie. can be n + 1 too)\n\t\tis_bands n = bands == n || bands == n + 1;\n\t}\n}\n\nhas_format x = has_member \"format\" x || is_Arrow x || is_image x;\n\nget_format x \n\t= x.format, has_member \"format\" x\n\t= x.image.format, is_Arrow x\n\t= get_header \"BandFmt\" x, is_image x\n\t= oo_unary_function get_format_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_format\")\n{\n\tget_format_op = Operator \"get_format\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bits x = has_member \"bits\" x || is_Arrow x || is_image x;\n\nget_bits x \n\t= x.bits, has_member \"bits\" x\n\t= x.image.bits, is_Arrow x\n\t= get_header \"Bbits\" x, is_image x\n\t= oo_unary_function get_bits_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bits\")\n{\n\tget_bits_op = Operator \"get_bits\" get_format \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_bands x = is_image x || has_member \"bands\" x || is_Arrow x;\n\nget_bands x \n\t= x.bands, has_member \"bands\" x\n\t= x.image.bands, is_Arrow x\n\t= get_header \"Bands\" x, is_image x\n\t= 1, is_real x\n\t= len x, is_real_list x\n\t= oo_unary_function get_bands_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_bands\")\n{\n\tget_bands_op = Operator \"get_bands\" get_bands \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_coding x = has_member \"coding\" x || is_Arrow x || is_image x;\n\nget_coding x \n\t= x.coding, has_member \"coding\" x\n\t= x.image.coding, is_Arrow x\n\t= get_header \"Coding\" x, is_image x\n\t= Image_coding.NOCODING, is_real x\n\t= oo_unary_function get_coding_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_coding\")\n{\n\tget_coding_op = Operator \"get_coding\" get_coding \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xres x = has_member \"xres\" x || is_Arrow x || is_image x;\n\nget_xres x \n\t= x.xres, has_member \"xres\" x\n\t= x.image.xres, is_Arrow x\n\t= get_header \"Xres\" x, is_image x\n\t= oo_unary_function get_xres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xres\")\n{\n\tget_xres_op = Operator \"get_xres\" get_xres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yres x = has_member \"yres\" x || is_Arrow x || is_image x;\n\nget_yres x \n\t= x.yres, has_member \"yres\" x\n\t= x.image.yres, is_Arrow x\n\t= get_header \"Yres\" x, is_image x\n\t= oo_unary_function get_yres_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yres\")\n{\n\tget_yres_op = Operator \"get_yres\" get_yres \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_xoffset x = has_member \"xoffset\" x || is_Arrow x || is_image x;\n\nget_xoffset x \n\t= x.xoffset, has_member \"xoffset\" x\n\t= x.image.xoffset, is_Arrow x\n\t= get_header \"Xoffset\" x, is_image x\n\t= oo_unary_function get_xoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_xoffset\")\n{\n\tget_xoffset_op = Operator \"get_xoffset\" get_xoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_yoffset x = has_member \"yoffset\" x || is_Arrow x || is_image x;\n\nget_yoffset x \n\t= x.yoffset, has_member \"yoffset\" x\n\t= x.image.yoffset, is_Arrow x\n\t= get_header \"Yoffset\" x, is_image x\n\t= oo_unary_function get_yoffset_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_yoffset\")\n{\n\tget_yoffset_op = Operator \"get_yoffset\" get_yoffset \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_value = has_member \"value\";\n\nget_value x = x.value;\n\nhas_image x = is_image x || is_Image x || is_Arrow x;\n\nget_image x \n\t= x.value, is_Image x\n\t= x.image.value, is_Arrow x\n\t= x, is_image x\n\t= oo_unary_function get_image_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_image\")\n{\n\tget_image_op = Operator \"get_image\" get_image \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_number x = is_number x || is_Real x;\n\nget_number x\n\t= x.value, is_Real x\n\t= x, is_number x \n\t= oo_unary_function get_number_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_number\")\n{\n\tget_number_op = Operator \"get_number\" get_number \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_real x = is_real x || is_Real x;\n\nget_real x\n\t= x.value, is_Real x\n\t= x, is_real x\n\t= oo_unary_function get_real_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_real\")\n{\n\tget_real_op = Operator \"get_real\" get_real \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_width x = has_member \"width\" x || is_image x;\n\nget_width x\n\t= x.width, has_member \"width\" x\n\t= get_header \"Xsize\" x, is_image x\n\t= oo_unary_function get_width_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_width\")\n{\n\tget_width_op = Operator \"get_width\" get_width \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_height x = has_member \"height\" x || is_image x;\n\nget_height x\n\t= x.height, has_member \"height\" x\n\t= get_header \"Ysize\" x, is_image x\n\t= oo_unary_function get_height_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_height\")\n{\n\tget_height_op = Operator \"get_height\" get_height \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_left x = has_member \"left\" x;\n\nget_left x\n\t= x.left, has_member \"left\" x\n\t= oo_unary_function get_left_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_left\")\n{\n\tget_left_op = Operator \"get_left\" get_left \n\t\tOperator_type.COMPOUND false;\n}\n\nhas_top x = has_member \"top\" x;\n\nget_top x\n\t= x.top, has_member \"top\" x\n\t= oo_unary_function get_top_op x, is_class x\n\t= error (_ \"bad arguments to \" ++ \"get_top\")\n{\n\tget_top_op = Operator \"get_top\" get_top \n\t\tOperator_type.COMPOUND false;\n}\n\n// like has/get member, but first in a lst of objects\nhas_member_list has objects\n\t= filter has objects != [];\n\n// need one with the args swapped\nget_member = converse dot;\n\n// get a member from the first of a list of objects to have it\nget_member_list has get objects\n\t= hd members, members != []\n\t= error \"unable to get property\"\n{\n\tmembers = map get (filter has objects);\n}\n\nis_hist x\n\t= has_image x && (h == 1 || w == 1 || t == Image_type.HISTOGRAM)\n{\n\tim = get_image x;\n\tw = get_width im;\n\th = get_height im;\n\tt = get_type im;\n}\n\nget_header field x\n\t= oo_unary_function get_header_op x, is_class x\n\t= get_header_image x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header\")\n{\n\tget_header_op = Operator \"get_header\" (get_header field)\n\t\tOperator_type.COMPOUND false;\n\tget_header_image im\n\t\t= im_header_int field im, type == itype\n\t\t= im_header_double field im, type == dtype\n\t\t= im_header_string field im, type == stype1 || type == stype2\n\t\t= error (_ \"image has no field \" ++ field), type == 0\n\t\t= error (_ \"unknown type for field \" ++ field)\n\t{\n\t\ttype = im_header_get_typeof field im;\n\n\t\titype = name2gtype \"gint\";\n\t\tdtype = name2gtype \"gdouble\";\n\t\tstype1 = name2gtype \"VipsRefString\";\n\t\tstype2 = name2gtype \"gchararray\";\n\t}\n}\n\nget_header_type field x\n\t= oo_unary_function get_header_type_op x, is_class x\n\t= im_header_get_typeof field x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"get_header_type\")\n{\n\tget_header_type_op = Operator \"get_header_type\" (get_header_type field)\n\t\tOperator_type.COMPOUND false;\n}\n\nset_header field value x\n\t= oo_unary_function set_header_op x, is_class x\n\t= im_copy_set_meta x field value, is_image x\n\t= error (_ \"bad arguments to \" ++ \"set_header\")\n{\n\tset_header_op = Operator \"set_header\" (set_header field value)\n\t\tOperator_type.COMPOUND false;\n}\n"
  },
  {
    "path": "share/nip2/start/_stdenv.def",
    "content": "/* optional args to functions\n */\n\nget_option options defaults f\n\t= error (_ \"unknown parameter \" ++ f), hits == []\n\t= hits?0\n{\n\thits = [v :: [n, v] <- options ++ defaults; n == f];\n}\n\n/* Various operators as functions.\n */\n\nlogical_and a b = a && b;\nlogical_or a b = a || b;\nbitwise_and a b = a & b;\nbitwise_or a b = a | b;\neor a b = a ^ b;\nleft_shift a b = a << b;\nright_shift a b = a >> b;\nnot a = !a;\n\nless a b = a < b;\nmore a b = a > b;\nless_equal a b = a <= b;\nmore_equal a b = a >= b;\nequal a b = a == b;\nnot_equal a b = a != b;\npointer_equal a b = a === b;\nnot_pointer_equal a b = a !== b;\n\nadd a b = a + b;\nsubtract a b = a - b;\nmultiply a b = a * b;\ndivide a b = a / b;\nidivide a b = (int) ((int) a / (int) b);\npower a b = a ** b;\nsquare x = x * x;\nremainder a b = a % b;\n\ncons a b = a : b;\ndot a b = a . ( b );\njoin a b = a ++ b;\n// 'difference' is defined in _list\nsubscript a b = a ? b;\n\ngenerate s n f = [s, n .. f];\ncomma r i = (r, i);\n\ncompose f g = f @ g;\n\n// our only trinary operator is actually a binary operator\nif_then_else a x = if a then x?0 else x?1;\n\ncast_unsigned_char x = (unsigned char) x;\ncast_signed_char x = (signed char) x;\ncast_unsigned_short x = (unsigned short) x;\ncast_signed_short x = (signed short) x;\ncast_unsigned_int x = (unsigned int) x;\ncast_signed_int x = (signed int) x;\ncast_float x = (float) x;\ncast_double x = (double) x;\ncast_complex x = (complex) x;\ncast_double_complex x = (double complex) x;\n\nunary_minus x = -x;\nnegate x = !x;\ncomplement x = ~x;\nunary_plus x = +x;\n\n// the function we call for \"a -> v\" expressions\nmksvpair s v\n\t= [s, v], is_string s\n\t= error \"not str on lhs of ->\";\n\n// the vector ops ... im is an image, vec is a real_list\nvec op_name im vec\n\t= im_lintra_vec ones im vec,\n\t\top_name == \"add\" || op_name == \"add'\"\n\t= im_lintra_vec ones (-1 * im) vec,\n\t\top_name == \"subtract'\" \n\t= im_lintra_vec ones im inv,\n\t\top_name == \"subtract\" \n\t= im_lintra_vec vec im zeros,\n\t\top_name == \"multiply\" || op_name == \"multiply'\"\n\t= im_lintra_vec vec (1 / im) zeros,\n\t\top_name == \"divide'\" \n\t= im_lintra_vec recip im zeros,\n\t\top_name == \"divide\" \n\t= im_expntra_vec im vec,\n\t\top_name == \"power'\" \n\t= im_powtra_vec im vec,\n\t\top_name == \"power\" \n\t= im_remainderconst_vec im vec,\n\t\top_name == \"remainder\" \n\t= im_andimage_vec im vec,\n\t\top_name == \"bitwise_and\" || op_name == \"bitwise_and'\"\n\t= im_orimage_vec im vec,\n\t\top_name == \"bitwise_or\" || op_name == \"bitwise_or'\"\n\t= im_eorimage_vec im vec,\n\t\top_name == \"eor\" || op_name == \"eor'\"\n\t= im_equal_vec im vec,\n\t\top_name == \"equal\" || op_name == \"equal'\"\n\t= im_notequal_vec im vec,\n\t\top_name == \"not_equal\" || op_name == \"not_equal'\"\n\t= im_less_vec im vec,\n\t\top_name == \"less\" \n\t= im_moreeq_vec im vec,\n\t\top_name == \"less'\" \n\t= im_lesseq_vec im vec,\n\t\top_name == \"less_equal\" \n\t= im_more_vec im vec,\n\t\top_name == \"less_equal'\" \n\t= error (\"unimplemented vector operation: \" ++ op_name)\n{\n\tzeros = replicate (len vec) 0;\n\tones = replicate (len vec) 1;\n\trecip = map (divide 1) vec;\n\tinv = map (multiply (-1)) vec;\n}\n\n// make a name value pair\nmknvpair n v\n\t= [n, v], is_string n\n\t= error \"not [char] on LHS of =>\";\n\n/* Macbeth chart patch names.\n */\nmacbeth_names = [\n\t\"Dark skin\",\n\t\"Light skin\",\n\t\"Blue sky\",\n\t\"Foliage\",\n\t\"Blue flower\",\n\t\"Bluish green\",\n\t\"Orange\",\n\t\"Purplish blue\",\n\t\"Moderate red\",\n\t\"Purple\",\n\t\"Yellow green\",\n\t\"Orange yellow\",\n\t\"Blue\",\n\t\"Green\",\n\t\"Red\",\n\t\"Yellow\",\n\t\"Magenta\",\n\t\"Cyan\",\n\t\"White (density 0.05)\",\n\t\"Neutral 8 (density 0.23)\",\n\t\"Neutral 6.5 (density 0.44)\",\n\t\"Neutral 5 (density 0.70)\",\n\t\"Neutral 3.5 (density 1.05)\",\n\t\"Black (density 1.50)\"\n];\n\nbandsplit x \n\t= oo_unary_function bandsplit_op x, is_class x\n\t= map (subscript x) [0 .. bands - 1], is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandsplit\")\n{\n\tbands = get_header \"Bands\" x;\n\tbandsplit_op = Operator \"bandsplit\" (map Image @ bandsplit)\n\t\tOperator_type.COMPOUND false;\n}\n\nbandjoin l\n\t= wrapper joined, has_wrapper\n\t= joined, is_listof has_image l\n\t= error (_ \"bad arguments to \" ++ \"bandjoin\")\n{\n\thas_wrapper = has_member_list (has_member \"Image\") l;\n\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\tjoined = im_gbandjoin (map get_image l);\n}\n\nbandand x\n\t= oo_unary_function bandand_op x, is_class x\n\t= foldr1 bitwise_and (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandand\")\n{\n\tbandand_op = Operator \"bandand\" bandand Operator_type.COMPOUND_REWRAP false;\n}\n\nbandor x\n\t= oo_unary_function bandor_op x, is_class x\n\t= foldr1 bitwise_or (bandsplit x), is_image x\n\t= error (_ \"bad arguments to \" ++ \"bandor\")\n{\n\tbandor_op = Operator \"bandor\" bandor Operator_type.COMPOUND_REWRAP false;\n}\n\nsum x\n\t= oo_unary_function sum_op x, is_class x\n\t= im_avg x * (get_width x) * (get_height x) * (get_bands x), is_image x\n\t= sum_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"sum\")\n{\n\tsum_op = Operator \"sum\" sum Operator_type.COMPOUND false;\n\n\t// add elements in a nested-list thing\n\tsum_list l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n}\n\nproduct x\n\t= oo_unary_function product_op x, is_class x\n\t= product_list x, is_list x \n\t// (product image) doesn't make much sense :(\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"product\")\n{\n\tproduct_op = Operator \"product\" product Operator_type.COMPOUND false;\n\n\tproduct_list l\n\t\t= foldr prod 1 l\n\t{\n\t\tprod x total\n\t\t\t= total * product x, is_list x\n\t\t\t= total * x;\n\t}\n}\n\nmean x\n\t= oo_unary_function mean_op x, is_class x\n\t= im_avg x, is_image x\n\t= mean_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"mean\")\n{\n\tmean_op = Operator \"mean\" mean Operator_type.COMPOUND false;\n\n\tmean_list l = sum l / size l;\n\n\t// number of elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1;\n\t}\n}\n\nmeang x \n\t= (appl (power e) @ mean @ appl log) x\n{\n\tappl fn x\n\t\t= map fn x, is_list x\n\t\t= fn x;\n}\n\nskew x\n\t= oo_unary_function skew_op x, is_class x\n\t= sum ((x - m) ** 3) / ((N - 1) * s ** 3), is_image x \n\t= sum ((Group x' - m) ** 3).value / ((N - 1) * s ** 3), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"skew\")\n{\n\tskew_op = Operator \"skew\" skew Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN \n\t\t= w * h * b, is_image x'\n\t\t= len x';\n}\n\nkurtosis x\n\t= oo_unary_function kurtosis_op x, is_class x\n\t= sum ((x - m) ** 4) / ((N - 1) * s ** 4), is_image x \n\t= sum ((Group x' - m) ** 4).value / ((N - 1) * s ** 4), is_list x\n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"kurtosis\")\n{\n\tkurtosis_op = Operator \"kurtosis\" kurtosis Operator_type.COMPOUND false;\n\n\t// squash any large matrix down to a flat list ... much simpler\n\tx' \n\t\t= x, is_image x;\n\t\t= flatten x;\n\n\tm = mean x';\n\ts = deviation x';\n\tw = get_width x';\n\th = get_height x';\n\tb = get_bands x';\n\n\tN\n\t\t= len x', is_list x';\n\t\t= w * h * b;\n}\n\n// zero-excluding mean\nmeanze x\n\t= oo_unary_function meanze_op x, is_class x\n\t= meanze_image_hist x, is_image x && \n\t\t(fmt == Image_format.UCHAR || fmt == Image_format.USHORT)\n\t= meanze_image x, is_image x\n\t= meanze_list x, is_list x \n\t= error (_ \"bad arguments (\" ++ print x ++ \") to \" ++ \"meanze\")\n{\n\tfmt = get_format x;\n\n\tmeanze_op = Operator \"meanze\" meanze Operator_type.COMPOUND false;\n\n\tmeanze_list l = sum l / size l;\n\n\t// number of non-zero elements in some sort of nested-list thing\n\tsize l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + size x, is_list x\n\t\t\t= total + 1, x != 0;\n\t\t\t= total;\n\t}\n\n\t// add elements in a nested-list thing\n\tsum l\n\t\t= foldr acc 0 l\n\t{\n\t\tacc x total\n\t\t\t= total + sum x, is_list x\n\t\t\t= total + x;\n\t}\n\n\t// image mean, for any image type\n\tmeanze_image i\n\t\t= sum / N\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n\n\t// image mean for 8 and 16-bit unsigned images\n\t// we can use a histogram, yay, and save a pass through the image\n\tmeanze_image_hist i\n\t\t= sum / N\n\t{\n\t\t// histogram, knock out zeros\n\t\thist = hist_find i;\n\t\tblack = image_new 1 1 (get_bands hist) \n\t\t\t(get_format hist) (get_coding hist) (get_type hist) 0 0 0;\n\t\thistze = insert 0 0 black hist;\n\n\t\t// matching identity\n\t\tiden\n\t\t\t= im_identity_ushort (get_bands hist) (get_width hist),\n\t\t\t\t(get_width hist) > 256\n\t\t\t= im_identity (get_bands hist);\n\n\t\t// number of non-zero pixels\n\t\tN = mean histze * 256;\n\n\t\t// sum of pixels\n\t\tsum = mean (hist * iden) * 256;\n\t}\n}\n\ndeviation x\n\t= oo_unary_function deviation_op x, is_class x\n\t= im_deviate x, is_image x\n\t= deviation_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviation\")\n{\n\tdeviation_op = Operator \"deviation\" \n\t\tdeviation Operator_type.COMPOUND false;\n\n\tdeviation_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return n, sum, sum of squares for a list of reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x\n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n}\n\ndeviationze x\n\t= oo_unary_function deviationze_op x, is_class x\n\t= deviationze_image x, is_image x\n\t= deviationze_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"deviationze\")\n{\n\tdeviationze_op = Operator \"deviationze\" \n\t\tdeviationze Operator_type.COMPOUND false;\n\n\tdeviationze_list l \n\t\t= (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5\n\t{\n\t\t[n, s, s2] = sum_sum2_list l;\n\t}\n\n\t// return number of non-zero elements, sum, sum of squares for a list of \n\t// reals\n\tsum_sum2_list x\n\t\t= foldr accumulate [0, 0, 0] x\n\t{\n\t\taccumulate x sofar\n\t\t\t= sofar, is_real x && x == 0\n\t\t\t= [n + 1, x + s, x * x + s2], is_real x \n\t\t\t= [n + n', s + s', s2 + s2'], is_list x\n\t\t\t= error \"sum_sum2_list: not real or [real]\"\n\t\t{\n\t\t\t[n, s, s2] = sofar;\n\t\t\t[n', s', s2'] = sum_sum2_list x;\n\t\t}\n\t}\n\t\n\tdeviationze_image i\n\t\t= ((sum2 - sum * sum / N) / (N - 1)) ** 0.5\n\t{\n\t\tw = get_width i;\n\t\th = get_height i;\n\t\tb = get_bands i;\n\n\t\tst = stats i;\n\t\tsum = st.value?0?2;\n\t\tsum2 = st.value?0?3;\n\n\t\t// find non-zero pixels (not zero in all bands)\n\t\tzp = im_notequal_vec i (replicate b 0);\n\n\t\t// number of non-zero pixels\n\t\tN = b * (mean zp * w * h) / 255;\n\t}\n}\n\n// find the centre of gravity of a histogram\ngravity x\n\t= oo_unary_function gravity_op x, is_class x\n\t= im_hist_gravity x, is_hist x\n\t= gravity_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"gravity\")\n{\n\tgravity_op = Operator \"gravity\" gravity Operator_type.COMPOUND false;\n\n\t// centre of gravity of a histogram... use the histogram to weight an \n\t// identity, then sum, then find the mean element\n\tim_hist_gravity h\n\t\t= m\n\t{\n\t\t// make horizontal\n\t\th'\n\t\t\t= rot270 h, get_width h == 1\n\t\t\t= h, get_height h == 1\n\t\t\t= error \"width or height not 1\";\n\n\t\t// number of elements\n\t\tw = get_width h';\n\n\t\t// matching identity\n\t\ti \n\t\t\t= im_identity_ushort 1 w, w <= 2 ** 16 - 1\n\t\t\t= make_xy w 1 ? 0;\n\n\t\t// weight identity and sum\n\t\ts = mean (i * h') * w;\n\n\t\t// sum of original histogram \n\t\ts' = mean h * w;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n\n\tgravity_list l\n\t\t= m\n\t{\n\t\tw = len l;\n\n\t\t// matching identity\n\t\ti = [0, 1 .. w - 1];\n\n\t\t// weight identity and sum\n\t\ts = sum (map2 multiply i l);\n\n\t\t// sum of original histogram \n\t\ts' = sum l;\n\n\t\t// weighted mean \n\t\tm = s / s';\n\t}\n}\n\nproject x\n\t= oo_unary_function project_op x, is_class x\n\t= im_project x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"project\")\n{\n\tproject_op = Operator \"project\" project Operator_type.COMPOUND false;\n}\n\nabs x\n\t= oo_unary_function abs_op x, is_class x\n\t= im_abs x, is_image x\n\t= abs_cmplx x, is_complex x\n\t= abs_num x, is_real x\n\t= abs_list x, is_real_list x\n\t= abs_list (map abs_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs\")\n{\n\tabs_op = Operator \"abs\" abs Operator_type.COMPOUND false;\n\n\tabs_list l = (sum (map square l)) ** 0.5;\n\n\tabs_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n}\n\ncopy x\n\t= oo_unary_function copy_op x, is_class x\n\t= im_copy x, is_image x\n\t= x\n{\n\tcopy_op = Operator \"copy\" copy Operator_type.COMPOUND_REWRAP false;\n}\n\n// like abs, but treat pixels as vectors ... ie. always get a 1-band image\n// back ... also treat matricies as lists of vectors\n// handy for dE from object difference\nabs_vec x\n\t= oo_unary_function abs_vec_op x, is_class x\n\t= abs_vec_image x, is_image x\n\t= abs_vec_cmplx x, is_complex x\n\t= abs_vec_num x, is_real x\n\t= abs_vec_list x, is_real_list x\n\t= mean (map abs_vec_list x), is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"abs_vec\")\n{\n\tabs_vec_op = Operator \"abs_vec\" \n\t\tabs_vec Operator_type.COMPOUND false;\n\n\tabs_vec_list l = (sum (map square l)) ** 0.5;\n\n\tabs_vec_num n\n\t\t= n, n >= 0\n\t\t= -n;\n\n\tabs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;\n\n\tabs_vec_image im \n\t\t= (sum (map square (bandsplit im))) ** 0.5;\n}\n\ntranspose x\n\t= oo_unary_function transpose_op x, is_class x\n\t= transpose_image x, is_image x\n\t= transpose_list x, is_listof is_list x\n\t= error (_ \"bad arguments to \" ++ \"transpose\")\n{\n\ttranspose_op = Operator \"transpose\" \n\t\ttranspose Operator_type.COMPOUND_REWRAP false;\n\n\ttranspose_list l\n\t\t= [], l' == []\n\t\t= (map hd l') : (transpose_list (map tl l'))\n\t{\n\t\tl' = takewhile (not_equal []) l;\n\t}\n\n\ttranspose_image = im_flipver @ im_rot270;\n}\n\nrot45 x\n\t= oo_unary_function rot45_op x, is_class x\n\t= error \"rot45 image: not implemented\", is_image x \n\t= error (_ \"bad arguments to \" ++ \"rot45\")\n{\n\trot45_op = Operator \"rot45\" \n\t\trot45_object Operator_type.COMPOUND_REWRAP false;\n\n\trot45_object x\n\t\t= rot45_matrix x, is_odd_square_matrix x\n\t\t= error \"rot45 image: not implemented\", is_image x \n\t\t= error (_ \"bad arguments to \" ++ \"rot45\");\n\n\t// slow, but what the heck\n\trot45_matrix l = (im_rotate_dmask45 (Matrix l)).value;\n}\n\n// apply an image function to a [[real]] ... matrix is converted to a 1 band\n// image for processing\napply_matrix_as_image fn m\n\t= (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m;\n\n// a general image/matrix operation where the mat version is most easily done\n// by converting mat->image->mat\napply_matim_operation name fn x\n\t= oo_unary_function class_op x, is_class x\n\t= fn x, is_image x\n\t= apply_matrix_as_image fn x, is_matrix x\n\t= error (_ \"bad arguments to \" ++ name)\n{\n\tclass_op = Operator name\n\t\t(apply_matim_operation name fn) Operator_type.COMPOUND_REWRAP false;\n}\n\nrot90 = apply_matim_operation \"rot90\" im_rot90;\nrot180 = apply_matim_operation \"rot180\" im_rot180;\nrot270 = apply_matim_operation \"rot270\" im_rot270;\nrotquad = apply_matim_operation \"rotquad\" im_rotquad;\nfliplr = apply_matim_operation \"fliplr\" im_fliphor;\nfliptb = apply_matim_operation \"flipud\" im_flipver;\n\nimage_set_type type x \n\t= oo_unary_function image_set_type_op x, is_class x\n\t= im_copy_set x (to_real type) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(get_header \"Xoffset\" x) (get_header \"Yoffset\" x),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_type:\" ++ \n\t\tprint type ++ \" \" ++ print x)\n{\n\timage_set_type_op = Operator \"image_set_type\" \n\t\t(image_set_type type) Operator_type.COMPOUND_REWRAP false;\n}\n\nimage_set_origin xoff yoff x \n\t= oo_unary_function image_set_origin_op x, is_class x\n\t= im_copy_set x \n\t\t(get_header \"Type\" x) \n\t\t(get_header \"Xres\" x) (get_header \"Yres\" x)\n\t\t(to_real xoff) (to_real yoff),\n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"image_set_origin\")\n{\n\timage_set_origin_op = Operator \"image_set_origin\" \n\t\t(image_set_origin xoff yoff) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ncache tile_width tile_height max_tiles x\n\t= oo_unary_function cache_op x, is_class x\n\t= im_tile_cache_random x (to_real tile_width) (to_real tile_height) \n\t\t(to_real max_tiles), is_image x\n\t= error (_ \"bad arguments to \" ++ \"cache\")\n{\n\tcache_op = Operator \"cache\" \n\t\t(cache tile_width tile_height max_tiles) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntile across down x\n\t= oo_unary_function tile_op x, is_class x\n\t= im_replicate x (to_real across) (to_real down), is_image x\n\t= error (_ \"bad arguments to \" ++ \"tile\")\n{\n\ttile_op = Operator \"tile\" \n\t\t(tile across down) Operator_type.COMPOUND_REWRAP false;\n}\n\ngrid tile_height across down x\n\t= oo_unary_function grid_op x, is_class x\n\t= im_grid x (to_real tile_height) (to_real across) (to_real down), \n\t\tis_image x\n\t= error (_ \"bad arguments to \" ++ \"grid\")\n{\n\tgrid_op = Operator \"grid\" \n\t\t(grid tile_height across down) Operator_type.COMPOUND_REWRAP false;\n}\n\nmax_pair a b\n\t= a, a > b\n\t= b;\n\nmin_pair a b\n      =\ta, a < b\n      =\tb;\n\nrange min value max = min_pair max (max_pair min value);\n\nmax x\n\t= oo_unary_function max_op x, is_class x\n\t= im_max x, is_image x\n\t= max_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"max\")\n{\n\tmax_op = Operator \"max\" max Operator_type.COMPOUND false;\n\n\tmax_list x\n\t\t= error \"max []\", x == []\n\t\t= foldr1 max_pair x, is_real_list x\n\t\t= foldr1 max_pair (map max_list x), is_list x\n\t\t= max x;\n}\n\nmin x\n\t= oo_unary_function min_op x, is_class x\n\t= im_min x, is_image x\n\t= min_list x, is_list x \n\t= x, is_number x\n\t= error (_ \"bad arguments to \" ++ \"min\")\n{\n\tmin_op = Operator \"min\" min Operator_type.COMPOUND false;\n\n\tmin_list x\n\t\t= error \"min []\", x == []\n\t\t= foldr1 min_pair x, is_real_list x\n\t\t= foldr1 min_pair (map min_list x), is_list x\n\t\t= min x;\n}\n\nmaxpos x\n\t= oo_unary_function maxpos_op x, is_class x\n\t= im_maxpos x, is_image x\n\t= maxpos_matrix x, is_matrix x\n\t= maxpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"maxpos\")\n{\n\tmaxpos_op = Operator \"maxpos\" maxpos Operator_type.COMPOUND false;\n\n\tmaxpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmax_value = max (Matrix m);\n\t\tindexes = map (index (equal max_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tmaxpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (max l)) l;\n}\n\nminpos x\n\t= oo_unary_function minpos_op x, is_class x\n\t= im_minpos x, is_image x\n\t= minpos_matrix x, is_matrix x\n\t= minpos_list x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"minpos\")\n{\n\tminpos_op = Operator \"minpos\" minpos Operator_type.COMPOUND false;\n\n\tminpos_matrix m \n\t\t= (-1, -1), m == [[]]\n\t\t= (indexes?row, row)\n\t{\n\t\tmin_value = min (Matrix m);\n\t\tindexes = map (index (equal min_value)) m;\n\t\trow = index (not_equal (-1)) indexes;\n\t}\n\n\tminpos_list l \n\t\t= -1, l == []\n\t\t= index (equal (min l)) l;\n}\n\nstats x\n\t= oo_unary_function stats_op x, is_class x\n\t= im_stats x, is_image x\n\t= im_stats (to_image x).value, is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"stats\")\n{\n\tstats_op = Operator \"stats\" \n\t\tstats Operator_type.COMPOUND false;\n}\n\ne = 2.7182818284590452354;\n\npi = 3.14159265358979323846;\n\nrad d = 2 * pi * (d / 360);\n\ndeg r = 360 * r / (2 * pi);\n\nsign x\n\t= oo_unary_function sign_op x, is_class x\n\t= im_sign x, is_image x\n\t= sign_cmplx x, is_complex x\n\t= sign_num x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"sign\")\n{\n\tsign_op = Operator \"sign\" sign Operator_type.COMPOUND_REWRAP false;\n\n\tsign_num n\n\t\t= 0, n == 0\n\t\t= 1, n > 0\n\t\t= -1;\n\n\tsign_cmplx c \n\t\t= (0, 0), mod == 0\n\t\t= (re c / mod, im c / mod)\n\t{\n\t\tmod = abs c;\n\t}\n}\n\nrint x\n\t= oo_unary_function rint_op x, is_class x\n\t= im_rint x, is_image x \n\t= rint_value x, is_number x \n\t= error (_ \"bad arguments to \" ++ \"rint\")\n{\n\trint_op = Operator \"rint\" rint Operator_type.ARITHMETIC false;\n\n\trint_value x\n\t\t= (int) (x + 0.5), x > 0\n\t\t= (int) (x - 0.5);\n}\n\nscale x\n\t= oo_unary_function scale_op x, is_class x\n\t= (unsigned char) x, is_number x \n\t= im_scale x, is_image x \n\t= scale_list x, is_real_list x || is_matrix x\n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scale\" scale Operator_type.COMPOUND_REWRAP false;\n\n\tscale_list l\n\t\t= apply_scale s o l\n\t{\n\t\tmn = find_limit min_pair l;\n\t\tmx = find_limit max_pair l;\n\t\ts = 255.0 / (mx - mn);\n\t\to = -(mn * s);\n\t}\n\n\tfind_limit fn l\n\t\t= find_limit fn (map (find_limit fn) l), is_listof is_list l\n\t\t= foldr1 fn l;\n\n\tapply_scale s o x\n\t\t= x * s + o, is_number x\n\t\t= map (apply_scale s o) x;\n}\n\nscaleps x\n\t= oo_unary_function scale_op x, is_class x\n\t= im_scaleps x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"scale\")\n{\n\tscale_op = Operator \"scaleps\" \n\t\tscaleps Operator_type.COMPOUND_REWRAP false;\n}\n\nfwfft x\n\t= oo_unary_function fwfft_op x, is_class x\n\t= im_fwfft x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"fwfft\")\n{\n\tfwfft_op = Operator \"fwfft\" \n\t\tfwfft Operator_type.COMPOUND_REWRAP false;\n}\n\ninvfft x\n\t= oo_unary_function invfft_op x, is_class x\n\t= im_invfftr x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"invfft\")\n{\n\tinvfft_op = Operator \"invfft\" \n\t\tinvfft Operator_type.COMPOUND_REWRAP false;\n}\n\nfalsecolour x\n\t= oo_unary_function falsecolour_op x, is_class x\n\t= image_set_type Image_type.sRGB (im_falsecolour x), is_image x \n\t= error (_ \"bad arguments to \" ++ \"falsecolour\")\n{\n\tfalsecolour_op = Operator \"falsecolour\" \n\t\tfalsecolour Operator_type.COMPOUND_REWRAP false;\n}\n\npolar x\n\t= oo_unary_function polar_op x, is_class x\n\t= im_c2amph x, is_image x\n\t= polar_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"polar\")\n{\n\tpolar_op = Operator \"polar\" polar Operator_type.COMPOUND false;\n\n\tpolar_cmplx r\n\t\t= (l, a)\n\t{\n\t\ta\n\t\t\t= 270, x == 0 && y < 0\n\t\t\t= 90, x == 0 && y >= 0\n\t\t\t= 360 + atan (y / x), x > 0 && y < 0\n\t\t\t= atan (y / x), x > 0 && y >= 0\n\t\t\t= 180 + atan (y / x);\n\n\t\tl = (x ** 2 + y ** 2) ** 0.5;\n\n\t\tx = re r;\n\t\ty = im r;\n\t}\n}\n\nrectangular x\n\t= oo_unary_function rectangular_op x, is_class x\n\t= im_c2rect x, is_image x\n\t= rectangular_cmplx x, is_complex x\n\t= error (_ \"bad arguments to \" ++ \"rectangular\")\n{\n\trectangular_op = Operator \"rectangular\" \n\t\trectangular Operator_type.COMPOUND false;\n\n\trectangular_cmplx p\n\t\t= (x, y)\n\t{\n\t\tl = re p;\n\t\ta = im p;\n\n\t\tx = l * cos a;\n\t\ty = l * sin a;\n\t}\n}\n\n// we can't use colour_unary: that likes 3 band only\nrecomb matrix x\n\t= oo_unary_function recomb_op x, is_class x\n\t= im_recomb x matrix, is_image x\n\t= recomb_real_list x, is_real_list x\n\t= map recomb_real_list x, is_matrix x \n\t= error (_ \"bad arguments to \" ++ \"recomb\")\n{\n\t// COMPOUND_REWRAP ... signal to the colour class to go to image and \n\t// back\n\trecomb_op = Operator \"recomb\" \n\t\t(recomb matrix) Operator_type.COMPOUND_REWRAP false;\n\n\t// process [1,2,3 ..] as an image\n\trecomb_real_list l\n\t\t= (to_matrix im').value?0\n\t{\n\t\tim = (float) (to_image (Vector l)).value;\n\t\tim' = recomb matrix im;\n\t}\n}\n\nextract_area x y w h obj\n\t= oo_unary_function extract_area_op obj, is_class obj\n\t= im_extract_area obj x' y' w' h', is_image obj\n\t= map (extract_range x' w') (extract_range y' h' obj), is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_area\")\n{\n\tx' = to_real x;\n\ty' = to_real y;\n\tw' = to_real w;\n\th' = to_real h;\n\n\textract_area_op = Operator \"extract_area\" (extract_area x y w h)\n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\textract_range from length list\n\t\t= (take length @ drop from) list;\n}\n\nextract_band b obj = subscript obj b;\n\nextract_row y obj\n\t= oo_unary_function extract_row_op obj, is_class obj\n\t= extract_area 0 y' (get_width obj) 1 obj, is_image obj\n\t= [obj?y'], is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_row\")\n{\n\ty' = to_real y;\n\n\textract_row_op = Operator \"extract_row\" (extract_row y)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nextract_column x obj\n\t= oo_unary_function extract_column_op obj, is_class obj\n\t= extract_area x' 0 1 height obj, is_image obj\n\t= map (\\row [row?x']) obj, is_matrix obj\n\t= error (_ \"bad arguments to \" ++ \"extract_column\")\n{\n\tx' = to_real x;\n\theight = get_header \"Ysize\" obj;\n\n\textract_column_op = Operator \"extract_column\" (extract_column x)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nblend cond in1 in2\n\t= oo_binary_function blend_op cond [in1,in2], is_class cond\n\t= im_blend (get_image cond) (get_image in1) (get_image in2),\n\t\thas_image cond && has_image in1 && has_image in2\n\t= error (_ \"bad arguments to \" ++ \"blend\" ++ \": \" ++\n\t\tjoin_sep \", \" (map print [cond, in1, in2]))\n{\n\tblend_op = Operator \"blend\" \n\t\tblend_obj Operator_type.COMPOUND_REWRAP false;\n\n\tblend_obj cond x\n\t\t= blend_result_image\n\t{\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, cond];\n\n\t\t// properties of our output image\n\t\ttarget_width = get_member_list has_width get_width objects;\n\t\ttarget_height = get_member_list has_height get_height objects;\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_format = get_member_list has_format get_format objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\tto_image x \n\t\t\t= to_image_size target_width target_height \n\t\t\t\ttarget_bands target_format x;\n\n\t\t[then_image, else_image] = map to_image [then_part, else_part];\n\n\t\tblend_result_image = image_set_type target_type \n\t\t\t(im_blend cond then_image else_image);\n\t}\n}\n\n// do big first: we want to keep big's class, if possible\n// eg. big is a Plot, small is a 1x1 Image\ninsert x y small big\n\t= oo_binary'_function insert_op small big, is_class big\n\t= oo_binary_function insert_op small big, is_class small\n\t= im_insert big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert\")\n{\n\tinsert_op = Operator \"insert\" \n\t\t(insert x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ninsert_noexpand x y small big\n\t= oo_binary_function insert_noexpand_op small big, is_class small\n\t= oo_binary'_function insert_noexpand_op small big, is_class big\n\t= im_insert_noexpand big small (to_real x) (to_real y), \n\t\tis_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"insert_noexpand\")\n{\n\tinsert_noexpand_op = Operator \"insert_noexpand\" \n\t\t(insert_noexpand x y) Operator_type.COMPOUND_REWRAP false;\n}\n\ndecode im\n\t= oo_unary_function decode_op im, is_class im\n\t= decode_im im, is_image im\n\t= error (_ \"bad arguments to \" ++ \"decode\")\n{\n\tdecode_op = Operator \"decode\" \n\t\tdecode Operator_type.COMPOUND_REWRAP false;\n\n\tdecode_im im\n\t\t= im_LabQ2Lab im, get_coding im == Image_coding.LABPACK\n\t\t= im_rad2float im, get_coding im == Image_coding.RAD\n\t\t= im;\n}\n\nmeasure_draw across down measure image\n    = mark\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n\n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::  \n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n    x = map (extract 0) cods;\n    y = map (extract 1) cods;\n\n    outer = mkim [$pixel => 255] sample_width sample_height 1;\n    inner = mkim [] (sample_width - 4) (sample_height - 4) 1;\n    patch = insert 2 2 inner outer;\n\n    bg = mkim [] image.width image.height 1;\n\n    mask = Image (im_insertset bg.value patch.value x y);\n\n    image' = colour_transform_to Image_type.sRGB image;\n\n    mark = if mask then Vector [0, 255, 0] else image';\n}\n\nmeasure_sample across down measure image\n    = measures\n{\n    patch_width = image.width / across;\n    sample_width = patch_width * (measure / 100);\n    left_margin = (patch_width - sample_width) / 2;\n    patch_height = image.height / down;\n    sample_height = patch_height * (measure / 100);\n    top_margin = (patch_height - sample_height) / 2;\n                \n    cods = [[x * patch_width + left_margin, y * patch_height + top_margin] ::\n        y <- [0 .. down - 1]; x <- [0 .. across - 1]];\n\n\timage' = decode image;\n    patches = map (\\p extract_area p?0 p?1 sample_width sample_height image') \n\t\tcods;\n    measures = Matrix (map (map mean) (map bandsplit patches));\n}\n\nextract_bands b n obj \n\t= oo_unary_function extract_bands_op obj, is_class obj\n\t= im_extract_bands obj (to_real b) (to_real n), is_image obj\n\t= error (_ \"bad arguments to \" ++ \"extract_bands\")\n{\n\textract_bands_op = Operator \"extract_bands\" \n\t\t(extract_bands b n) Operator_type.COMPOUND_REWRAP false;\n}\n\ninvert x\n\t= oo_unary_function invert_op x, is_class x\n\t= im_invert x, is_image x\n\t= 255 - x, is_real x\n\t= error (_ \"bad arguments to \" ++ \"invert\")\n{\n\tinvert_op = Operator \"invert\" invert Operator_type.COMPOUND false;\n}\n\ntransform ipol wrap params image\n\t= oo_unary_function transform_op image, is_class image\n\t= im_transform image \n\t\t(to_matrix params) (to_real ipol) (to_real wrap), is_image image\n\t= error (_ \"bad arguments to \" ++ \"transform\")\n{\n\ttransform_op = Operator \"transform\" \n\t\t(transform ipol wrap params) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntransform_search max_error max_iterations order ipol wrap sample reference\n\t= oo_binary_function transform_search_op sample reference, is_class sample\n\t= oo_binary'_function transform_search_op sample reference, \n\t\tis_class reference\n\t= im_transform_search sample reference\n\t\t(to_real max_error) (to_real max_iterations) (to_real order) \n\t\t(to_real ipol) (to_real wrap), \n\t\t\tis_image sample && is_image reference\n\t= error (_ \"bad arguments to \" ++ \"transform_search\")\n{\n\ttransform_search_op = Operator \"transform_search\" \n\t\t(transform_search max_error max_iterations order ipol wrap) \n\t\tOperator_type.COMPOUND false;\n}\n\nrotate interp angle image\n\t= oo_binary_function rotate_op angle image, is_class angle\n\t= oo_binary'_function rotate_op angle image, is_class image\n\t= im_affinei_all image interp.value a (-b) b a 0 0, \n\t\tis_real angle && is_image image \n\t= error (_ \"bad arguments to \" ++ \"rotate\")\n{\n\trotate_op = Operator \"rotate\" \n\t\t(rotate interp) Operator_type.COMPOUND_REWRAP false;\n\ta = cos angle;\n\tb = sin angle;\n}\n\nmatrix_binary fn a b\n\t= itom (fn (mtoi a) (mtoi b))\n{\n\tmtoi x = im_mask2vips (Matrix x);\n\titom x = (im_vips2mask x).value;\n}\n\njoin_lr a b\n\t= oo_binary_function join_lr_op a b, is_class a\n\t= oo_binary'_function join_lr_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_lr\")\n{\n\tjoin_lr_op = Operator \"join_lr\" \n\t\tjoin_lr Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert (get_width a) 0 b a;\n}\n\njoin_tb a b\n\t= oo_binary_function join_tb_op a b, is_class a\n\t= oo_binary'_function join_tb_op a b, is_class b\n\t= join_im a b, is_image a && is_image b \n\t= matrix_binary join_im a b, is_matrix a && is_matrix b \n\t= error (_ \"bad arguments to \" ++ \"join_tb\")\n{\n\tjoin_tb_op = Operator \"join_tb\" \n\t\tjoin_tb Operator_type.COMPOUND_REWRAP false;\n\n\tjoin_im a b\t= insert 0 (get_height a) b a;\n}\n\nconj x\n\t= oo_unary_function conj_op x, is_class x\n\t= (re x, -im x), \n\t\tis_complex x || \n\t\t(is_image x && format == Image_format.COMPLEX) ||\n\t\t(is_image x && format == Image_format.DPCOMPLEX)\n\t// assume it's some sort of real \n\t= x\n{\n\tformat = get_header \"BandFmt\" x;\n\tconj_op = Operator \"conj\" conj Operator_type.COMPOUND false;\n}\n\nclip2fmt format image\n\t= oo_unary_function clip2fmt_op image, is_class image\n\t= im_clip2fmt image (to_real format), is_image image\n\t= error (_ \"bad arguments to \" ++ \"clip2fmt\")\n{\n\tclip2fmt_op = Operator \"clip2fmt\" \n\t\t(clip2fmt format) Operator_type.COMPOUND_REWRAP false;\n}\n\nembed type x y w h im\n\t= oo_unary_function embed_op im, is_class im\n\t= im_embed im (to_real type) \n\t\t(to_real x) (to_real y) (to_real w) (to_real h), is_image im\n\t= error (_ \"bad arguments to \" ++ \"embed\")\n{\n\tembed_op = Operator \"embed\" \n\t\t(embed type x y w h) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it \n * with m1, turn it back to a matrix again.\n */\n_morph_2_masks fn m1 m2\n\t= m''\n{\n\t// The [[real]] can contain 128 values ... squeeze them out!\n\timage = im_mask2vips (Matrix m2) == 255;\n\tm2_width = get_width image;\n\tm2_height = get_height image;\n\n\t// need to embed m2 in an image large enough for us to be able to \n\t// position m1 all around the edges, with a 1 pixel overlap\n\timage' = embed 0 \n\t\t(m1.width / 2) (m1.height / 2) \n\t\t(m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) \n\t\timage;\n\n\t// morph!\n\timage'' = fn m1 image';\n\n\t// back to mask\n\tm' = im_vips2mask ((double) image'');\n\n\t// Turn 0 in output to 128 (don't care).\n\tm'' \n\t\t= map (map fn) m'.value\n\t{\n\t\tfn a\n\t\t\t= 128, a == 0;\n\t\t\t= a;\n\t}\n}\n\ndilate mask image\n\t= oo_unary_function dilate_op image, is_class image\n\t= im_dilate image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"dilate\")\n{\n\tdilate_op = Operator \"dilate\" \n\t\tdilate_object Operator_type.COMPOUND_REWRAP false;\n\t\n\tdilate_object x\n\t\t= _morph_2_masks dilate mask x, is_matrix x\n\t\t= dilate mask x;\n}\n\nerode mask image\n\t= oo_unary_function erode_op image, is_class image\n\t= im_erode image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"erode\")\n{\n\terode_op = Operator \"erode\" \n\t\terode_object Operator_type.COMPOUND_REWRAP false;\n\n\terode_object x\n\t\t= _morph_2_masks erode mask x, is_matrix x\n\t\t= erode mask x;\n}\n\nconv mask image\n\t= oo_unary_function conv_op image, is_class image\n\t= im_conv image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"conv\" ++ \": \" ++ \n\t\t\"conv (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconv_op = Operator \"conv\" \n\t\t(conv mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvf mask image\n\t= oo_unary_function convf_op image, is_class image\n\t= im_conv_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convf\" ++ \": \" ++ \n\t\t\"convf (\" ++ print mask ++ \") (\" ++ print image ++ \")\")\n{\n\tconvf_op = Operator \"convf\" \n\t\t(convf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsep mask image\n\t= oo_unary_function convsep_op image, is_class image\n\t= im_convsep image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsep\")\n{\n\tconvsep_op = Operator \"convsep\" \n\t\t(convsep mask) Operator_type.COMPOUND_REWRAP false;\n}\n\naconvsep layers mask image \n\t= oo_unary_function aconvsep_op image, is_class image\n\t= im_aconvsep image (to_matrix mask) (to_real layers), is_image image\n\t= error (_ \"bad arguments to \" ++ \"aconvsep\")\n{\n\taconvsep_op = Operator \"aconvsep\" \n\t\t(aconvsep layers mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nconvsepf mask image\n\t= oo_unary_function convsepf_op image, is_class image\n\t= im_convsep_f image (to_matrix mask), is_image image\n\t= error (_ \"bad arguments to \" ++ \"convsepf\")\n{\n\tconvsepf_op = Operator \"convsepf\" \n\t\t(convsepf mask) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank w h n image\n\t= oo_unary_function rank_op image, is_class image\n\t= im_rank image (to_real w) (to_real h) (to_real n), is_image image\n\t= error (_ \"bad arguments to \" ++ \"rank\")\n{\n\trank_op = Operator \"rank\" \n\t\t(rank w h n) Operator_type.COMPOUND_REWRAP false;\n}\n\nrank_image n x\n\t= rlist x.value, is_Group x\n\t= rlist x, is_list x\n\t= error (_ \"bad arguments to \" ++ \"rank_image\")\n{\n\trlist l\n\t\t= wrapper ranked, has_wrapper\n\t\t= ranked\n\t{\n\t\thas_wrapper = has_member_list (has_member \"Image\") l;\n\t\twrapper = get_member_list (has_member \"Image\") (get_member \"Image\") l;\n\t\tranked = im_rank_image (map get_image l) (to_real n);\n\t}\n}\n\n// find the correlation surface for a small image within a big one\ncorrelate small big\n\t= oo_binary_function correlate_op small big, is_class small\n\t= oo_binary'_function correlate_op small big, is_class big\n\t= im_spcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate\")\n{\n\tcorrelate_op = Operator \"correlate\" \n\t\tcorrelate Operator_type.COMPOUND_REWRAP false;\n}\n\n// just sum-of-squares-of-differences\ncorrelate_fast small big\n\t= oo_binary_function correlate_fast_op small big, is_class small\n\t= oo_binary'_function correlate_fast_op small big, is_class big\n\t= im_fastcor big small, is_image small && is_image big\n\t= error (_ \"bad arguments to \" ++ \"correlate_fast\")\n{\n\tcorrelate_fast_op = Operator \"correlate_fast\" \n\t\tcorrelate_fast Operator_type.COMPOUND_REWRAP false;\n}\n\n// set Type, wrap as Plot_hist if it's a class\nhist_tag x\n\t= oo_unary_function hist_tag_op x, is_class x\n\t= image_set_type Image_type.HISTOGRAM x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_tag\")\n{\n\thist_tag_op = Operator \"hist_tag\" \n\t\t(Plot_histogram @ hist_tag) Operator_type.COMPOUND false;\n}\n\nhist_find x\n\t= oo_unary_function hist_find_op x, is_class x\n\t= im_histgr x (-1), is_image x\n\t= error (_ \"bad arguments to \" ++ \"hist_find\")\n{\n\thist_find_op = Operator \"hist_find\" \n\t\t(Plot_histogram @ hist_find) Operator_type.COMPOUND false;\n}\n\nhist_find_nD bins image\n\t= oo_unary_function hist_find_nD_op image, is_class image\n\t= im_histnD image (to_real bins), is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_find_nD\")\n{\n\thist_find_nD_op = Operator \"hist_find_nD\" \n\t\t(hist_find_nD bins) Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_find_indexed mode index value\n\t= oo_binary_function hist_find_indexed_op index value, is_class index\n\t= oo_binary'_function hist_find_indexed_op index value, is_class value\n\t= indexed index value, is_image index && is_image value\n\t= error (_ \"bad arguments to \" ++ \"hist_find_indexed\")\n{\n\thist_find_indexed_op = Operator \"hist_find_indexed\" \n\t\t(compose (compose Plot_histogram) (hist_find_indexed mode)) \n\t\t\tOperator_type.COMPOUND false;\n\n\tindexed index value\n\t\t= out\n\t{\n\t\t[out] = vips_call \"hist_find_indexed\" [value, index] [\n\t\t\t\"combine\" => mode\n\t\t];\n\t}\n}\n\nhist_entropy x \n\t= oo_unary_function hist_entropy_op x, is_class x\n\t= entropy x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hist_entropy\")\n{\n\thist_entropy_op = Operator \"hist_entropy\" \n\t\thist_entropy Operator_type.COMPOUND_REWRAP false;\n\n\tentropy x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"hist_entropy\" [x] [\n\t\t];\n\t}\n}\n\nhist_map hist image\n\t= oo_binary_function hist_map_op hist image, is_class hist\n\t= oo_binary'_function hist_map_op hist image, is_class image\n\t= im_maplut image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_map\")\n{\n\t// can't use rewrap, as we want to always wrap as image\n\thist_map_op = Operator \"hist_map\" \n\t\t(compose (compose Image) hist_map) Operator_type.COMPOUND false;\n}\n\nhist_cum hist \n\t= oo_unary_function hist_cum_op hist, is_class hist\n\t= im_histcum hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_cum\")\n{\n\thist_cum_op = Operator \"hist_cum\" \n\t\thist_cum Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_diff hist \n\t= oo_unary_function hist_diff_op hist, is_class hist\n\t= im_histdiff hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_diff\")\n{\n\thist_diff_op = Operator \"hist_diff\" \n\t\thist_diff Operator_type.COMPOUND_REWRAP false;\n\n\tim_histdiff h \n\t\t= (conv (Matrix [[-1, 1]]) @ clip2fmt (fmt (get_format h))) h\n\t{\n\t\t// up the format so it can represent the whole range of\n\t\t// possible values from this mask\n\t\tfmt x\n\t\t\t= Image_format.SHORT, \n\t\t\t\tx == Image_format.UCHAR || x == Image_format.CHAR\n\t\t\t= Image_format.INT, \n\t\t\t\tx == Image_format.USHORT || x == Image_format.SHORT ||\n\t\t\t\tx == Image_format.UINT \n\t\t\t= x;\n\t}\n}\n\nhist_norm hist \n\t= oo_unary_function hist_norm_op hist, is_class hist\n\t= im_histnorm hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_norm\")\n{\n\thist_norm_op = Operator \"hist_norm\" \n\t\thist_norm Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_inv hist \n\t= oo_unary_function hist_inv_op hist, is_class hist\n\t= inv hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_inv\")\n{\n\thist_inv_op = Operator \"hist_inv\" \n\t\thist_inv Operator_type.COMPOUND_REWRAP false;\n\n\tinv im\n\t\t= im_invertlut (to_matrix im''') len\n\t{\n\t\t// need a vertical doublemask\n\t\tim' \n\t\t\t= rot90 im, get_width im > 1 && get_height im == 1 \n\t\t\t= im, get_width im == 1 && get_height im > 1\n\t\t\t= error (_ \"not a hist\");\n\t\tlen = get_height im';\n\n\t\t// values must be scaled to 0 - 1\n\t\tim'' = im' / (max im');\n\t\t\n\t\t// add an index column on the left\n\t\t// again, must be in 0-1\n\t\ty = ((make_xy 1 len)?1) / len;\n\t\tim''' = y ++ im'';\n\t}\n}\n\nhist_match in ref\n\t= oo_binary_function hist_match_op in ref, is_class in\n\t= oo_binary'_function hist_match_op in ref, is_class ref\n\t= im_histspec in ref, is_image in && is_image ref\n\t= error (_ \"bad arguments to \" ++ \"hist_match\")\n{\n\thist_match_op = Operator \"hist_match\" \n\t\thist_match Operator_type.COMPOUND_REWRAP false;\n}\n\nhist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x;\n\nhist_equalize_local w h l image\n\t= oo_unary_function hist_equalize_local_op image, is_class image\n\t= out, is_image image\n\t= error (_ \"bad arguments to \" ++ \"hist_equalize_local\")\n{\n\thist_equalize_local_op = Operator \"hist_equalize_local\" \n\t\t(hist_equalize_local w h l) Operator_type.COMPOUND_REWRAP false;\n\n\t[out] = vips_call \"hist_local\" \n\t\t[image, to_real w, to_real h] [$max_slope => to_real l];\n}\n\n// find the threshold below which are percent of the image (percent in [0,1])\n// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels\nhist_thresh percent image\n\t= x\n{\n\t// our own normaliser ... we don't want to norm channels separately\n\t// norm to [0,1]\n\tmy_hist_norm h = h / max h;\n\n\t// normalised cumulative hist\n\t// we sum the channels before we normalise, because we want to treat them\n\t// all the same\n\th = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) \n\t\timage.value;\n\n\t// threshold that, then use im_profile to search for the x position in the\n\t// histogram\n\tx = mean (im_profile (h > percent) 1);\n}\n\n/* Sometimes useful, despite plotting now being built in, for making\n * diagnostic images.\n */\nhist_plot hist \n\t= oo_unary_function hist_plot_op hist, is_class hist\n\t= im_histplot hist, is_image hist\n\t= error (_ \"bad arguments to \" ++ \"hist_plot\")\n{\n\thist_plot_op = Operator \"hist_plot\" \n\t\t(Image @ hist_plot) Operator_type.COMPOUND false;\n}\n\nzerox d x \n\t= oo_unary_function zerox_op x, is_class x\n\t= im_zerox x (to_real d), is_image x\n\t= error (_ \"bad arguments to \" ++ \"zerox\")\n{\n\tzerox_op = Operator \"zerox\" \n\t\t(zerox d) Operator_type.COMPOUND_REWRAP false;\n}\n\nreduce kernel xshr yshr image\n\t= oo_unary_function reduce_op image, is_class image\n\t= reduce_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"reduce\")\n{\n\treduce_op = Operator \"reduce\" \n\t\treduce_im Operator_type.COMPOUND_REWRAP false;\n\n\treduce_im im \n\t\t= out\n\t{\n\t\t[out] = vips_call \"reduce\" [im, xshr, yshr] [$kernel => kernel.value];\n\t}\n}\n\nsimilarity interpolate scale angle image\n\t= oo_unary_function similarity_op image, is_class image\n\t= similarity_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"similarity\")\n{\n\tsimilarity_op = Operator \"similarity\" \n\t\tsimilarity_im Operator_type.COMPOUND_REWRAP false;\n\n\tsimilarity_im im \n\t\t= out\n\t{\n\t\t[out] = vips_call \"similarity\" [im] [\n\t\t\t$interpolate => interpolate.value,\n\t\t\t$scale => scale,\n\t\t\t$angle => angle\n\t\t];\n\t}\n}\n\nresize kernel xfac yfac image\n\t= oo_unary_function resize_op image, is_class image\n\t= resize_im image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"resize\")\n{\n\tresize_op = Operator \"resize\" \n\t\tresize_im Operator_type.COMPOUND_REWRAP false;\n\n\txfac' = to_real xfac;\n\tyfac' = to_real yfac;\n\n\trxfac' = 1 / xfac';\n\tryfac' = 1 / yfac';\n\n\tis_nn = kernel.type == Kernel_type.NEAREST_NEIGHBOUR;\n\n\tresize_im im\n\t\t// upscale by integer factor, nearest neighbour\n\t\t= im_zoom im xfac' yfac', \n\t\t\tis_int xfac' && is_int yfac' && \n\t\t\txfac' >= 1 && yfac' >= 1 &&\n\t\t\tis_nn \n\n\t\t// downscale by integer factor, nearest neighbour\n\t\t= im_subsample im rxfac' ryfac', \n\t\t\tis_int rxfac' && is_int ryfac' && \n\t\t\trxfac' >= 1 && ryfac' >= 1 &&\n\t\t\tis_nn \n\n\t\t// everything else ... we just pass on to vips_resize()\n\t\t= vips_resize kernel xfac' yfac' im\n\t{\n\t\tvips_resize kernel hscale vscale im \n\t\t\t= out\n\t\t{\n\t\t\t[out] = vips_call \"resize\" [im, hscale] \n\t\t\t\t[$vscale => vscale, $kernel => kernel.value];\n\t\t}\n\t}\n}\n\nsharpen radius x1 y2 y3 m1 m2 in\n\t= oo_unary_function sharpen_op in, is_class in\n\t= im_sharpen in (to_real radius)\n\t\t(to_real x1) (to_real y2) (to_real y3) \n\t\t(to_real m1) (to_real m2), is_image in \n\t= error (_ \"bad arguments to \" ++ \"sharpen\")\n{\n\tsharpen_op = Operator \"sharpen\" \n\t\t(sharpen radius x1 y2 y3 m1 m2) \n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\ntone_analyse s m h sa ma ha in\n\t= oo_unary_function tone_analyse_op in, is_class in\n\t= im_tone_analyse in\n\t\t(to_real s) (to_real m) (to_real h)\n\t\t(to_real sa) (to_real ma) (to_real ha), is_image in \n\t= error (_ \"bad arguments to \" ++ \"tone_analyse\")\n{\n\ttone_analyse_op = Operator \"tone_analyse\" \n\t\t(Plot_histogram @ tone_analyse s m h sa ma ha) \n\t\tOperator_type.COMPOUND false;\n}\n\ntone_map hist image\n\t= oo_binary_function tone_map_op hist image, is_class hist\n\t= oo_binary'_function tone_map_op hist image, is_class image\n\t= im_tone_map image hist, is_image hist && is_image image\n\t= error (_ \"bad arguments to \" ++ \"tone_map\")\n{\n\ttone_map_op = Operator \"tone_map\" \n\t\ttone_map Operator_type.COMPOUND_REWRAP false;\n}\n\ntone_build fmt b w s m h sa ma ha \n\t= (Plot_histogram @ clip2fmt fmt) \n\t\t(im_tone_build_range mx mx \n\t\t\t(to_real b) (to_real w) \n\t\t\t(to_real s) (to_real m) (to_real h)\n\t\t\t(to_real sa) (to_real ma) (to_real ha))\n{\n\tmx = Image_format.maxval fmt;\n}\n\nicc_export depth profile intent in\n\t= oo_unary_function icc_export_op in, is_class in\n\t= im_icc_export_depth in\n\t\t(to_real depth) (expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_export\")\n{\n\ticc_export_op = Operator \"icc_export\" \n\t\t(icc_export depth profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import profile intent in\n\t= oo_unary_function icc_import_op in, is_class in\n\t= im_icc_import in\n\t\t(expand profile) (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import\")\n{\n\ticc_import_op = Operator \"icc_import\" \n\t\t(icc_import profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_import_embedded intent in\n\t= oo_unary_function icc_import_embedded_op in, is_class in\n\t= im_icc_import_embedded in (to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_import_embedded\")\n{\n\ticc_import_embedded_op = Operator \"icc_import_embedded\" \n\t\t(icc_import_embedded intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_transform in_profile out_profile intent in\n\t= oo_unary_function icc_transform_op in, is_class in\n\t= im_icc_transform in\n\t\t(expand in_profile) (expand out_profile) \n\t\t(to_real intent), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_transform\")\n{\n\ticc_transform_op = Operator \"icc_transform\" \n\t\t(icc_transform in_profile out_profile intent)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\nicc_ac2rc profile in\n\t= oo_unary_function icc_ac2rc_op in, is_class in\n\t= im_icc_ac2rc in (expand profile), is_image in \n\t= error (_ \"bad arguments to \" ++ \"icc_ac2rc\")\n{\n\ticc_ac2rc_op = Operator \"icc_ac2rc\" \n\t\t(icc_ac2rc profile)\n\t\tOperator_type.COMPOUND_REWRAP false;\n}\n\n\n// Given a xywh rect, flip it around so wh are always positive\nrect_normalise x y w h \n\t= [x', y', w', h']\n{\n\tx'\n\t\t= x + w, w < 0\n\t\t= x;\n\ty'\n\t\t= y + h, h < 0\n\t\t= y;\n\tw' = abs w;\n\th' = abs h;\n}\n\ndraw_flood_blob x y ink image\n\t= oo_unary_function draw_flood_blob_op image, is_class image\n\t= im_draw_flood_blob image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood_blob\")\n{\n\tdraw_flood_blob_op = Operator \"draw_flood_blob\" \n\t\t(draw_flood_blob x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_flood x y ink image\n\t= oo_unary_function draw_flood_op image, is_class image\n\t= im_draw_flood image (to_real x) (to_real y) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_flood\")\n{\n\tdraw_flood_op = Operator \"draw_flood\" \n\t\t(draw_flood x y ink) Operator_type.COMPOUND_REWRAP false;\n}\n\n/* This version of draw_rect uses insert_noexpand and will be fast, even for\n * huge images.\n */\ndraw_rect_width x y w h f t ink image\n\t= oo_unary_function draw_rect_width_op image, is_class image\n\t= my_draw_rect_width image (to_int x) (to_int y) \n\t\t(to_int w) (to_int h) (to_int f) (to_int t) ink, \n\t\tis_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_width\")\n{\n\tdraw_rect_width_op = Operator \"draw_rect_width\" \n\t\t(draw_rect_width x y w h f t ink) \n\t\tOperator_type.COMPOUND_REWRAP false;\n\n\tmy_draw_rect_width image x y w h f t ink\n\t\t= insert x' y' (block w' h') image, f == 1\n\t\t= (insert x' y' (block w' t) @ \n\t\t\tinsert (x' + w' - t) y' (block t h') @ \n\t\t\tinsert x' (y' + h' - t) (block w' t) @ \n\t\t\tinsert x' y' (block t h')) image\n\t{\n\t\tinsert = insert_noexpand;\n\t\tblock w h = image_new w h (get_bands image) (get_format image)\n\t\t\t(get_coding image) (get_type image) ink' 0 0;\n\t\tink' \n\t\t\t= Vector ink, is_list ink\n\t\t\t= ink;\n\t\t[x', y', w', h'] = rect_normalise x y w h;\n\t}\n}\n\n/* Default to 1 pixel wide edges.\n */\ndraw_rect x y w h f ink image\n\t= draw_rect_width x y w h f 1 ink image;\n\n/* This version of draw_rect uses the paintbox rect draw operation. It is an\n * inplace operation and will use bucketloads of memory.\n */\ndraw_rect_paintbox x y w h f ink image\n\t= oo_unary_function draw_rect_op image, is_class image\n\t= im_draw_rect image (to_real x) (to_real y) \n\t\t(to_real w) (to_real h) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_rect_paintbox\")\n{\n\tdraw_rect_op = Operator \"draw_rect\" \n\t\t(draw_rect x y w h f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_circle x y r f ink image\n\t= oo_unary_function draw_circle_op image, is_class image\n\t= im_draw_circle image (to_real x) (to_real y) \n\t\t(to_real r) (to_real f) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_circle\")\n{\n\tdraw_circle_op = Operator \"draw_circle\" \n\t\t(draw_circle x y r f ink) Operator_type.COMPOUND_REWRAP false;\n}\n\ndraw_line x1 y1 x2 y2 ink image\n\t= oo_unary_function draw_line_op image, is_class image\n\t= im_draw_line image (to_real x1) (to_real y1) \n\t\t(to_real x2) (to_real y2) ink, is_image image\n\t= error (_ \"bad arguments to \" ++ \"draw_line\")\n{\n\tdraw_line_op = Operator \"draw_line\" \n\t\t(draw_line x1 y1 x2 y2 ink) Operator_type.COMPOUND_REWRAP false;\n}\n\nprint_base base in\n\t= oo_unary_function print_base_op in, is_class in\n\t= map (print_base base) in, is_list in \n\t= print_base_real, is_real in \n\t= error (_ \"bad arguments to \" ++ \"print_base\")\n{\n\tprint_base_op \n\t\t= Operator \"print_base\" (print_base base) Operator_type.COMPOUND false;\n\n\tprint_base_real \n\t\t= error \"print_base: bad base\", base < 2 || base > 16\n\t\t= \"0\", in < 0 || chars == [] \n\t\t= reverse chars\n\t{\n\t\tdigits = map (\\x x % base) \n\t\t\t(takewhile (not_equal 0) \n\t\t\t\t(iterate (\\x idivide x base) in));\n\t\tchars = map tohd digits;\n\n\t\ttohd x\n\t\t\t= (char) ((int) '0' + x), x < 10\n\t\t\t= (char) ((int) 'A' + (x - 10));\n\t}\n}\n\n/* id x: the identity function\n *\n * id :: * -> *\n */\nid x = x;\n\n/* const x y: junk y, return x\n * \n * (const 3) is the function that always returns 3.\n * const :: * -> ** -> *\n */\nconst x y = x;\n\n/* converse fn a b: swap order of args to fn\n * \n * converse fn a b == fn b a\n * converse :: (* -> ** -> ***) -> ** -> * -> ***\n */\nconverse fn a b = fn b a;\n\n/* fix fn x: find the fixed point of a function\n */\nfix fn x = limit (iterate fn x);\n\n/* until pred fn n: apply fn to n until pred succeeds; return that value\n *\n * until (more 1000) (multiply 2) 1 = 1024\n * until :: (* -> bool) -> (* -> *) -> * -> *\n */\nuntil pred fn n\n\t= n, pred n\n\t= until pred fn (fn n);\n\n/* Infinite list of primes.\n */\nprimes \n\t= 1 : (sieve [2 ..])\n{\n\tsieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l));\n\tnmultiple n x = x / n != (int) (x / n);\n}\n\n/* Map an n-ary function (pass the args as a list) over groups of objects.\n * The objects can be single objects or groups. If more than one \n * object is a group, we iterate for the length of the smallest group.\n * Don't loop over plain lists, since we want (eg.) \"mean [1, 2, 3]\" to work.\n * Treat [] as no-value --- ie. if any of the inputs are [] we put [] into the\n * output and don't apply the function.\n\n\t\tcopy-pasted into _types, keep in sync \n\n */\nmap_nary fn args\n\t= fn args, groups == []\n\t= Group (map process [0, 1 .. shortest - 1])\n{\n\t// find all the group arguments\n\tgroups = filter is_Group args;\n\n\t// what's the length of the shortest group arg?\n\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested groups too\n\tprocess n\n\t\t= NULL, any (map (is_noval n) args)\n\t\t= map_nary fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg.value?n, is_Group arg\n\t\t\t= arg;\n\n\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t}\n}\n\n/* Map a 1-ary function over an object.\n */\nmap_unary fn a = map_nary (list_1ary fn) [a];\n\n/* Map a 2-ary function over a pair of objects.\n */\nmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\n/* Map a 3-ary function over three objects.\n */\nmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n\n/* Map a 4-ary function over three objects.\n */\nmap_quaternary fn a b c d = map_nary (list_4ary fn) [a, b, c, d];\n\n/* Same as map_nary, but for lists. Handy for (eg.) implementing arith ops on\n * vectors and matricies.\n */\nmap_nary_list fn args\n\t= fn args, lists == []\n\t= map process [0, 1 .. shortest - 1]\n{\n\t// find all the list arguments\n\tlists = filter is_list args;\n\t\n\t// what's the length of the shortest list arg?\n\tshortest = foldr1 min_pair (map len lists);\n\n\t// process index n ... pull that member from each argument\n\t// recurse to handle application, so we work for nested lists too\n\tprocess n\n\t\t= map_nary_list fn (map (extract n) args)\n\t{\n\t\textract n arg\n\t\t\t= arg?n, is_list arg\n\t\t\t= arg;\n\t}\n}\n\nmap_unaryl fn a = map_nary_list (list_1ary fn) [a];\n\nmap_binaryl fn a b = map_nary_list (list_2ary fn) [a, b];\n\n/* Remove features smaller than x pixels across from an image. This used to be\n * rather complex ... convsep is now good enough to use.\n */\nsmooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image;\n\n/* Chop up an image into a list of lists of smaller images. Pad edges with \n * black.\n */\nimagearray_chop tile_width tile_height hoverlap voverlap i\n\t= map chop' [0, vstep .. last_y]\n{\n\twidth = get_width i;\n\theight = get_height i;\n\tbands = get_bands i;\n\tformat = get_format i;\n\ttype = get_type i;\n\n\ttile_width' = to_real tile_width;\n\ttile_height' = to_real tile_height;\n\thoverlap' = to_real hoverlap;\n\tvoverlap' = to_real voverlap;\n\n\t/* Unique pixels per tile.\n\t */\n\thstep = tile_width' - hoverlap';\n\tvstep = tile_height' - voverlap';\n\n\t/* Number of tiles across and down. Remember the case where width ==\n\t * hstep.\n\t */\n\tacross = (int) ((width - 1) / hstep) + 1;\n\tdown = (int) ((height - 1) / vstep) + 1;\n\n\t/* top/left of final tile.\n\t */\n\tlast_x = hstep * (across - 1);\n\tlast_y = vstep * (down - 1);\n\n\t/* How much do we need to pad by? \n\t */\n\tsx = last_x + tile_width';\n\tsy = last_y + tile_height';\n\n\t/* Expand image with black to pad size.\n\t */\n\tpad = embed 0 0 0 sx sy i;\n\n\t/* Chop up a row.\n\t */\n\tchop' y \n\t\t= map chop'' [0, hstep .. last_x]\n\t{\n\t\tchop'' x = extract_area x y tile_width' tile_height' pad;\n\t}\n}\n\n/* Reassemble image.\n */\nimagearray_assemble hoverlap voverlap il\n\t= (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il\n{\n\tlrj l r = insert (get_width l + hoverlap) 0 r l;\n\ttbj t b = insert 0 (get_height t + voverlap) b t;\n}\n\n/* Generate an nxn identity matrix.\n */\nidentity_matrix n\n\t= error \"identity_matrix: n > 0\", n < 1\n\t= map line [0 .. n - 1]\n{\n\tline p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..];\n}\n\n/* Incomplete gamma function Q(a, x) == 1 - P(a, x)\n\n\tFIXME ... this is now a builtin, until we can get a nice List class\n\t(requires overloadable ':')\n\ngammq a x\n\t= error \"bad args\", x < 0 || a <= 0\n\t= 1 - gamser, x < a + 1\n\t= gammcf\n{\n\tgamser = (gser a x)?0;\n\tgammcf = (gcf a x)?0;\n}\n */\n\n/* Incomplete gamma function P(a, x) evaluated as series representation. Also\n * return ln(gamma(a)) ... nr in c, pp 218\n */\ngser a x\n\t= [gamser, gln]\n{\n\tgln = gammln a;\n\tgamser\n\t\t= error \"bad args\", x < 0\n\t\t= 0, x == 0\n\t\t= 1\t\t// fix this\n\t{\n\t\t// maximum iterations\n\t\tmaxit = 100;\n\n\t\tap = List [a + 1, a + 2 ...];\n\t\txoap = x / ap;\n\n\t\tdel = map product (prefixes xoap.value);\n\n\n\t\t\n\n\n\n\n/*\n\t\tdel = map (multiply (1 / a)) (map product (prefixes xoap))\n\n\t\tdel = \n\n\t\txap = iterate (multiply \n */\n\n\t\t/* Generate all prefixes of a list ... [1,2,3] -> [[1], [1, 2], [1, 2,\n\t\t * 3], [1, 2, 3, 4] ...]\n\t\t */\n\t\tprefixes l = map (converse take l) [1..];\n\n\t}\n}\n\n/* ln(gamma(xx)) ... nr in c, pp 214\n */\ngammln xx\n\t= gln\n{\n\tcof = [76.18009172947146, -86.50532032941677, 24.01409824083091,\n\t\t-1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5];\n\ty = take 6 (iterate (add 1) (xx + 1));\n\tser = 1.000000000190015 + sum (map2 divide cof y);\n\ttmp = xx + 0.5;\n\ttmp' = tmp - ((xx + 0.5) * log tmp);\n\tgln = -tmp + log (2.5066282746310005 * ser / xx);\n}\n\n/* make a LUT from a scatter\n */\nbuildlut x\n\t= Plot_histogram (im_buildlut x), is_Matrix x && x.width > 1\n\t= im_buildlut (Matrix x), is_matrix x && is_list_len_more 1 x?0\n\t= error (_ \"bad arguments to \" ++ \"buildlut\");\n\n/* Linear regression. Return a class with the stuff we need in.\n * from s15.2, p 665 NR in C\n * \n * Also calculate R2, see eg.:\n * https://en.wikipedia.org/wiki/Coefficient_of_determination \n */\nlinreg xes yes\n    = obj\n{\n    obj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [t * y :: [t, y] <- zip2 tes yes] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [(y - intercept - slope * x) ** 2 :: [x, y] <- zip2 xes yes];\n\n\t\tsiga = (chi2 / (ss - 2)) ** 0.5 *\n\t\t\t((1 + sx ** 2 / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (chi2 / (ss - 2)) ** 0.5 * (1 / st2) ** 0.5;\n\n\t\t// for compat with linregw, see below\n\t\tq = 1.0;\n\n\t\tR2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes];\n\t}\n\n\tss = len xes;\n\tsx = sum xes;\n\tsy = sum yes;\n\tmy = sy / ss;\n\tsxoss = sx / ss;\n\n\ttes = [x - sxoss :: x <- xes];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Weighted linear regression. Xes, yes and a list of deviations.\n */\nlinregw xes yes devs \n\t= obj\n{\n\tobj = class {\n\t\t// in case we ever get shown in the workspace\n\t\t_vislevel = 2;\n\n\t\tslope = sum [(t * y) / sd :: [t, y, sd] <- zip3 tes yes devs] / st2;\n\t\tintercept = (sy - sx * slope) / ss;\n\n\t\tchi2 = sum [((y - intercept - slope * x) / sd) ** 2 :: \n\t\t\t[x, y, sd] <- zip3 xes yes devs];\n\n\t\tsiga = ((1 + sx * sx / (ss * st2)) / ss) ** 0.5;\n\t\tsigb = (1 / st2) ** 0.5;\n\n\t\tq = gammq (0.5 * (len xes - 2)) (0.5 * chi2);\n\n\t\tR2 = 1 - chi2 / sum [(y - my) ** 2 :: y <- yes];\n\t}\n\n\twt = [sd ** -0.5 :: sd <- devs];\n\n\tss = sum wt;\n\tsx = sum [x * w :: [x, w] <- zip2 xes wt];\n\tsy = sum [y * w :: [y, w] <- zip2 yes wt];\n\tmy = sy / len xes;\n\tsxoss = sx / ss;\n\n\ttes = [(x - sxoss) / sd :: [x, sd] <- zip2 xes devs];\n\tst2 = sum [t ** 2 :: t <- tes];\n}\n\n/* Clustering: pass in a list of points, repeatedly merge the\n * closest two points until no two points are closer than the threshold.\n * Return [merged-points, corresponding-weights]. A weight is a list of the\n * indexes we merged to make that point, ie. len weight == how significant\n * this point is.\n *\n * eg. \n *\tcluster 12 [152,154,155,42,159] == \n *\t\t[[155,42],[[1,2,0,4],[3]]]\n */\ncluster thresh points\n\t= oo_unary_function cluster_op points, is_class points\n\t// can't use [0..len points - 1], in case len points == 0\n\t= merge [points, map (converse cons []) (take (len points) [0 ..])],\n\t\tis_list points\n\t= error (_ \"bad arguments to \" ++ \"cluster\")\n{\n\tcluster_op = Operator \"cluster\" \n\t\t(cluster thresh) Operator_type.COMPOUND false;\n\n\tmerge x\n\t\t= x, m < 2 || d > thresh\n\t\t= merge [points', weights']\n\t{\n\t\t[points, weights] = x;\n\t\tm = len points;\n\n\t\t// generate indexes of all possible pairs, avoiding comparing a thing \n\t\t// to itself, and assuming that dist is reflexive\n\t\t// first index is always less than 2nd index\n\t\t// the +1,+2 makes sure we have an increasing generator, otherwise we\n\t\t// can get [3 .. 4] (for example), which will make a decreasing\n\t\t// sequence\n\t\tpairs = [[x, y] :: x <- [0 .. m - 1]; y <- [x + 1, x + 2 .. m - 1]];\n\n\t\t// distance function\n\t\t// arg is eg. [3,1], meaning get distance from point 3 to point 1\n\t\tdist x \n\t\t\t= abs (points?i - points?j)\n\t\t{\n\t\t\t[i, j] = x;\n\t\t}\n\n\t\t// smallest distance, then the two points we merge\n\t\tp = minpos (map dist pairs);\n\t\td = dist pairs?p;\n\t\t[i, j] = pairs?p;\n\n\t\t// new point and new weight\n\t\tnw = weights?i ++ weights?j;\n\t\tnp = (points?i * len weights?i + points?j * len weights?j) / len nw;\n\n\t\t// remove element i from a list\n\t\tremove i l = take i l ++ drop (i + 1) l;\n\n\t\t// remove two old points, add the new merged one\n\t\t// i < j (see \"pairs\", above)\n\t\tpoints' = np : remove i (remove j points);\n\t\tweights' = nw : remove i (remove j weights);\n\t}\n}\n\n/* Extract the area of an image around an arrow.\n * Transform the image to make the arrow horizontal, then displace by hd and\n * vd pxels, then cut out a bit h pixels high centered on the arrow.\n */\nextract_arrow hd vd h arrow\n\t= extract_area (re p' + hd) (im p' - h / 2 + vd) (re pv) h im'\n{\n\t// the line as a polar vector\n\tpv = polar (arrow.width, arrow.height);\n\ta = im pv;\n\n\t// smallest rotation that will make the line horizontal\n\ta'\n\t\t= 360 - a, a > 270\n\t\t= 180 - a, a > 90\n\t\t= -a;\n\n\tim' = rotate Interpolate_bilinear a' arrow.image;\n\n\t// look at the start and end of the arrow, pick the leftmost\n\tp\n\t\t= (arrow.left, arrow.top), arrow.left <= arrow.right\n\t\t= (arrow.right, arrow.bottom);\n\n\t// transform that point to im' space\n\tp' = rectangular (polar p + (0, a')) + (im'.xoffset, im'.yoffset);\n}\n\n/* You'd think these would go in _convert, but they are not really colour ops,\n * so put them here.\n */\nrad2float image\n\t= oo_unary_function rad2float_op image, is_class image\n\t= im_rad2float image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"rad2float\")\n{\n\trad2float_op = Operator \"rad2float\" \n\t\trad2float Operator_type.COMPOUND_REWRAP false;\n}\n\nfloat2rad image\n\t= oo_unary_function float2rad_op image, is_class image\n\t= im_float2rad image, is_image image\n\t= error (_ \"bad arguments to \" ++ \"float2rad\")\n{\n\tfloat2rad_op = Operator \"float2rad\" \n\t\tfloat2rad Operator_type.COMPOUND_REWRAP false;\n}\n\nsegment x\n\t= oo_unary_function segment_op x, is_class x\n\t= image', is_image x \n\t= error (_ \"bad arguments to \" ++ \"segment\")\n{\n\tsegment_op = Operator \"segment\" \n\t\tsegment Operator_type.COMPOUND_REWRAP false;\n\n\t[image, nsegs] = im_segment x;\n\timage' = im_copy_set_meta image \"n-segments\" nsegs;\n}\n\npoint a b\n\t= oo_binary_function point_op a b, is_class a\n\t= oo_binary'_function point_op a b, is_class b\n\t= im_read_point b x y, is_image b\n\t= [b?x?y], is_matrix b\n\t= [b?x], is_real_list b && y == 0\n\t= [b?y], is_real_list b && x == 0\n\t= error (_ \"bad arguments to \" ++ \"point\")\n{\n\tpoint_op = Operator \"point\" \n\t\t(\\a\\b Vector (point a b)) Operator_type.COMPOUND false;\n\n\t(x, y) \n\t\t= a, is_complex a;\n\t\t= (a?0, a?1), is_real_list a && is_list_len 2 a\n\t\t= error \"bad position format\";\n}\n\n/* One image in, one out. \n */\nsystem_image command x\n\t= oo_unary_function system_image_op x, is_class x\n\t= system x, is_image x\n\t= error (_ \"bad arguments to \" ++ \"system_image\")\n{\n\tsystem_image_op = Operator \"system_image\" \n\t\t(system_image command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem im\n\t\t= image_out\n\t{\n\t\t[image_out, log] = \n\t\t\tim_system_image (get_image im) \"%s.tif\" \"%s.tif\" command;\n\t}\n}\n\n/* Two images in, one out. \n */\nsystem_image2 command x1 x2\n\t= oo_binary_function system_image2_op x1 x2, is_class x1\n\t= oo_binary'_function system_image2_op x1 x2, is_class x2\n\t= system x1 x2, is_image x1 && is_image x2\n\t= error (_ \"bad arguments to \" ++ \"system_image2\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image2 command) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Three images in, one out. \n */\nsystem_image3 command x1 x2 x3\n\t= oo_binary_function system_image2_op x2 x3, is_class x2\n\t= oo_binary'_function system_image2_op x2 x3, is_class x3\n\t= system x1 x2 x3, is_image x1 && is_image x2 && is_image x3\n\t= error (_ \"bad arguments to \" ++ \"system_image3\")\n{\n\tsystem_image2_op = Operator \"system_image2\" \n\t\t(system_image3 command x1) Operator_type.COMPOUND_REWRAP false;\n\n\tsystem x1 x2 x3\n\t\t= image_out\n\t{\n\t\t[image_out] = vips_call \"system\" [command] [\n\t\t\t$in => [x1, x2, x3], \n\t\t\t$out => true,\n\t\t\t$out_format => \"%s.tif\", \n\t\t\t$in_format => \"%s.tif\"\n\t\t];\n\t}\n}\n\n/* Zero images in, one out. \n */\nsystem_image0 command \n\t= Image image_out\n{\n\t[image_out] = vips_call \"system\" [command] [\n\t\t$out => true,\n\t\t$out_format => \"%s.tif\" \n\t];\n}\n\nhough_line w h x \n\t= oo_unary_function hough_line_op x, is_class x\n\t= hline (to_real w) (to_real h) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_line\")\n{\n\though_line_op = Operator \"hough_line\" \n\t\t(hough_line w h) Operator_type.COMPOUND_REWRAP false;\n\n\thline w h x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_line\" [x] [\n\t\t\t$width => w, \n\t\t\t$height => h\n\t\t];\n\t}\n}\n\nhough_circle s mn mx x \n\t= oo_unary_function hough_circle_op x, is_class x\n\t= hcircle (to_real s) (to_real mn) (to_real mx) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hough_circle\")\n{\n\though_circle_op = Operator \"hough_circle\" \n\t\t(hough_circle s mn mx) Operator_type.COMPOUND_REWRAP false;\n\n\thcircle s mn mx x\n\t\t= pspace\n\t{\n\t\t[pspace] = vips_call \"hough_circle\" [x] [\n\t\t\t$scale => s, \n\t\t\t$min_radius => mn, \n\t\t\t$max_radius => mx\n\t\t];\n\t}\n}\n\nmapim interp ind in\n\t= oo_binary_function mapim_op ind in, is_class ind\n\t= oo_binary'_function mapim_op ind in, is_class in\n\t= mapim_fn ind in, is_image ind && is_image in\n\t= error (_ \"bad arguments to \" ++ \"mapim\")\n{\n\tmapim_op = Operator \"mapim\" \n\t\t(mapim interp) Operator_type.COMPOUND_REWRAP false;\n\n\tmapim_fn ind im\n\t\t= out\n\t{\n\t\t[out] = vips_call \"mapim\" [im, ind] [$interpolate => interp];\n\t}\n}\n\nperlin cell width height\n\t= Image im\n{\n\t[im] = vips_call \"perlin\" [to_real width, to_real height] [\n\t\t$cell_size => to_real cell \n\t];\n}\n\nworley cell width height\n\t= Image im\n{\n\t[im] = vips_call \"worley\" [to_real width, to_real height] [\n\t\t$cell_size => to_real cell \n\t];\n}\n\ngaussnoise width height mean sigma\n\t= im\n{\n\t[im] = vips_call \"gaussnoise\" [to_real width, to_real height] [\n\t\t$mean => to_real mean,\n\t\t$sigma => to_real sigma\n\t];\n}\n\nflattenimage bg x \n\t= oo_unary_function flatten_op x, is_class x\n\t= flt (to_vector bg) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"flattenimage\")\n{\n\tflatten_op = Operator \"flatten\" \n\t\t(flattenimage bg) Operator_type.COMPOUND_REWRAP false;\n\n\tflt bg x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"flatten\" [x] [\n\t\t\t$background => bg.value \n\t\t];\n\t}\n}\n\npremultiply x \n\t= oo_unary_function premultiply_op x, is_class x\n\t= prem x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"premultiply\")\n{\n\tpremultiply_op = Operator \"premultiply\" \n\t\tpremultiply Operator_type.COMPOUND_REWRAP false;\n\n\tprem x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"premultiply\" [x] [\n\t\t];\n\t}\n}\n\nunpremultiply x \n\t= oo_unary_function unpremultiply_op x, is_class x\n\t= unprem x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"unpremultiply\")\n{\n\tunpremultiply_op = Operator \"unpremultiply\" \n\t\tunpremultiply Operator_type.COMPOUND_REWRAP false;\n\n\tunprem x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"unpremultiply\" [x] [\n\t\t];\n\t}\n}\n\nhist_entropy x \n\t= oo_unary_function hist_entropy_op x, is_class x\n\t= entropy x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"hist_entropy\")\n{\n\thist_entropy_op = Operator \"hist_entropy\" \n\t\thist_entropy Operator_type.COMPOUND_REWRAP false;\n\n\tentropy x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"hist_entropy\" [x] [\n\t\t];\n\t}\n}\n\ncanny sigma precision x \n\t= oo_unary_function canny_op x, is_class x\n\t= canny_im (to_real sigma) (to_int precision) x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"canny\")\n{\n\tcanny_op = Operator \"canny\" \n\t\t(canny sigma precision) Operator_type.COMPOUND_REWRAP false;\n\n\tcanny_im sigma precision x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"canny\" [x] [\n\t\t\t$sigma => sigma,\n\t\t\t$precision => precision\n\t\t];\n\t}\n\n}\n\nsobel x \n\t= oo_unary_function sobel_op x, is_class x\n\t= sobel_im x, is_image x \n\t= error (_ \"bad arguments to \" ++ \"sobel\")\n{\n\tsobel_op = Operator \"sobel\" \n\t\tsobel Operator_type.COMPOUND_REWRAP false;\n\n\tsobel_im x\n\t\t= out\n\t{\n\t\t[out] = vips_call \"sobel\" [x] [\n\t\t];\n\t}\n}\n"
  },
  {
    "path": "share/nip2/start/_types.def",
    "content": "/* A list of things. Do automatic iteration of unary and binary operators on\n * us. \n *\tList [1, 2] + [2, 3] -> List [3, 5]\n *\thd (List [2, 3]) -> 2\n *\tList [] == [] -> true\n */\nList value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n    oo_binary_table op x = [\n\t\t[apply2 op value x',\n\t\t\top.op_name == \"subscript\" || op.op_name == \"subscript'\" ||\n\t\t\top.op_name == \"equal\" || op.op_name == \"equal'\"],\n\t\t[this.List (apply2 op value x'),\n\t\t\top.op_name == \"join\" || op.op_name == \"join'\"],\n\t\t[this.List (map2 (apply2 op) value x'),\n\t\t\tis_list x'],\n\t\t[this.List (map (apply2 op' x) value),\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\n\t\t// strip the List wrapper, if any\n\t\tx'\n\t\t\t= x.value, is_List x\n\t\t\t= x;\n\n\t\tapply2 op x1 x2\n\t\t\t= oo_binary_function op x1 x2, is_class x1 \n\t\t\t= oo_binary'_function op x1 x2, is_class x2\n\t\t\t= op.fn x1 x2;\n\t};\n\n\too_unary_table op = [\n\t\t[apply value,\n\t\t\top.op_name == \"hd\" || op.op_name == \"tl\"],\n\t\t[this.List (map apply value),\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tapply x\n\t\t\t= oo_unary_function op x, is_class x\n\t\t\t= op.fn x;\n\t}\n}\n\n/* A group of things. Loop the operation over the group.\n */\nGroup value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_list]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t// if_then_else is really a trinary operator\n\t\t[map_trinary ite this x?0 x?1,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[map_binary op.fn this x,\n\t\t\tis_Group x],\n\t\t[map_unary (\\a op.fn a x) this,\n\t\t\ttrue]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[map_unary op.fn this,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// we can't call map_trinary directly, since it uses Group and we\n\t// don't support mutually recursive top-level functions :-(\n\t// copy-paste it here, keep in sync with the version in _stdenv\n\tmap_nary fn args\n\t\t= fn args, groups == []\n\t\t= Group (map process [0, 1 .. shortest - 1])\n\t{\n\t\tgroups = filter is_Group args;\n\t\n\t\tshortest = foldr1 min_pair (map (len @ get_value) groups);\n\n\t\tprocess n\n\t\t\t= NULL, any (map (is_noval n) args)\n\t\t\t= map_nary fn (map (extract n) args)\n\t\t{\n\t\t\textract n arg\n\t\t\t\t= arg.value?n, is_Group arg\n\t\t\t\t= arg;\n\t\n\t\t\tis_noval n arg = is_Group arg && arg.value?n == NULL;\n\t\t}\n\t}\n\n\t// need ite as a true trinary\n\tite a b c = if a then b else c;\n\n\tmap_unary fn a = map_nary (list_1ary fn) [a];\n\tmap_binary fn a b = map_nary (list_2ary fn) [a, b];\n\tmap_trinary fn a b c = map_nary (list_3ary fn) [a, b, c];\n}\n\n/* Single real number ... eg slider.\n */\nReal value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Real (op.fn this.value x.value), \n\t\t\tis_Real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Real (op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value x.value, \n\t\t\tis_Real x && \n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value x, \n\t\t\t!is_class x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Real (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* Single bool ... eg Toggle.\n */\nBool value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_bool]\n\t];\n\n\t// methods\n\too_binary_table op x = [\n\t\t[op.fn this.value x, \n\t\t\top.op_name == \"if_then_else\"],\n\t\t[this.Bool (op.fn this.value x.value), \n\t\t\tis_Bool x],\n\t\t[this.Bool (op.fn this.value x), \n\t\t\tis_bool x]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[this.Bool (op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC ||\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* An editable string.\n */\nString caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable real number.\n */\nNumber caption value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string]\n\t];\n\n\tReal x = this.Number caption x;\n}\n\n/* An editable expression.\n */\nExpression caption expr = class \n\t(if is_class expr then expr else _Object) {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[expr, \"expr\", check_any]\n\t];\n}\n\n/* A ticking clock.\n */\nClock interval value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[interval, \"interval\", check_real]\n\t];\n\n\tReal x = this.Clock interval x;\n}\n\n/* An editable filename.\n */\nPathname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* An editable fontname.\n */\nFontname caption value = class \n\t_Object {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_string]\n\t];\n}\n\n/* Vector type ... just a finite list of real. Handy for wrapping an\n * argument to eg. im_lintra_vec. Make it behave like a single pixel image.\n */\nVector value = class\n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_real_list]\n\t];\n\n\tbands = len value;\n\n\t// methods\n\too_binary_table op x = [\n\t\t// Vector ++ Vector means bandwise join\n\t\t[this.Vector (op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[this.Vector (op.fn this.value [get_number x]), \n\t\t\thas_number x &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t// Vector ? number means extract element\n\t\t[op.fn this.value (get_real x), \n\t\t\thas_real x &&\n\t\t\t(op.op_name == \"subscript\" || \n\t\t\t\top.op_name == \"subscript'\")],\n\t\t// extra check for lengths equal\n\t\t[this.Vector (map_binaryl op.fn this.value x.value), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map_binaryl op.fn this.value (get_real x)), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// need extra length check\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value x.value)), \n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (map bool_to_real \n\t\t\t(map_binaryl op.fn this.value (get_real x))), \n\t\t\thas_real x &&\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value x.value),\n\t\t\tis_Vector x &&\n\t\t\tlen value == len x.value &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[x.Image (vec op'.op_name x.value value),\n\t\t\tis_Image x],\n\t\t[vec op'.op_name x value,\n\t\t\tis_image x],\n\t\t[op.fn this.value x, \n\t\t\tis_real x]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\top' = oo_converse op;\n\t};\n\n\too_unary_table op = [\n\t\t[this.Vector (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Vector (map bool_to_real\n\t\t\t(map_unaryl op.fn this.value)),\n\t\t\top.type == Operator_type.RELATIONAL],\n\t\t[this.Vector (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n\n\t// turn an ip bool (or a number, for Vector) into VIPSs 255/0\n\tbool_to_real x\n\t\t= 255, is_bool x && x\n\t\t= 255, is_number x && x != 0\n\t\t= 0;\n}\n\n/* A rectangular array of real.\n */\nMatrix_base value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_matrix]\n\t];\n\n\t// calculate these from value\n\twidth = len value?0;\n\theight = len value;\n\n\t// extract a rectanguar area\n\textract left top width height\n\t\t= this.Matrix_base \n\t\t\t((map (take width) @ map (drop left) @\n\t\t\t\ttake height @ drop top) value);\n\n\t// methods\n\too_binary_table op x = [\n\t\t// mat multiply is special\n\t\t[this.Matrix_base mul.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply\"],\n\t\t[this.Matrix_base mul'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"multiply'\"],\n\n\t\t// mat divide is also special\n\t\t[this.Matrix_base div.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide\"],\n\t\t[this.Matrix_base div'.value,\n\t\t\tis_Matrix x &&\n\t\t\top.op_name == \"divide'\"],\n\n\t\t// power -1 means invert\n\t\t[this.Matrix_base inv.value,\n\t\t\tis_real x && x == -1 &&\n\t\t\top.op_name == \"power\"],\n\t\t[this.Matrix_base sq.value,\n\t\t\tis_real x && x == 2 &&\n\t\t\top.op_name == \"power\"],\n\t\t[error \"matrix **-1 and **2 only\",\n\t\t\top.op_name == \"power\" ||\n\t\t\top.op_name == \"power'\"],\n\n\t\t// matrix op vector ... treat a vector as a 1 row matrix\n\t\t[this.Matrix_base (map (map_binaryl op'.fn x.value) this.value),\n\t\t\tis_Vector x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x) && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t[this.Matrix_base (map_binaryl op.fn this.value x),\n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound ... don't do iteration\n\t\t[this.Matrix_base (op.fn this.value x.value),\n\t\t\t(is_Matrix x || is_Real x || is_Vector x) &&\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\n\t\t[op.fn this.value x,\n\t\t\top.type == Operator_type.COMPOUND]\n\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tmul = im_matmul this x;\n\t\tmul' = im_matmul x this;\n\t\tdiv = im_matmul this (im_matinv x);\n\t\tdiv' = im_matmul x (im_matinv this);\n\t\tinv = im_matinv this;\n\t\tsq = im_matmul this this;\n\t\top' = oo_converse op;\n\t}\n\n\too_unary_table op = [\n\t\t[this.Matrix_base (map_unaryl op.fn this.value),\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Matrix_base (op.fn this.value),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP],\n\t\t[op.fn this.value,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op;\n}\n\n/* How to display a matrix: text, sliders, toggles, or text plus scale/offset.\n */\nMatrix_display = class {\n        text = 0;\n        slider = 1;\n        toggle = 2;\n        text_scale_offset = 3;\n\n        is_display = member [text, slider, toggle, text_scale_offset];\n}\n\n/* A matrix as VIPS sees them ... add scale, offset and filename. For nip, add\n * a display type as well to control how the widget renders.\n */\nMatrix_vips value scale offset filename display = class \n\tscope.Matrix_base value {\n\t_check_args = [\n\t\t[scale, \"scale\", check_real],\n\t\t[offset, \"offset\", check_real],\n\t\t[filename, \"filename\", check_string],\n\t\t[display, \"display\", check_matrix_display]\n\t];\n\n\tMatrix_base x = this.Matrix_vips x scale offset filename display;\n}\n\n/* A plain 'ol matrix which can be passed to VIPS.\n */\nMatrix value = class \n\tMatrix_vips value 1 0 \"\" Matrix_display.text {}\n\n/* Specialised constructors ... for convolutions, recombinations and\n * morphologies.\n */\nMatrix_con scale offset value = class\n\tMatrix_vips value scale offset \"\" Matrix_display.text_scale_offset {};\n\nMatrix_rec value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.slider {};\n\nMatrix_mor value = class\n\tMatrix_vips value 1 0 \"\" Matrix_display.toggle {};\n\nMatrix_file filename = (im_read_dmask @ expand @ search) filename;\n\n/* A CIE colour ... a triple, plus a format (eg XYZ, Lab etc)\n */\nColour colour_space value = class\n\tscope.Vector value {\n\t_check_args = [\n\t\t[colour_space, \"colour_space\", check_colour_space]\n\t];\n\t_check_all = [\n\t\t[is_list_len 3 value, \"len value == 3\"]\n\t];\n\n\tVector x = this.Colour colour_space x;\n\n\t// make a colour-ish thing from an image\n\t// back to Colour if we have another 3 band image\n\t// to a vector if bands > 1\n\t// to a number otherwise\n\titoc im\n\t\t= this.Colour nip_type (to_matrix im).value?0, \n\t\t\tbands == 3\n\t\t= scope.Vector (map mean (bandsplit im)),\n\t\t\tbands > 1\n\t\t= mean im\n\t{\n\t\ttype = get_header \"Type\" im;\n\t\tbands = get_header \"Bands\" im;\n\t\tnip_type = Image_type.colour_spaces.lookup 1 0 type;\n\t}\n\n\t// methods\n\too_binary_table op x = [\n\t\t[itoc (op.fn \n\t\t\t((float) (to_image this).value) \n\t\t\t((float) (to_image x).value)),\n\t\t\t// here REWRAP means go via image\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_binary_table op x;\n\n\too_unary_table op = [\n\t\t[itoc (op.fn ((float) (to_image this).value)),\n\t\t\top.type == Operator_type.COMPOUND_REWRAP]\n\t] ++ super.oo_unary_table op;\n}\n\n// a subclass with widgets for picking a space and value\nColour_picker default_colour default_value = class \n\tColour space.item colour.expr {\n\t_vislevel = 3;\n\n\tspace = Option_enum \"Colour space\" Image_type.colour_spaces default_colour;\n\tcolour = Expression \"Colour value\" default_value;\n\n\tColour_edit colour_space value = \n\t\tColour_picker colour_space value;\n}\n\n/* Base scale type.\n */\nScale caption from to value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[from, \"from\", check_real],\n\t\t[to, \"to\", check_real]\n\t];\n\t_check_all = [\n\t\t[from < to, \"from < to\"]\n\t];\n\n\tReal x = this.Scale caption from to x;\n\n\t// methods\n\too_binary_table op x = [\n\t\t[this.Scale caption (op.fn this.from x.from) (op.fn this.to x.to)\n\t\t\t(op.fn this.value x.value), \n\t\t\tis_Scale x &&\n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Scale caption (op.fn this.from x) (op.fn this.to x)\n\t\t\t(op.fn this.value x), \n\t\t\tis_real x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x;\n}\n\n/* Base toggle type.\n */\nToggle caption value = class \n\tscope.Bool value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[value, \"value\", check_bool]\n\t];\n\n\tBool x = this.Toggle caption x;\n}\n\n/* Base option type.\n */\nOption caption labels value = class \n\tscope.Real value {\n\t_check_args = [\n\t\t[caption, \"caption\", check_string],\n\t\t[labels, \"labels\", check_string_list],\n\t\t[value, \"value\", check_uint]\n\t];\n}\n\n/* An option whose value is a string rather than a number.\n */\nOption_string caption labels item = class\n\tOption caption labels (index (equal item) labels) {\n\tOption_edit caption labels value \n\t\t= this.Option_string caption labels (labels?value);\n}\n\n/* Make an option from an enum.\n */\nOption_enum caption enum item = class\n\tOption_string caption enum.names item {\n\t// corresponding thing\n\tvalue_thing = enum.get_thing item;\n\n\tOption_edit caption labels value \n\t\t= this.Option_enum caption enum (enum.names?value);\n}\n\n/* A rectangle. width and height can be -ve.\n */\nRect left top width height = class \n\t_Object {\n\t_check_args = [\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\t// derived\n\tright = left + width;\n\tbottom = top + height;\n\n\too_binary_table op x = [\n\t\t[equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"equal\" || op.op_name == \"equal'\")],\n\t\t[!equal x, \n\t\t\tis_Rect x &&\n\t\t\t(op.op_name == \"not_equal\" || \n\t\t\t\top.op_name == \"not_equal'\")],\n\n\t\t// binops with a complex are the same as (comp op comp)\n\t\t[oo_binary_function op this (Rect (re x) (im x) 0 0),\n\t\t\tis_complex x],\n\n\t\t// all others are just pairwise\n\t\t[this.Rect left' top' width' height',\n\t\t\tis_Rect x && \n\t\t\top.type == Operator_type.ARITHMETIC],\n\t\t[this.Rect left'' top'' width'' height'',\n\t\t\thas_number x && \n\t\t\top.type == Operator_type.ARITHMETIC]\n\t] ++ super.oo_binary_table op x\n\t{\n\t\tleft' = op.fn left x.left;\n\t\ttop' = op.fn top x.top;\n\t\twidth' = op.fn width x.width;\n\t\theight' = op.fn height x.height;\n\n\t\tleft'' = op.fn left x';\n\t\ttop'' = op.fn top x';\n\t\twidth'' = op.fn width x';\n\t\theight'' = op.fn height x';\n\t\tx' = get_number x;\n\t}\n\n\too_unary_table op = [\n\t\t// arithmetic uops just map\n\t\t[this.Rect left' top' width' height',\n\t\t\top.type == Operator_type.ARITHMETIC],\n\n\t\t// compound uops are just like ops on complex\n\t\t// do (width, height) so thing like abs(Arrow) work as you'd expect\n\t\t[op.fn (width, height),\n\t\t\top.type == Operator_type.COMPOUND]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tleft' = op.fn left;\n\t\ttop' = op.fn top;\n\t\twidth' = op.fn width;\n\t\theight' = op.fn height;\n\t}\n\n\t// empty? ie. contains no pixels\n\tis_empty = width == 0 || height == 0;\n\n\t// normalised version, ie. make width/height +ve and flip the origin\n\tnleft\n\t\t= left + width, width < 0\n\t\t= left;\n\tntop\n\t\t= top + height, height < 0\n\t\t= top;\n\tnwidth = abs width;\n\tnheight = abs height;\n\tnright = nleft + nwidth;\n\tnbottom = ntop + nheight;\n\n\tequal x = left == x.left && top == x.top &&\n\t\t  width == x.width && height == x.height;\n\n\t// contains a point?\n\tincludes_point x y\n\t\t= nleft <= x && x <= nright && ntop <= y && y <= nbottom;\n\n\t// contains a rect? just test top left and bottom right points\n\tincludes_rect r\n\t\t= includes_point r.nleft r.ntop &&\n\t\t\tincludes_point r.nright r.nbottom;\n\n\t// bounding box of two rects\n\t// if either is empty, can just return the other\n\tunion r\n\t\t= r, is_empty\n\t\t= this, r.is_empty\n\t\t= Rect left' top' width' height'\n\t{\n\t\tleft' = min_pair nleft r.nleft;\n\t\ttop' = min_pair ntop r.ntop;\n\t\twidth' = max_pair nright r.nright - left';\n\t\theight' = max_pair nbottom r.nbottom - top';\n\t}\n\n\t// intersection of two rects ... empty rect if no intersection\n\tintersect r\n\t\t= Rect left' top' width'' height''\n\t{\n\t\tleft' = max_pair nleft r.nleft;\n\t\ttop' = max_pair ntop r.ntop;\n\t\twidth' = min_pair nright r.nright - left';\n\t\theight' = min_pair nbottom r.nbottom - top';\n\t\twidth''\n\t\t\t= width', width > 0\n\t\t\t= 0;\n\t\theight''\n\t\t\t= height', height > 0\n\t\t\t= 0;\n\t}\n\n\t// expand/collapse by n pixels\n\tmargin_adjust n\n\t\t= Rect (left - n) (top - n) (width + 2 * n) (height + 2 * n);\n}\n\n/* Values for Compression field in image.\n */\nImage_compression = class {\n\tNONE = 0;\n\tNO_COMPRESSION = 0;\n\tTCSF_COMPRESSION = 1;\n\tJPEG_COMPRESSION = 2;\n\tLABPACK_COMPRESSED = 3;\n\tRGB_COMPRESSED = 4;\n\tLUM_COMPRESSED = 5;\n}\n\n/* Values for Coding field in image.\n */\nImage_coding = class {\n\tNONE = 0;\n\tNOCODING = 0;\n\tCOLQUANT = 1;\n\tLABPACK = 2;\n\tRAD = 6;\n}\n\n/* Values for BandFmt field in image.\n */\nImage_format = class {\n\tDPCOMPLEX = 9;\n\tDOUBLE = 8;\n\tCOMPLEX = 7;\n\tFLOAT = 6;\n\tINT = 5;\n\tUINT = 4;\n\tSHORT = 3;\n\tUSHORT = 2;\n\tCHAR = 1;\n\tUCHAR = 0;\n\tNOTSET = -1;\n\n\tmaxval fmt \n\t\t= [\n\t\t\t255,\t\t// UCHAR\n\t\t\t127,\t\t// CHAR\n\t\t\t65535,\t\t// USHORT\n\t\t\t32767,\t\t// SHORT\n\t\t\t4294967295,\t// UINT\n\t\t\t2147483647,\t// INT\n\t\t\t255,\t\t// FLOAT\n\t\t\t255,\t\t// COMPLEX\n\t\t\t255,\t\t// DOUBLE\n\t\t\t255\t\t\t// DPCOMPLEX\n\t\t] ? fmt, fmt >= 0 && fmt <= DPCOMPLEX\n\t\t= error (_ \"bad value for BandFmt\");\n}\n\n/* A lookup table.\n */\nTable value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_rectangular]\n\t];\n\n\t/* Extract a column.\n\t */\n\tcolumn n = map (extract n) value;\n\n\t/* present col x: is there an x in column col\n\t */\n\tpresent col x = member (column col) x;\n\n\t/* Look on column from, return matching item in column to.\n\t */\n\tlookup from to x\n\t\t= value?n?to, n >= 0\n\t\t= error (_ \"item\" ++ \" \" ++ print x ++ \" \" ++ _ \"not in table\")\n\t{\n\t\tn = index (equal x) (column from);\n\t}\n}\n\n/* A two column lookup table with the first column a string and the second a\n * thing. Used for representing various enums. Option_enum makes a selector\n * from one of these.\n */\nEnum value = class \n\tTable value {\n\t_check_args = [\n\t\t[value, \"value\", check_enum]\n\t]\n\t{\n\t\tcheck_enum = [is_enum, _ \"is [[char, *]]\"];\n\t\tis_enum x = \n\t\t\tis_rectangular x && \n\t\t\tis_listof is_string (map (extract 0) x);\n\t}\n\n\t// handy ... all the names and things as lists\n\tnames = this.column 0; \n\tthings = this.column 1; \n\n\t// is a legal name or thing\n\thas_name x = this.present 1 x;\n\thas_thing x = this.present 0 x;\n\n\t// map things to strings and back\n\tget_name x = this.lookup 1 0 x;\n\tget_thing x = this.lookup 0 1 x;\n}\n\n/* Type field.\n */\nImage_type = class {\n\tMULTIBAND = 0;\n\tB_W = 1;\n\tHISTOGRAM = 10;\n\tXYZ = 12;\n\tLAB = 13;\n\tCMYK = 15;\n\tLABQ = 16;\n\tRGB = 17;\n\tUCS = 18;\n\tLCH = 19;\n\tLABS = 21;\n\tsRGB = 22;\n\tYXY = 23;\n\tFOURIER = 24;\n\tRGB16 = 25;\n\tGREY16 = 26;\n\tARRAY = 27;\n\tscRGB = 28;\n\n\t/* Table to get names <-> numbers.\n\t */\n\ttype_names = Enum [\n\t\t$MULTIBAND => MULTIBAND,\n\t\t$B_W => B_W,\n\t\t$HISTOGRAM => HISTOGRAM,\n\t\t$XYZ => XYZ,\n\t\t$LAB => LAB,\n\t\t$CMYK => CMYK,\n\t\t$LABQ => LABQ,\n\t\t$RGB => RGB,\n\t\t$UCS => UCS,\n\t\t$LCH => LCH,\n\t\t$LABS => LABS,\n\t\t$sRGB => sRGB,\n\t\t$YXY => YXY,\n\t\t$FOURIER => FOURIER,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$ARRAY => ARRAY,\n\t\t$scRGB => scRGB\n\t];\n\n\t/* Table relating nip's colour space names and VIPS's Type numbers.\n\t * Options are generated from this, so match the order to the order in \n\t * the Colour menu.\n\t */\n\tcolour_spaces = Enum [\n\t\t$sRGB => sRGB,\n\t\t$scRGB => scRGB,\n\t\t$Lab => LAB,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n\n\t/* A slightly larger table ... the types of colorimetric image we can\n\t * have. Add mono, and the S and Q forms of LAB.\n\t */\n\timage_colour_spaces = Enum [\n\t\t$Mono => B_W,\n\t\t$sRGB => sRGB,\n\t\t$scRGB => scRGB,\n\t\t$RGB16 => RGB16,\n\t\t$GREY16 => GREY16,\n\t\t$Lab => LAB,\n\t\t$LabQ => LABQ,\n\t\t$LabS => LABS,\n\t\t$LCh => LCH,\n\t\t$XYZ => XYZ,\n\t\t$Yxy => YXY,\n\t\t$UCS => UCS\n\t];\n}\n\n/* Base image type. Simple layer over vips_image.\n */\nImage value = class \n\t_Object {\n\t_check_args = [\n\t\t[value, \"value\", check_image]\n\t];\n\n\t// fields from VIPS header\n\twidth = get_width value;\n\theight = get_height value;\n\tbands = get_bands value;\n\tformat = get_format value;\n\tbits = get_bits value;\n\tcoding = get_coding value;\n\ttype = get_type value;\n\txres = get_header \"Xres\" value;\n\tyres = get_header \"Yres\" value;\n\txoffset = get_header \"Xoffset\" value;\n\tyoffset = get_header \"Yoffset\" value;\n\tfilename = get_header \"filename\" value;\n\t\n\t// convenience ... the area our pixels occupy, as a rect\n\trect = Rect 0 0 width height;\n\n\t// operator overloading\n\t// (op Image Vector) done in Vector class\n\too_binary_table op x = [\n\t\t// handle image ++ constant here\n\t\t[wrap join_result_image,\n\t\t\t(has_real x || is_Vector x) &&\n\t\t\t(op.op_name == \"join\" || op.op_name == \"join'\")],\n\t\t[wrap ite_result_image,\n\t\t\top.op_name == \"if_then_else\"],\n\t\t[wrap (op.fn this.value (get_image x)),\n\t\t\thas_image x],\n\t\t[wrap (op.fn this.value (get_number x)),\n\t\t\thas_number x],\n\t\t// if it's not a class on the RHS, handle here ... just apply and\n\t\t// rewrap\n\t\t[wrap (op.fn this.value x),\n\t\t\t!is_class x]\n\t\t// all other cases handled by other classes\n\t] ++ super.oo_binary_table op x\n\t{\n\t\t// wrap the result with this \n\t\t// x can be a non-image, eg. compare \"Image v == []\" vs. \n\t\t// \"Image v == 12\"\n\t\twrap x\n\t\t\t= x, op.type == Operator_type.COMPOUND ||\n\t\t\t\t!is_image x\n\t\t\t= this.Image x;\n\n\t\tjoin_result_image \n\t\t\t= value ++ new_stuff, op.op_name == \"join\"\n\t\t\t= new_stuff ++ value\n\t\t{\n\t\t\tnew_stuff = image_new width height new_bands\n\t\t\t\tformat\n\t\t\t\tcoding\n\t\t\t\tImage_type.B_W x xoffset yoffset;\n\t\t\tnew_bands\n\t\t\t\t= get_bands x, has_bands x\n\t\t\t\t= 1;\n\t\t}\n\n\t\t[then_part, else_part] = x;\n\n\t\t// get things about our output from inputs in this order\n\t\tobjects = [then_part, else_part, this];\n\n\t\t// properties of our output image\n\t\ttarget_bands = get_member_list has_bands get_bands objects;\n\t\ttarget_type = get_member_list has_type get_type objects;\n\n\t\t// if one of then/else is an image, get the target format from that\n\t\t// otherwise, let the non-image objects set the target\n\t\ttarget_format \n\t\t\t= get_member_list has_format get_format x, \n\t\t\t\thas_member_list has_format x\n\t\t\t= NULL;\n\n\t\tto_image x = to_image_size width height target_bands target_format x;\n\n\t\t[then', else'] = map to_image x;\n\n\t\tite_result_image = image_set_type target_type\n\t\t\t(if value then then' else else');\n\t}\n\n\t// FIXME ... yuk ... don't use operator hints, just always rewrap if\n\t// we have an image result\n\t// forced on us by things like abs:\n\t// \tabs Vector -> real\n\t//\tabs Image -> Image\n\t// does not fit well with COMPOUND/whatever scheme\n\too_unary_table op = [\n\t\t[this.Image result,\n\t\t\tis_image result],\n\t\t[result,\n\t\t\ttrue]\n\t] ++ super.oo_unary_table op\n\t{\n\t\tresult = op.fn this.value;\n\t}\n}\n\n/* Construct an image from a file.\n */\nImage_file filename = class \n\tImage value {\n\t_check_args = [\n\t\t[filename, \"filename\", check_string]\n\t];\n\n\tvalue = vips_image filename;\n}\n\nRegion image left top width height = class \n\tImage value {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_preal],\n\t\t[height, \"height\", check_preal]\n\t];\n\n\t// a rect for our coordinates\n\t// region.rect gets the rect for the extracted image\n\tregion_rect = Rect left top width height;\n\n\t// we need to always succeed ... value is our enclosing image if we're\n\t// out of bounds\n\tvalue \n\t\t= extract_area left top width height image.value,\n\t\t\timage.rect.includes_rect region_rect\n\t\t= image.value;\n}\n\nArea image left top width height = class\n\tscope.Region image left top width height {\n\tRegion image left top width height \n\t\t= this.Area image left top width height;\n}\n\nArrow image left top width height = class \n\tscope.Rect left top width height {\n\t_check_args = [\n\t\t[image, \"Image\", check_Image],\n\t\t[left, \"left\", check_real],\n\t\t[top, \"top\", check_real],\n\t\t[width, \"width\", check_real],\n\t\t[height, \"height\", check_real]\n\t];\n\n\tRect l t w h = this.Arrow image l t w h;\n}\n\nHGuide image top = class \n\tscope.Arrow image image.rect.left top image.width 0 {\n\tArrow image left top width height = this.HGuide image top;\n}\n\nVGuide image left = class \n\tscope.Arrow image left image.rect.top 0 image.height {\n\tArrow image left top width height = this.VGuide image left;\n}\n\nMark image left top = class \n\tscope.Arrow image left top 0 0 {\n\tArrow image left top width height = this.Mark image left top;\n}\n\n// convenience functions: ... specify position as [0 .. 1)\n\nRegion_relative image u v w h\n\t= Region image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArea_relative image u v w h\n\t= Area image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nArrow_relative image u v w h\n\t= Arrow image \n\t\t(image.width * u)\n\t\t(image.height * v)\n\t\t(image.width * w)\n\t\t(image.height * h);\n\nVGuide_relative image v \n\t= VGuide image (image.height * v);\n\nHGuide_relative image u \n\t= HGuide image (image.width * u);\n\nMark_relative image u v\n\t= Mark image \n\t\t(image.width * u)\n\t\t(image.height * v);\n\nKernel_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tLINEAR = 1;\n\tCUBIC = 2;\n\tMITCHELL = 3;\n\tLANCZOS2 = 4;\n\tLANCZOS3 = 5;\n\n\t// Should introspect to get the list of interpolators :-(\n\t// We can \"dir\" on VipsInterpolate to get a list of them, but we\n\t// can't get i18n'd descriptions until we have more\n\t// introspection stuff in nip2.\n\n\t/* Table to map kernel numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Linear\", \n\t\t_ \"Cubic\",\n\t\t_ \"Mitchell\",\n\t\t_ \"Lanczos, two lobes\",\n\t\t_ \"Lanczos, three lobes\"\n\t];\n\n\t/* And to vips enum nicknames.\n\t */\n\ttypes = [\n\t\t\"nearest\", \n\t\t\"linear\", \n\t\t\"cubic\", \n\t\t\"mitchell\", \n\t\t\"lanczos2\", \n\t\t\"lanczos3\"\n\t];\n}\n\nKernel type = class {\n\tvalue = Kernel_type.types?type;\n}\n\nKernel_linear = Kernel Kernel_type.LINEAR;\n\nKernel_picker default = class \n\tKernel kernel.value {\n\t_vislevel = 2;\n\n\tkernel = Option \"Kernel\" Kernel_type.descriptions default;\n}\n\nInterpolate_type = class {\n\tNEAREST_NEIGHBOUR = 0;\n\tBILINEAR = 1;\n\tBICUBIC = 2;\n\tLBB = 3;\n\tNOHALO = 4;\n\tVSQBS = 5;\n\n\t// Should introspect to get the list of interpolators :-(\n\t// We can \"dir\" on VipsInterpolate to get a list of them, but we\n\t// can't get i18n'd descriptions until we have more\n\t// introspection stuff in nip2.\n\n\t/* Table to map interpol numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Nearest neighbour\",\n\t\t_ \"Bilinear\", \n\t\t_ \"Bicubic\",\n\t\t_ \"Upsize: reduced halo bicubic (LBB)\",\n\t\t_ \"Upsharp: reduced halo bicubic with edge sharpening (Nohalo)\",\n\t\t_ \"Upsmooth: quadratic B-splines with jaggy reduction (VSQBS)\"\n\t];\n\n\t/* And to vips type names.\n\t */\n\ttypes = [\n\t\t\"VipsInterpolateNearest\",\n\t\t\"VipsInterpolateBilinear\",\n\t\t\"VipsInterpolateBicubic\",\n\t\t\"VipsInterpolateLbb\",\n\t\t\"VipsInterpolateNohalo\",\n\t\t\"VipsInterpolateVsqbs\"\n\t];\n}\n\nInterpolate type options = class {\n\tvalue = vips_object_new Interpolate_type.types?type [] options;\n}\n\nInterpolate_bilinear = Interpolate Interpolate_type.BILINEAR [];\n\nInterpolate_picker default = class \n\tInterpolate interp.value [] {\n\t_vislevel = 2;\n\n\tinterp = Option \"Interpolation\" Interpolate_type.descriptions default;\n}\n\nRender_intent = class {\n\tPERCEPTUAL = 0;\n\tRELATIVE = 1;\n\tSATURATION = 2;\n\tABSOLUTE = 3;\n\n\t/* Table to get names <-> numbers.\n\t */\n\tnames = Enum [\n\t\t_ \"Perceptual\" => PERCEPTUAL,\n\t\t_ \"Relative\" => RELATIVE,\n\t\t_ \"Saturation\" => SATURATION,\n\t\t_ \"Absolute\" => ABSOLUTE\n\t];\n}\n\n// abstract base class for toolkit menus\nMenu = class {}\n\n// a \"----\" line in a menu\nMenuseparator = class Menu {}\n\n// abstract base class for items in menus\nMenuitem label tooltip = class Menu {}\n\nMenupullright label tooltip = class Menuitem label tooltip {}\n\nMenuaction label tooltip = class Menuitem label tooltip {}\n\n/* Plots.\n */\n\nPlot_style = class {\n\tPOINT = 0;\n\tLINE = 1;\n\tSPLINE = 2;\n\tBAR = 3;\n\n\tnames = Enum [\n\t\t_ \"Point\" => POINT,\n\t\t_ \"Line\" => LINE,\n\t\t_ \"Spline\" => SPLINE,\n\t\t_ \"Bar\" => BAR\n\t];\n}\n\nPlot_format = class {\n\tYYYY = 0;\n\tXYYY = 1;\n\tXYXY = 2;\n\n\tnames = Enum [\n\t\t_ \"YYYY\" => YYYY,\n\t\t_ \"XYYY\" => XYXY,\n\t\t_ \"XYXY\" => XYXY\n\t];\n}\n\nPlot_type = class {\n\t/* Lots of Ys (ie. multiple line plots).\n\t */\n\tYYYY = 0;\n\n\t/* First column of matrix is X position, others are Ys (ie. multiple XY \n\t * line plots, all with the same Xes).\n\t */\n\tXYYY = 1;\n\n\t/* Many independent XY plots.\n\t */\n\tXYXY = 2;\n}\n\n/* \"options\" is a list of [\"key\", value] pairs.\n */\nPlot options value = class \n\tscope.Image value {\n\tImage value = this.Plot options value;\n\tto_image dpi = extract_bands 0 3 \n\t\t(graph_export_image (to_real dpi) this);\n}\n\nPlot_matrix options value = class \n\tPlot options (to_image value).value {\n}\n\nPlot_histogram value = class\n\tscope.Plot [] value {\n}\n\nPlot_xy value = class\n\tscope.Plot [$format => Plot_format.XYYY] value {\n}\n\n/* A no-value type. Call it NULL for C-alike fun. Used by Group to indicate\n * empty slots, for example.\n */\nNULL = class \n\t_Object {\n\too_binary_table op x = [\n\t\t// the only operation we allow is equality .. use pointer equality,\n\t\t// this lets us test a == NULL and a != NULL\n\t\t[this === x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"equal\"],\n\t\t[this !== x, \n\t\t\top.type == Operator_type.RELATIONAL &&\n\t\t\top.op_name == \"not_equal\"]\n\t] ++ super.oo_binary_table op x;\n}\n\nBlend_type = class {\n\tCLEAR = 0;\n\tSOURCE = 1;\n\tOVER = 2;\n\tIN = 3;\n\tOUT = 4;\n\tATOP = 5;\n\tDEST = 6;\n\tDEST_OVER = 7;\n\tDEST_IN = 8;\n\tDEST_OUT = 9;\n\tDEST_ATOP = 10;\n\tXOR = 11;\n\tADD = 12;\n\tSATURATE = 13;\n\tMULTIPLY = 14;\n\tSCREEN = 15;\n\tOVERLAY = 16;\n\tDARKEN = 17;\n\tLIGHTEN = 18;\n\tCOLOUR_DODGE = 19;\n\tCOLOUR_BURN = 20;\n\tHARD_LIGHT = 21;\n\tSOFT_LIGHT = 22;\n\tDIFFERENCE = 23;\n\tEXCLUSION = 24;\n\n\t/* Table to map blend numbers to descriptive strings\n\t */\n\tdescriptions = [\n\t\t_ \"Clear\",\n\t\t_ \"Source\",\n\t\t_ \"Over\",\n\t\t_ \"In\",\n\t\t_ \"Out\",\n\t\t_ \"Atop\",\n\t\t_ \"Dest\",\n\t\t_ \"Dest over\",\n\t\t_ \"Dest in\",\n\t\t_ \"Dest out\",\n\t\t_ \"Dest atop\",\n\t\t_ \"Xor\",\n\t\t_ \"Add\",\n\t\t_ \"Saturate\",\n\t\t_ \"Multiply\",\n\t\t_ \"Screen\",\n\t\t_ \"Overlay\",\n\t\t_ \"Darken\",\n\t\t_ \"Lighten\",\n\t\t_ \"Colour dodge\",\n\t\t_ \"Colour burn\",\n\t\t_ \"Hard light\",\n\t\t_ \"Soft light\",\n\t\t_ \"Difference\",\n\t\t_ \"Exclusion\"\n\t];\n\n\t/* And to vips enum nicknames.\n\t */\n\ttypes = Enum [\n\t\t$clear => \"clear\",\n\t\t$source => \"source\",\n\t\t$over => \"over\",\n\t\t$in => \"in\",\n\t\t$out => \"out\",\n\t\t$atop => \"atop\",\n\t\t$dest => \"dest\",\n\t\t$dest_over => \"dest_over\",\n\t\t$dest_in => \"dest_in\",\n\t\t$dest_out => \"dest_out\",\n\t\t$dest_atop => \"dest_atop\",\n\t\t$xor => \"xor\",\n\t\t$add => \"add\",\n\t\t$saturate => \"saturate\",\n\t\t$multiply => \"multiply\",\n\t\t$screen => \"screen\",\n\t\t$overlay => \"overlay\",\n\t\t$darken => \"darken\",\n\t\t$lighten => \"lighten\",\n\t\t$colour_dodge => \"colour_dodge\",\n\t\t$colour_burn => \"colour_burn\",\n\t\t$hard_light => \"hard_light\",\n\t\t$soft_light => \"soft_light\",\n\t\t$difference => \"difference\",\n\t\t$exclusion => \"exclusion\"\n\t];\n}\n\nBlend type = class {\n\tvalue = Blend_type.types?type;\n}\n\nBlend_over = Blend Blend_type.OVER;\n\nBlend_picker default = class \n\tBlend blend.value {\n\t_vislevel = 2;\n\n\tblend = Option \"Blend\" Blend_type.descriptions default;\n}\n\nCombine_type = class {\n\tMAX = 0;\n\tSUM = 1;\n\tMIN = 2;\n\n\tenum = Enum [\n\t\t_ \"Maximum\" => MAX,\n\t\t_ \"Sum\" => SUM,\n\t\t_ \"Minimum\" => MIN\n\t];\n}\n\nCombine type = class {\n\tvalue = Combine_type.enum.names?type;\n}\n\nCombine_sum = Combine Combine_type.SUM;\n\nCombine_picker default = Option \"Combine\" Combine_type.enum.names default;\n"
  },
  {
    "path": "src/BITMAPS/Makefile.am",
    "content": "EXTRA_DIST = \\\n\tant.xbm \\\n\tautomatic.xbm \\\n\tautomatic.xpm \\\n\tautomatic1.xbm \\\n\tautomatic1.xpm \\\n\tautomatic2.xbm \\\n\tautomatic2.xpm \\\n\tautomatic3.xbm \\\n\tautomatic3.xpm \\\n\tchange.xbm \\\n\tconvol.xbm \\\n\tdropper.xpm \\\n\tdropper_msk.xbm \\\n\tdropper_src.xbm \\\n\timage.xbm \\\n\tkill.xbm \\\n\tmag_msk.xbm \\\n\tmagin.xpm \\\n\tmagin_src.xbm \\\n\tmagout.xpm \\\n\tmagout_src.xbm \\\n\tmorph.xbm \\\n\tpan.xpm \\\n\tpaint.xpm \\\n\tprogram.xbm \\\n\tselect.xpm \\\n\tslider.xbm \\\n\twatch_1.xbm \\\n\twatch_2.xbm \\\n\twatch_3.xbm \\\n\twatch_4.xbm \\\n\twatch_5.xbm \\\n\twatch_6.xbm \\\n\twatch_7.xbm \\\n\twatch_8.xbm \\\n\twatch_msk.xbm \\\n\tbook_open.xpm \\\n\tbook_closed.xpm \\\n\ttoolbox_open.xpm \\\n\ttoolbox_closed.xpm \\\n\ttools.xpm \\\n\tcol.xpm \\\n\tseparator.xpm \\\n\tfloppy.xpm \\\n\tmini_page.xpm \n"
  },
  {
    "path": "src/BITMAPS/ant.xbm",
    "content": "#define ant_width 64\n#define ant_height 64\nstatic unsigned char ant_bits[] = {\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0x6a, 0x77,\n   0x77, 0xef, 0xfe, 0x5b, 0x55, 0x55, 0xb5, 0xad, 0xad, 0xb5, 0x6b, 0x17,\n   0xaa, 0x6a, 0x6b, 0xdb, 0x76, 0xdf, 0xde, 0x3d, 0xaa, 0x56, 0xd5, 0xb6,\n   0xad, 0xf5, 0x75, 0x57, 0x55, 0xd5, 0x2a, 0xd5, 0xf6, 0x5e, 0xdf, 0x2d,\n   0xaa, 0xad, 0xa4, 0x54, 0xad, 0xfb, 0x75, 0x3f, 0x55, 0x5b, 0x4a, 0x49,\n   0xdb, 0xae, 0xdf, 0x75, 0xaa, 0xaa, 0x28, 0x92, 0x74, 0xf7, 0xf6, 0x5f,\n   0xd5, 0x16, 0x45, 0x55, 0xad, 0xbd, 0x5b, 0x3b, 0xba, 0xaa, 0xa8, 0x88,\n   0xe8, 0xef, 0xfe, 0x2f, 0xa5, 0x45, 0x05, 0x25, 0x55, 0xbd, 0xab, 0x6a,\n   0x5d, 0x29, 0xaa, 0x48, 0xd2, 0xeb, 0xfe, 0x2d, 0x55, 0x42, 0x91, 0x92,\n   0x54, 0xbf, 0x95, 0x2a, 0xd5, 0x14, 0x24, 0x25, 0xa5, 0x6a, 0xb7, 0x56,\n   0x35, 0xa1, 0x42, 0x4a, 0xaa, 0xdf, 0xad, 0x2a, 0xad, 0x14, 0x94, 0x90,\n   0x54, 0x7a, 0x55, 0x55, 0x55, 0xa0, 0x22, 0x25, 0xd1, 0xaf, 0xa5, 0x2a,\n   0x55, 0x05, 0x48, 0x4a, 0x2a, 0xbd, 0xaa, 0x2a, 0x2a, 0xa8, 0x92, 0x90,\n   0xca, 0xaa, 0x54, 0x55, 0xad, 0x02, 0x44, 0x4a, 0xb2, 0x5e, 0x55, 0x2a,\n   0x2a, 0xa8, 0x90, 0x24, 0xa5, 0xb5, 0xaa, 0x52, 0x95, 0x04, 0x0a, 0x91,\n   0x28, 0xad, 0x4a, 0x55, 0x16, 0x42, 0x20, 0x42, 0xaa, 0xaa, 0x52, 0x6a,\n   0x55, 0x08, 0x82, 0x94, 0xaa, 0x7a, 0x55, 0x35, 0x0a, 0x91, 0x10, 0x20,\n   0x49, 0xa5, 0xaa, 0x6a, 0x55, 0x04, 0x40, 0x55, 0xaa, 0x7a, 0x91, 0x3a,\n   0x0d, 0x51, 0x02, 0x80, 0x4a, 0x65, 0x55, 0x55, 0x55, 0x04, 0x48, 0xaa,\n   0x54, 0xda, 0xaa, 0x3a, 0x0a, 0x91, 0x00, 0x11, 0xa9, 0x6a, 0xa9, 0x16,\n   0x55, 0x44, 0x52, 0xa4, 0x52, 0xd5, 0x52, 0x35, 0x8a, 0x10, 0x08, 0x29,\n   0x95, 0xaa, 0xaa, 0x4a, 0x55, 0x4a, 0xa1, 0x52, 0x6a, 0xad, 0x55, 0x1d,\n   0x95, 0x24, 0x0a, 0x85, 0xaa, 0x56, 0x55, 0x23, 0x15, 0x91, 0x54, 0x69,\n   0x79, 0x4b, 0x55, 0x2d, 0x6b, 0x4a, 0x51, 0x4a, 0xca, 0x92, 0xaa, 0x52,\n   0x96, 0x24, 0x95, 0xaa, 0xb5, 0xa4, 0x92, 0x15, 0x55, 0x49, 0xaa, 0xb4,\n   0x2a, 0x09, 0x25, 0x25, 0xad, 0x92, 0x12, 0xd5, 0x55, 0x52, 0x92, 0x54,\n   0x5b, 0xa4, 0xa4, 0xba, 0xa2, 0x84, 0x4a, 0x55, 0xaa, 0x55, 0x49, 0x6a,\n   0x95, 0x52, 0x11, 0x2a, 0xbb, 0x12, 0x92, 0xaa, 0x24, 0x25, 0xa6, 0x24,\n   0x56, 0xd5, 0xa4, 0xf2, 0x49, 0x45, 0x29, 0x29, 0xed, 0x2a, 0xa9, 0xb6,\n   0x52, 0x5b, 0x4b, 0x2a, 0x5b, 0x55, 0x45, 0x29, 0xd4, 0xaa, 0x54, 0x55,\n   0xb6, 0xab, 0x2a, 0xaa, 0x55, 0x55, 0x95, 0x2a, 0xd5, 0xde, 0x4a, 0x21,\n   0x48, 0xaa, 0x52, 0x25, 0xad, 0xaa, 0x55, 0x4a, 0x95, 0xad, 0xaa, 0x6a,\n   0xdb, 0xb6, 0x96, 0x24, 0x62, 0x6b, 0x95, 0x54, 0xaa, 0x6d, 0x55, 0x49,\n   0x59, 0xda, 0xaa, 0x2a, 0x6d, 0xb5, 0x57, 0x12, 0x52, 0xa7, 0x56, 0x55,\n   0xd5, 0x6a, 0xad, 0xa2, 0x94, 0x68, 0x55, 0x35, 0xad, 0x57, 0xb5, 0x14,\n   0x55, 0xaa, 0x55, 0x6b, 0xb5, 0xac, 0xaa, 0xa2, 0x24, 0x75, 0xd5, 0x36,\n   0x6d, 0xab, 0x54, 0x15, 0xa9, 0xac, 0xad, 0x6a, 0xaa, 0xaa, 0x4a, 0x4a,\n   0x55, 0xdb, 0x5a, 0x5d, 0x55, 0x15, 0x14, 0x54, 0x55, 0xb5, 0xd7, 0x36,\n   0xaa, 0x4a, 0x85, 0xa2, 0xaa, 0x7f, 0x55, 0x6b, 0x55, 0x91, 0x02, 0x54,\n   0x7d, 0xd5, 0x6a, 0x37, 0xaa, 0x4a, 0x4a, 0x48, 0xa5, 0x7f, 0x5b, 0x6d,\n   0x55, 0xa4, 0x02, 0x92, 0xea, 0xea, 0x56, 0x2b, 0x92, 0x12, 0x01, 0x40,\n   0xa8, 0xbd, 0x55, 0x55, 0x2a, 0xa4, 0x0a, 0x12, 0x45, 0xd7, 0xb5, 0x2e,\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n"
  },
  {
    "path": "src/BITMAPS/automatic.xbm",
    "content": "#define automatic_width 32\n#define automatic_height 32\nstatic const unsigned char automatic_bits[] = {\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n   0x00, 0x00, 0x00, 0x00, 0x80, 0xaa, 0xaa, 0x00, 0x40, 0x55, 0x55, 0x01,\n   0x80, 0xff, 0xff, 0x00, 0x40, 0x01, 0x40, 0x01, 0x80, 0x01, 0xc0, 0x00,\n   0x40, 0xe1, 0x47, 0x01, 0x80, 0x11, 0xc8, 0x00, 0x40, 0x09, 0x50, 0x01,\n   0x80, 0x75, 0xd7, 0x00, 0x40, 0xf5, 0x5f, 0x01, 0x80, 0x95, 0xd9, 0x00,\n   0x40, 0x65, 0x56, 0x01, 0x80, 0x35, 0xd0, 0x00, 0x40, 0xf5, 0x50, 0x01,\n   0x80, 0xc5, 0xd4, 0x00, 0x40, 0x05, 0x56, 0x01, 0x80, 0x05, 0xd6, 0x00,\n   0x40, 0xed, 0x53, 0x01, 0x80, 0xd9, 0xd8, 0x00, 0x40, 0x31, 0x4c, 0x01,\n   0x80, 0x21, 0xc2, 0x00, 0x40, 0xff, 0x7f, 0x01, 0x80, 0xaa, 0xaa, 0x00,\n   0x40, 0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n"
  },
  {
    "path": "src/BITMAPS/automatic.xpm",
    "content": "/* XPM */\nstatic char *automatic[]={\n\"32 32 8 1\",\n\". c None\",\n\"d c #000000\",\n\"b c #585858\",\n\"a c #808000\",\n\"# c #a0a0a0\",\n\"c c #c0c000\",\n\"e c #ffc0c0\",\n\"f c #ffffff\",\n\"................................\",\n\"................................\",\n\"................................\",\n\"......###################.......\",\n\"......#aaaaaaaaaaaaaaaaab.......\",\n\"......#abbbbbbbbbbbbbb#ab.......\",\n\"......#abccccccccccccc#ab.......\",\n\"......#abccccccccccccc#ab.......\",\n\"......#abccccddddddccc#ab.......\",\n\"......#abcccdeeeeeedcc#ab.......\",\n\"......#abccdeeeeeeeedc#ab.......\",\n\"......#abcdedddedddedc#ab.......\",\n\"......#abcdedddddddddc#ab.......\",\n\"......#abcdedffddffddc#ab.......\",\n\"......#abcdeeddeeddedc#ab.......\",\n\"......#abcdeddeeeeeedc#ab.......\",\n\"......#abcdeddddeeeedc#ab.......\",\n\"......#abcdeeeddeededc#ab.......\",\n\"......#abcdeeeeeeddedc#ab.......\",\n\"......#abcdeeeeeeddedc#ab.......\",\n\"......#abcddedddddeedc#ab.......\",\n\"......#abccddeddeeeddc#ab.......\",\n\"......#abcccddeeeeddcc#ab.......\",\n\"......#abccccdeeedcccc#ab.......\",\n\"......#a###############ab.......\",\n\"......#aaaaaaaaaaaaaaaaab.......\",\n\"......#bbbbbbbbbbbbbbbbbb.......\",\n\"................................\",\n\"................................\",\n\"................................\",\n\"................................\",\n\"................................\"};\n"
  },
  {
    "path": "src/BITMAPS/automatic1.xbm",
    "content": "#define automatic1_width 32\n#define automatic1_height 32\nstatic const unsigned char automatic1_bits[] = {\n   0x50, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00,\n   0x9e, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x64, 0x03, 0x00, 0x00,\n   0x67, 0x06, 0x00, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x08, 0x53, 0x55, 0x55,\n   0x90, 0xa3, 0xaa, 0xaa, 0x10, 0xcf, 0xff, 0x7f, 0x20, 0xaa, 0x00, 0xa0,\n   0x20, 0xd6, 0x00, 0x60, 0x40, 0xa4, 0x00, 0xa0, 0x80, 0xc8, 0xe0, 0x67,\n   0x80, 0xb0, 0x10, 0xa8, 0x00, 0xd1, 0x08, 0x70, 0x00, 0xa1, 0x74, 0xa7,\n   0x00, 0xa2, 0xb4, 0x6b, 0x00, 0xc4, 0xf4, 0xab, 0x00, 0x84, 0x64, 0x66,\n   0x00, 0x88, 0x35, 0xa0, 0x00, 0x08, 0xf5, 0x60, 0x00, 0xf0, 0xc7, 0xb0,\n   0x00, 0xc0, 0x64, 0x70, 0x00, 0xa0, 0xe4, 0xb1, 0x00, 0xc0, 0xcc, 0x73,\n   0x00, 0xa0, 0x18, 0xbb, 0x00, 0xc0, 0x10, 0x6c, 0x00, 0xa0, 0xff, 0xbf,\n   0x00, 0x40, 0x55, 0x55, 0x00, 0xa0, 0xaa, 0xaa};\n"
  },
  {
    "path": "src/BITMAPS/automatic1.xpm",
    "content": "/* XPM */\nstatic char *automatic1[]={\n\"32 32 8 1\",\n\". c None\",\n\"# c #000000\",\n\"d c #585858\",\n\"c c #808000\",\n\"b c #a0a0a0\",\n\"e c #c0c000\",\n\"f c #ffc0c0\",\n\"a c #ffffff\",\n\"....#a#.........................\",\n\"#...#a##........................\",\n\"##..#aa#........................\",\n\"a####aa##.......................\",\n\"aa##aaaa#.......................\",\n\"aa#aa##a##......................\",\n\"###aa##aa##.....................\",\n\"..#aaaaaa###....................\",\n\"...#aaaa##aa#bbbbbbbbbbbbbbbbbbb\",\n\"....#aa###aa.bcccccccccccccccccd\",\n\"....#aaa####abcddddddddddddddbcd\",\n\".....#aaa#.#.bcdeeeeeeeeeeeeebcd\",\n\".....#aaa##.#bcdeeeeeeeeeeeeebcd\",\n\"......#aaa#..bcdeeeeeeeeeeeeebcd\",\n\".......#aaa#.bcdeeeee######eebcd\",\n\".......#aaaa#bcdeeee#ffffff#ebcd\",\n\"........#aaa#bcdeee#ffffffff#bcd\",\n\"........#aaaa#cdee#f###f###ffbcd\",\n\".........#aaa#cdee#f##a###a#fbcd\",\n\"..........#aaa#dee#f######a#fbcd\",\n\"..........#aaaa#ee#ff##ff##ffbcd\",\n\"...........#aaa##e#f##fffffffbcd\",\n\"...........#aaaa#e#f####fffffbcd\",\n\"............#####e#fff##ffff#bcd\",\n\".............bcdee#ff##fffff#bcd\",\n\".............bcdee#ff####fff#bcd\",\n\".............bcdee##ff####ff#bcd\",\n\".............bcdeee##fff##f##bcd\",\n\".............bcdeeee#fffff##ebcd\",\n\".............bcbbbbbbbbbbbbbbbcd\",\n\".............bcccccccccccccccccd\",\n\".............bdddddddddddddddddd\"};\n"
  },
  {
    "path": "src/BITMAPS/automatic2.xbm",
    "content": "#define automatic2_width 32\n#define automatic2_height 32\nstatic const unsigned char automatic2_bits[] = {\n   0xe0, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00,\n   0x9e, 0x01, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x64, 0x0f, 0x00, 0x00,\n   0x64, 0x12, 0x00, 0x00, 0x07, 0x72, 0x00, 0x00, 0x0c, 0x43, 0x55, 0x55,\n   0x88, 0xa6, 0xaa, 0xaa, 0x10, 0xc9, 0xff, 0x7f, 0x10, 0xb2, 0x00, 0xa0,\n   0x20, 0xc2, 0x00, 0x60, 0x20, 0xa4, 0x00, 0xa0, 0x40, 0xc4, 0xe0, 0x67,\n   0x40, 0xa8, 0x10, 0xa8, 0x80, 0xc8, 0x08, 0x70, 0x80, 0xb0, 0x74, 0xa7,\n   0x00, 0xd1, 0xb4, 0x6b, 0x00, 0xa1, 0xf4, 0xab, 0x00, 0xe2, 0x64, 0x66,\n   0x00, 0xc2, 0x34, 0xa0, 0x00, 0xc4, 0xf4, 0x60, 0x00, 0xc4, 0xc4, 0xb0,\n   0x00, 0xf8, 0x64, 0x70, 0x00, 0xa0, 0xe4, 0xb1, 0x00, 0xc0, 0xcc, 0x73,\n   0x00, 0xa0, 0x18, 0xbb, 0x00, 0xc0, 0x10, 0x6c, 0x00, 0xa0, 0xff, 0xbf,\n   0x00, 0x40, 0x55, 0x55, 0x00, 0xa0, 0xaa, 0xaa};\n"
  },
  {
    "path": "src/BITMAPS/automatic2.xpm",
    "content": "/* XPM */\nstatic char *automatic2[]={\n\"32 32 8 1\",\n\". c None\",\n\"# c #000000\",\n\"d c #585858\",\n\"c c #808000\",\n\"b c #a0a0a0\",\n\"e c #c0c000\",\n\"f c #ffc0c0\",\n\"a c #ffffff\",\n\".....#a#........................\",\n\"....#aa#........................\",\n\"#...#aa#........................\",\n\"a####aa##.......................\",\n\"aa##aaaa##......................\",\n\"aa#aa##a####....................\",\n\"aa#aa##aa#aa#...................\",\n\"###aaaaaa#aa###.................\",\n\"..##aaaa##aaabbbbbbbbbbbbbbbbbbb\",\n\"...#aaa#.##aabcccccccccccccccccd\",\n\"....#aaa#..#abcddddddddddddddbcd\",\n\"....#aaaa#..#bcdeeeeeeeeeeeeebcd\",\n\".....#aaa#...bcdeeeeeeeeeeeeebcd\",\n\".....#aaaa#..bcdeeeeeeeeeeeeebcd\",\n\"......#aaa#..bcdeeeee######eebcd\",\n\"......#aaaa#.bcdeeee#ffffff#ebcd\",\n\".......#aaa#.bcdeee#ffffffff#bcd\",\n\".......#aaaa#bcdee#f###f###ffbcd\",\n\"........#aaa#bcdee#f##a###a#fbcd\",\n\"........#aaaa#cdee#f######a#fbcd\",\n\".........#aaa#cdee#ff##ff##ffbcd\",\n\".........#aaaa#dee#f##fffffffbcd\",\n\"..........#aaa#dee#f####fffffbcd\",\n\"..........#aaa#dee#fff##ffff#bcd\",\n\"...........####dee#ff##fffff#bcd\",\n\".............bcdee#ff####fff#bcd\",\n\".............bcdee##ff####ff#bcd\",\n\".............bcdeee##fff##f##bcd\",\n\".............bcdeeee#fffff##ebcd\",\n\".............bcbbbbbbbbbbbbbbbcd\",\n\".............bcccccccccccccccccd\",\n\".............bdddddddddddddddddd\"};\n"
  },
  {
    "path": "src/BITMAPS/automatic3.xbm",
    "content": "#define automatic3_width 32\n#define automatic3_height 32\nstatic const unsigned char automatic3_bits[] = {\n   0x33, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00,\n   0x9c, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x66, 0x03, 0x00, 0x00,\n   0x64, 0x06, 0x00, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x08, 0x53, 0x55, 0x55,\n   0x90, 0xa3, 0xaa, 0xaa, 0x30, 0xc2, 0xff, 0x7f, 0x20, 0xa4, 0x00, 0xa0,\n   0x40, 0xc8, 0x00, 0x60, 0x80, 0xa8, 0x00, 0xa0, 0x80, 0xd0, 0xe0, 0x67,\n   0x00, 0xa1, 0x10, 0xa8, 0x00, 0xc2, 0x08, 0x70, 0x00, 0xc4, 0x74, 0xa7,\n   0x00, 0x84, 0xb5, 0x6b, 0x00, 0x08, 0xf5, 0xab, 0x00, 0x10, 0x66, 0x66,\n   0x00, 0x30, 0x34, 0xa0, 0x00, 0x20, 0xfc, 0x60, 0x00, 0xe0, 0xcf, 0xb0,\n   0x00, 0xc0, 0x64, 0x70, 0x00, 0xa0, 0xe4, 0xb1, 0x00, 0xc0, 0xcc, 0x73,\n   0x00, 0xa0, 0x18, 0xbb, 0x00, 0xc0, 0x10, 0x6c, 0x00, 0xa0, 0xff, 0xbf,\n   0x00, 0x40, 0x55, 0x55, 0x00, 0xa0, 0xaa, 0xaa};\n"
  },
  {
    "path": "src/BITMAPS/automatic3.xpm",
    "content": "/* XPM */\nstatic char *automatic3[]={\n\"32 32 8 1\",\n\"a c None\",\n\". c #000000\",\n\"d c #585858\",\n\"c c #808000\",\n\"b c #a0a0a0\",\n\"e c #c0c000\",\n\"f c #ffc0c0\",\n\"# c #ffffff\",\n\"..##..aaaaaaaaaaaaaaaaaaaaaaaaaa\",\n\"#..###..aaaaaaaaaaaaaaaaaaaaaaaa\",\n\"##...##.aaaaaaaaaaaaaaaaaaaaaaaa\",\n\"##...##..aaaaaaaaaaaaaaaaaaaaaaa\",\n\".#..####.aaaaaaaaaaaaaaaaaaaaaaa\",\n\"a..##..#..aaaaaaaaaaaaaaaaaaaaaa\",\n\"aa.##..##..aaaaaaaaaaaaaaaaaaaaa\",\n\"aa.######...aaaaaaaaaaaaaaaaaaaa\",\n\"aaa.####..##.bbbbbbbbbbbbbbbbbbb\",\n\"aaaa.##...###bcccccccccccccccccd\",\n\"aaaa..###.###bcddddddddddddddbcd\",\n\"aaaaa.####.##bcdeeeeeeeeeeeeebcd\",\n\"aaaaaa.####.#bcdeeeeeeeeeeeeebcd\",\n\"aaaaaaa.###.#bcdeeeeeeeeeeeeebcd\",\n\"aaaaaaa.####.bcdeeeee......eebcd\",\n\"aaaaaaaa.####.cdeeee.ffffff.ebcd\",\n\"aaaaaaaaa.####.deee.ffffffff.bcd\",\n\"aaaaaaaaaa.###.dee.f...f...ffbcd\",\n\"aaaaaaaaaa.####..e.f..#...#.fbcd\",\n\"aaaaaaaaaaa.####.e.f......#.fbcd\",\n\"aaaaaaaaaaaa.####..ff..ff..ffbcd\",\n\"aaaaaaaaaaaaa.####.f..fffffffbcd\",\n\"aaaaaaaaaaaaab.###......fffffbcd\",\n\"aaaaaaaaaaaaabc.....ff..ffff.bcd\",\n\"aaaaaaaaaaaaabcdee.ff..fffff.bcd\",\n\"aaaaaaaaaaaaabcdee.ff....fff.bcd\",\n\"aaaaaaaaaaaaabcdee..ff....ff.bcd\",\n\"aaaaaaaaaaaaabcdeee..fff..f..bcd\",\n\"aaaaaaaaaaaaabcdeeee.fffff..ebcd\",\n\"aaaaaaaaaaaaabcbbbbbbbbbbbbbbbcd\",\n\"aaaaaaaaaaaaabcccccccccccccccccd\",\n\"aaaaaaaaaaaaabdddddddddddddddddd\"};\n"
  },
  {
    "path": "src/BITMAPS/book_closed.xpm",
    "content": "/* XPM */\nstatic char * book_closed_xpm[] = {\n\"16 16 6 1\",\n\"       c None s None\",\n\".      c black\",\n\"X      c red\",\n\"o      c yellow\",\n\"O      c #808080\",\n\"#      c white\",\n\"                \",\n\"       ..       \",\n\"     ..XX.      \",\n\"   ..XXXXX.     \",\n\" ..XXXXXXXX.    \",\n\".ooXXXXXXXXX.   \",\n\"..ooXXXXXXXXX.  \",\n\".X.ooXXXXXXXXX. \",\n\".XX.ooXXXXXX..  \",\n\" .XX.ooXXX..#O  \",\n\"  .XX.oo..##OO. \",\n\"   .XX..##OO..  \",\n\"    .X.#OO..    \",\n\"     ..O..      \",\n\"      ..        \",\n\"                \"};\n"
  },
  {
    "path": "src/BITMAPS/book_open.xpm",
    "content": "/* XPM */\nstatic char * book_open_xpm[] = {\n\"16 16 4 1\",\n\"       c None s None\",\n\".      c black\",\n\"X      c #808080\",\n\"o      c white\",\n\"                \",\n\"  ..            \",\n\" .Xo.    ...    \",\n\" .Xoo. ..oo.    \",\n\" .Xooo.Xooo...  \",\n\" .Xooo.oooo.X.  \",\n\" .Xooo.Xooo.X.  \",\n\" .Xooo.oooo.X.  \",\n\" .Xooo.Xooo.X.  \",\n\" .Xooo.oooo.X.  \",\n\"  .Xoo.Xoo..X.  \",\n\"   .Xo.o..ooX.  \",\n\"    .X..XXXXX.  \",\n\"    ..X.......  \",\n\"     ..         \",\n\"                \"};\n"
  },
  {
    "path": "src/BITMAPS/change.xbm",
    "content": "#define change_width 32\n#define change_height 32\nstatic unsigned char change_bits[] = {\n   0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xfd, 0xff, 0xb2, 0x01, 0x0b, 0xd8,\n   0xb3, 0x01, 0x0d, 0xd8, 0xfe, 0xff, 0xfb, 0xff, 0x55, 0x55, 0x55, 0x55,\n   0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,\n   0xff, 0xff, 0xfd, 0xff, 0x02, 0x1b, 0x8b, 0x0d, 0x03, 0x1b, 0x8d, 0x0d,\n   0xfe, 0xff, 0xfb, 0xff, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa,\n   0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xfd, 0xff,\n   0xda, 0x00, 0x6b, 0x03, 0xdb, 0x00, 0x6d, 0x03, 0xfe, 0xff, 0xfb, 0xff,\n   0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,\n   0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xfd, 0xff, 0x02, 0x1b, 0x8b, 0x0d,\n   0x03, 0x1b, 0x8d, 0x0d, 0xfe, 0xff, 0xfb, 0xff, 0x55, 0x55, 0x55, 0x55,\n   0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55};\n"
  },
  {
    "path": "src/BITMAPS/col.xpm",
    "content": "/* XPM */\nstatic char *col[]={\n\"16 16 8 1\",\n\". c None\",\n\"# c #000000\",\n\"f c #303030\",\n\"e c #585858\",\n\"b c #808080\",\n\"d c #a0a0a0\",\n\"c c #c3c3c3\",\n\"a c #ffffff\",\n\"....#aaaaaaaaaa#\",\n\"....#aaaaaaaaaa#\",\n\"....############\",\n\"......#bca#bc#..\",\n\"......#bca#bc#..\",\n\"......#bca#bc#..\",\n\"......#bca#bc#..\",\n\"d.....#bca#bc#..\",\n\"ddd...#bca#bc#..\",\n\"eedd..#bca#bc#..\",\n\"eeeddd#bca#bc#..\",\n\"eeeeee#bca#bc#..\",\n\"ffeeee#bca#bc#..\",\n\"#ffe############\",\n\"##ff#aaaaaaaaaa#\",\n\"###f#aaaaaaaaaa#\"};\n"
  },
  {
    "path": "src/BITMAPS/convol.xbm",
    "content": "#define convol_width 32\n#define convol_height 32\nstatic unsigned char convol_bits[] = {\n   0x00, 0x00, 0x00, 0x00, 0x84, 0x3c, 0xf3, 0x1e, 0xc6, 0xa0, 0x44, 0x02,\n   0xa4, 0x10, 0x62, 0x0e, 0xe4, 0x09, 0x81, 0x10, 0x84, 0x88, 0x80, 0x10,\n   0x8e, 0x88, 0x77, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x31, 0x86, 0x08,\n   0x42, 0x4a, 0xc9, 0x0c, 0x8e, 0x49, 0xa9, 0x08, 0x52, 0x4a, 0xee, 0x09,\n   0x52, 0x4a, 0x88, 0x08, 0x8c, 0x31, 0x86, 0x1c, 0x00, 0x00, 0x00, 0x00,\n   0x0c, 0x91, 0x67, 0x0c, 0x92, 0x99, 0x90, 0x12, 0x52, 0x91, 0x43, 0x08,\n   0xd2, 0x13, 0x24, 0x04, 0x12, 0x11, 0x14, 0x02, 0x0c, 0xb9, 0xf3, 0x1e,\n   0x00, 0x00, 0x00, 0x00, 0x9e, 0x21, 0xe6, 0x19, 0x48, 0x32, 0x09, 0x25,\n   0x0c, 0x29, 0x86, 0x10, 0x90, 0x78, 0x49, 0x08, 0x50, 0x20, 0x49, 0x04,\n   0xce, 0x23, 0x46, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n"
  },
  {
    "path": "src/BITMAPS/dropper.xpm",
    "content": "/* XPM */\nstatic char * dropper_xpm[] = {\n/* width height ncolors cpp [x_hot y_hot] */\n\"16 16 4 1 -1 -1\",\n/* colors */\n\" \ts none\tm none\tc none\",\n\".\ts iconColor1\tm black\tc black\",\n\"X\ts iconColor2\tm white\tc white\",\n\"o\ts iconGray2\tm gray\tc #909090909090\",\n/* pixels */\n\"          ...   \",\n\"         .XX... \",\n\"         .X.... \",\n\"         .......\",\n\"         .......\",\n\"       .........\",\n\"       XX......o\",\n\"      X.XX.oooo \",\n\"     X.XXX.o    \",\n\"    X.XXXooo    \",\n\"   X.XXXo       \",\n\"  X.XXXo        \",\n\" X.XXXo         \",\n\" XXXXo          \",\n\"XXXXo           \",\n\"XXoo            \"};\n"
  },
  {
    "path": "src/BITMAPS/dropper_msk.xbm",
    "content": "#define dropper_msk_width 16\n#define dropper_msk_height 16\nstatic unsigned char dropper_msk_bits[] = {\n   0x00, 0x3c, 0x00, 0x7e, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x80, 0xff,\n   0x80, 0x7f, 0xc0, 0x07, 0xe0, 0x07, 0xf0, 0x01, 0xf8, 0x00, 0x7c, 0x00,\n   0x3e, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x03, 0x00};\n"
  },
  {
    "path": "src/BITMAPS/dropper_src.xbm",
    "content": "#define dropper_src_width 16\n#define dropper_src_height 16\nstatic unsigned char dropper_src_bits[] = {\n   0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n   0x80, 0x01, 0x40, 0x03, 0xa0, 0x03, 0xd0, 0x01, 0xe8, 0x00, 0x74, 0x00,\n   0x3a, 0x00, 0x1e, 0x00, 0x0f, 0x00, 0x03, 0x00};\n"
  },
  {
    "path": "src/BITMAPS/floppy.xpm",
    "content": "/* XPM */\nstatic char *floppy[]={\n\"16 16 10 1\",\n\". c None\",\n\"# c #000000\",\n\"e c #000080\",\n\"c c #0000c0\",\n\"a c #0000ff\",\n\"b c #303030\",\n\"g c #808080\",\n\"h c #a0a0a4\",\n\"f c #c0c0c0\",\n\"d c #ffffff\",\n\"................\",\n\".......#........\",\n\"......#ab#......\",\n\".....#acdd##....\",\n\"....#acddddd##..\",\n\"...#acdddddddc##\",\n\"..#aeaacddddcae#\",\n\".#aefeeaacdcae#.\",\n\"#aefaffeeacae#..\",\n\"#egfffhaaeae#...\",\n\".##g.haaeae#....\",\n\"...##gaeae#.....\",\n\".....##ee#......\",\n\".......##.......\",\n\"................\",\n\"................\"};\n"
  },
  {
    "path": "src/BITMAPS/image.xbm",
    "content": "#define program_width 32\n#define program_height 32\nstatic unsigned char program_bits[] = {\n   0x55, 0x55, 0x55, 0x55, 0xfe, 0xff, 0xff, 0xff, 0x03, 0x10, 0x00, 0x40,\n   0x02, 0x18, 0x00, 0xc0, 0x03, 0x08, 0x00, 0x40, 0x02, 0x00, 0x38, 0xc0,\n   0x03, 0x1c, 0xcc, 0x40, 0x02, 0x34, 0xc4, 0xc0, 0x03, 0xa0, 0x00, 0x40,\n   0x02, 0x90, 0x78, 0xc0, 0x03, 0x90, 0x5c, 0x40, 0x02, 0xc0, 0x18, 0xc0,\n   0x03, 0x20, 0x00, 0x40, 0x02, 0x30, 0x00, 0xc0, 0x03, 0x10, 0x00, 0x40,\n   0x02, 0x18, 0x06, 0xc0, 0x03, 0x08, 0x0c, 0x40, 0x02, 0xd0, 0x08, 0xc0,\n   0x03, 0xb0, 0x0f, 0x40, 0x02, 0x00, 0x00, 0xc0, 0x03, 0x80, 0x00, 0x40,\n   0x02, 0xc0, 0x01, 0xc0, 0x03, 0x80, 0x7f, 0x40, 0x02, 0x00, 0x39, 0xc0,\n   0x03, 0x00, 0x00, 0x40, 0x02, 0x00, 0x01, 0xe0, 0x03, 0x00, 0x1f, 0x60,\n   0x02, 0x00, 0x1c, 0xf0, 0x03, 0x00, 0x30, 0x58, 0x02, 0x00, 0xe0, 0xfe,\n   0xff, 0xff, 0xff, 0x7f, 0xaa, 0xaa, 0xaa, 0xaa};\n"
  },
  {
    "path": "src/BITMAPS/kill.xbm",
    "content": "#define kill_width 16\n#define kill_height 16\nstatic unsigned char kill_bits[] = {\n   0x04, 0xc0, 0x0a, 0xe0, 0x16, 0x70, 0x2e, 0xb8, 0x5c, 0x5c, 0xb8, 0x2e,\n   0x70, 0x17, 0xe0, 0x0a, 0xc0, 0x05, 0xe0, 0x0a, 0x70, 0x17, 0xb8, 0x2e,\n   0x5c, 0x5c, 0x2e, 0xb8, 0x16, 0x70, 0x0a, 0xe0};\n"
  },
  {
    "path": "src/BITMAPS/mag_msk.xbm",
    "content": "#define mag_msk_width 16\n#define mag_msk_height 16\nstatic unsigned char mag_msk_bits[] = {\n   0xf0, 0x00, 0xfc, 0x03, 0xfe, 0x07, 0xfe, 0x07, 0xff, 0x0f, 0xff, 0x0f,\n   0xff, 0x0f, 0xff, 0x0f, 0xfe, 0x07, 0xfe, 0x0f, 0xfc, 0x1f, 0xf0, 0x3e,\n   0x00, 0x7c, 0x00, 0xf8, 0x00, 0xf0, 0x00, 0xe0};\n"
  },
  {
    "path": "src/BITMAPS/magin.xpm",
    "content": "/* XPM */\nstatic char * magin_xpm[] = {\n/* width height ncolors cpp [x_hot y_hot] */\n\"16 16 4 1 -1 -1\",\n/* colors */\n\" \ts none\tm none\tc none\",\n\".\ts iconColor1\tm black\tc black\",\n\"X\ts iconColor2\tm white\tc white\",\n\"o\ts iconGray1\tm white\tc #dededededede\",\n/* pixels */\n\"    ....        \",\n\"  ..XXXX..      \",\n\" .XXXXXXXX.     \",\n\" .XXX..XXX.     \",\n\".XXXX..XXXX.    \",\n\".XX......XX.o   \",\n\".XX......XX.o   \",\n\".XXXX..XXXX.o   \",\n\" .XXX..XXX.o    \",\n\" .XXXXXXXX..o   \",\n\"  ..XXXX...X.   \",\n\"    ....o.X.X.  \",\n\"     ooo o...X. \",\n\"           ...X.\",\n\"            ...X\",\n\"             ...\"};\n"
  },
  {
    "path": "src/BITMAPS/magin_src.xbm",
    "content": "#define magin_src_width 16\n#define magin_src_height 16\nstatic unsigned char magin_src_bits[] = {\n   0x00, 0x00, 0xf0, 0x00, 0xfc, 0x03, 0x9c, 0x03, 0x9e, 0x07, 0x06, 0x06,\n   0x06, 0x06, 0x9e, 0x07, 0x9c, 0x03, 0xfc, 0x03, 0xf0, 0x08, 0x00, 0x14,\n   0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00};\n"
  },
  {
    "path": "src/BITMAPS/magout.xpm",
    "content": "/* XPM */\nstatic char * magout_xpm[] = {\n/* width height ncolors cpp [x_hot y_hot] */\n\"16 16 4 1 -1 -1\",\n/* colors */\n\" \ts none\tm none\tc none\",\n\".\ts iconColor1\tm black\tc black\",\n\"X\ts iconColor2\tm white\tc white\",\n\"o\ts iconGray1\tm white\tc #dededededede\",\n/* pixels */\n\"    ....        \",\n\"  ..XXXX..      \",\n\" .XXXXXXXX.     \",\n\" .XXXXXXXX.     \",\n\".XXXXXXXXXX.    \",\n\".XX......XX.o   \",\n\".XX......XX.o   \",\n\".XXXXXXXXXX.o   \",\n\" .XXXXXXXX.o    \",\n\" .XXXXXXXX..o   \",\n\"  ..XXXX...X.   \",\n\"    ....o.X.X.  \",\n\"     ooo o...X. \",\n\"           ...X.\",\n\"            ...X\",\n\"             ...\"};\n"
  },
  {
    "path": "src/BITMAPS/magout_src.xbm",
    "content": "#define magout_src_width 16\n#define magout_src_height 16\nstatic unsigned char magout_src_bits[] = {\n   0x00, 0x00, 0xf0, 0x00, 0xfc, 0x03, 0xfc, 0x03, 0xfe, 0x07, 0x06, 0x06,\n   0x06, 0x06, 0xfe, 0x07, 0xfc, 0x03, 0xfc, 0x03, 0xf0, 0x08, 0x00, 0x14,\n   0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00, 0x00};\n"
  },
  {
    "path": "src/BITMAPS/mini_page.xpm",
    "content": "/* XPM */\nstatic char * mini_page_xpm[] = {\n\"16 16 4 1\",\n\"       c None s None\",\n\".      c black\",\n\"X      c white\",\n\"o      c #808080\",\n\"                \",\n\"   .......      \",\n\"   .XXXXX..     \",\n\"   .XoooX.X.    \",\n\"   .XXXXX....   \",\n\"   .XooooXoo.o  \",\n\"   .XXXXXXXX.o  \",\n\"   .XooooooX.o  \",\n\"   .XXXXXXXX.o  \",\n\"   .XooooooX.o  \",\n\"   .XXXXXXXX.o  \",\n\"   .XooooooX.o  \",\n\"   .XXXXXXXX.o  \",\n\"   ..........o  \",\n\"    oooooooooo  \",\n\"                \"};\n"
  },
  {
    "path": "src/BITMAPS/morph.xbm",
    "content": "#define morph_width 32\n#define morph_height 32\nstatic unsigned char morph_bits[] = {\n   0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00,\n   0xf8, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00,\n   0x10, 0x07, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0xfe, 0x30, 0x00, 0x00,\n   0xba, 0x28, 0x00, 0x00, 0x12, 0x99, 0x00, 0x00, 0xd6, 0xde, 0x00, 0x00,\n   0xe0, 0x6d, 0x03, 0x00, 0xb8, 0x10, 0x00, 0x00, 0x7c, 0x07, 0x00, 0x00,\n   0xce, 0x03, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0xc0, 0x00,\n   0xe0, 0x03, 0xe6, 0x00, 0xf0, 0x07, 0xfe, 0x00, 0xf8, 0x0f, 0xfc, 0x01,\n   0x60, 0x13, 0xf0, 0x03, 0x60, 0x33, 0xfc, 0x07, 0x60, 0x7e, 0xfe, 0x3f,\n   0xe0, 0xfe, 0xfe, 0x7f, 0xc0, 0xf1, 0xff, 0x7f, 0xc0, 0xff, 0xfe, 0x7f,\n   0x00, 0x7f, 0xfa, 0xff, 0x00, 0x30, 0xfc, 0xff, 0x00, 0x10, 0xfe, 0x7f,\n   0x00, 0x00, 0xff, 0x33, 0x00, 0x00, 0x87, 0x01};\n"
  },
  {
    "path": "src/BITMAPS/paint.xpm",
    "content": "/* XPM */\nstatic char * paint_xpm[] = {\n/* width height ncolors cpp [x_hot y_hot] */\n\"16 16 4 1 -1 -1\",\n/* colors */\n\" \ts none\tm none\tc none\",\n\".\ts iconColor2\tm white\tc white\",\n\"x\ts iconColor1\tm black\tc black\",\n\"a\ts iconGray2\tm gray\tc #909090909090\",\n/* pixels */\n\"           x..xa\",\n\"          x..xaa\",\n\"          x..xa \",\n\"         x..xaa \",\n\"         x..xa  \",\n\"        x..xaa  \",\n\"        x..xa   \",\n\"       xxxxaa   \",\n\"      x..xxa    \",\n\"     x...xxa    \",\n\"     x..axxa    \",\n\"    x..axxaa    \",\n\"    x.axxaa     \",\n\"   x.axxaa      \",\n\"  xxxxaaa       \",\n\"   aaaa         \"};\n"
  },
  {
    "path": "src/BITMAPS/pan.xpm",
    "content": "/* XPM */\nstatic char * pan_xpm[] = {\n/* width height ncolors cpp [x_hot y_hot] */\n\"16 16 3 1 -1 -1\",\n/* colors */\n\" \ts none\tm none\tc none\",\n\".\ts iconColor1\tm black\tc black\",\n\"X\tc #929292929292\",\n/* pixels */\n\"       .        \",\n\"      ...       \",\n\"     .....      \",\n\"       .XXX     \",\n\"       .X       \",\n\"  .    .X   .   \",\n\" ..    .X   ..  \",\n\"............... \",\n\" ..XXXX.XXXX..XX\",\n\"  .X   .X   .XX \",\n\"   X   .X    X  \",\n\"       .X       \",\n\"     .....      \",\n\"      ...X      \",\n\"       .X       \",\n\"       X        \"};\n"
  },
  {
    "path": "src/BITMAPS/program.xbm",
    "content": "#define program_width 32\n#define program_height 32\nstatic unsigned char program_bits[] = {\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n   0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,\n   0x20, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x30, 0xf8, 0x38, 0x00, 0x28,\n   0x20, 0x44, 0x7c, 0x24, 0x10, 0x44, 0x00, 0x22, 0x10, 0x44, 0x7c, 0x7e,\n   0x10, 0x64, 0x01, 0x20, 0x10, 0x98, 0x00, 0x20, 0x12, 0x00, 0x00, 0x00,\n   0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n   0x00, 0x00, 0x84, 0x03, 0x40, 0x00, 0x46, 0x04, 0x30, 0x00, 0x04, 0x04,\n   0x48, 0x7c, 0x04, 0x02, 0x48, 0x00, 0x04, 0x01, 0x30, 0x7c, 0x84, 0x00,\n   0x08, 0x00, 0x44, 0x00, 0x70, 0x00, 0xce, 0x07, 0x88, 0x01, 0x00, 0x00,\n   0x08, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00,\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n"
  },
  {
    "path": "src/BITMAPS/select.xpm",
    "content": "/* XPM */\nstatic char * select_xpm[] = {\n/* width height ncolors cpp [x_hot y_hot] */\n\"16 16 5 1 -1 -1\",\n/* colors */\n\" \ts iconColor2\tm white\tc white\",\n\".\ts iconColor1\tm black\tc black\",\n\"X\ts iconGray2\tm white\tc #bdbdbdbdbdbd\",\n\"o\ts none\tm none\tc none\",\n\"O\ts iconGray3\tm white\tc #adadadadadad\",\n/* pixels */\n\"               .\",\n\" XXXXXXXXXXXXXX.\",\n\" X............X.\",\n\" X.      .ooo X.\",\n\" X. OOOOO.ooo X.\",\n\" X. OX.XO.ooo X.\",\n\" X. O...O.ooo X.\",\n\" X. O.X.O.ooo X.\",\n\" X. OOOOO.ooo X.\",\n\" X........ooo X.\",\n\" X.oooooooooo X.\",\n\" X.oooooooooo X.\",\n\" X.oooooooooo X.\",\n\" X.           X.\",\n\" XXXXXXXXXXXXXX.\",\n\"................\"};\n"
  },
  {
    "path": "src/BITMAPS/separator.xpm",
    "content": "/* XPM */\nstatic char *separator[]={\n\"64 4 6 1\",\n\"# c #000040\",\n\". c #0000ff\",\n\"c c #0080ff\",\n\"a c #58a8ff\",\n\"b c #a8dcff\",\n\"d c #ffffff\",\n\".##############################################################.\",\n\"a..............................................................a\",\n\"bbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccbb\",\n\"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\"};\n"
  },
  {
    "path": "src/BITMAPS/slider.xbm",
    "content": "#define slider_width 32\n#define slider_height 32\nstatic unsigned char slider_bits[] = {\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00,\n   0x00, 0x93, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00,\n   0x00, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n   0xfc, 0xff, 0xff, 0x3f, 0x04, 0x36, 0x00, 0x20, 0x04, 0x36, 0x00, 0x20,\n   0xfc, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00,\n   0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x0f, 0x00,\n   0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00,\n   0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00,\n   0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n"
  },
  {
    "path": "src/BITMAPS/toolbox_closed.xpm",
    "content": "/* XPM */\nstatic char *toolbox_closed[]={\n\"16 16 10 1\",\n\". c None\",\n\"a c #000000\",\n\"b c #2b1702\",\n\"c c #482704\",\n\"f c #8c4c07\",\n\"h c #ca6d0a\",\n\"# c #cacbcb\",\n\"d c #ed800c\",\n\"g c #ffff00\",\n\"e c #ffffff\",\n\".............#..\",\n\".........abcc...\",\n\".......ccabdec..\",\n\".....cccfabeecc.\",\n\"...ccccffaddddc.\",\n\"..cfffccddddcfc.\",\n\".bfffffcddccgfc.\",\n\".afffffcacgggdc.\",\n\".bbbcccccfgaddf.\",\n\".cfhhhhbffgdddf.\",\n\".cffhhhcddddddf.\",\n\".cfffhhcddddff..\",\n\".ccffhhcddff....\",\n\".accffhcff......\",\n\".aaccccc........\",\n\"................\"};\n"
  },
  {
    "path": "src/BITMAPS/toolbox_open.xpm",
    "content": "/* XPM */\nstatic char *toolbox_open[]={\n\"16 16 12 1\",\n\". c None\",\n\"b c #000000\",\n\"h c #2b1702\",\n\"a c #482704\",\n\"c c #82683b\",\n\"i c #8c4c07\",\n\"e c #8e8e8e\",\n\"j c #ca6d0a\",\n\"# c #cacbcb\",\n\"g c #ed800c\",\n\"d c #ffc0c0\",\n\"f c #ffff00\",\n\".............#..\",\n\"...aab..........\",\n\".baacca.........\",\n\"aaddccca........\",\n\"dddddccca.......\",\n\"dddddddaaaaaaaaa\",\n\"aadddaaeeecaafga\",\n\"gabaaeeeebafffga\",\n\"cchhhaaaaaafbggi\",\n\"haaijjjjhggfgggi\",\n\"..aiijjjaggggggi\",\n\"..aiiijjaggggii.\",\n\"..aaiijjaggii...\",\n\"..baaiijaii.....\",\n\"..bbaaaaa.......\",\n\"................\"};\n"
  },
  {
    "path": "src/BITMAPS/tools.xpm",
    "content": "/* XPM */\nstatic char *tools[]={\n\"16 16 7 1\",\n\". c None\",\n\"# c #000000\",\n\"e c #00c0c0\",\n\"c c #808080\",\n\"a c #a0a0a0\",\n\"b c #c0ffff\",\n\"d c #c3c3c3\",\n\"................\",\n\"..........####..\",\n\".........#abc...\",\n\".........#b#..#.\",\n\".........#bd#c#.\",\n\"........#bdeee#.\",\n\".......#bde###..\",\n\"......#bde#.....\",\n\".....#bde#......\",\n\"....#bde#.......\",\n\"...#bde#........\",\n\"..#bde#.........\",\n\".#bde#..........\",\n\"#bee#...........\",\n\"#ee#............\",\n\".##.............\"};\n"
  },
  {
    "path": "src/BITMAPS/watch_1.xbm",
    "content": "#define watch_1_width 16\n#define watch_1_height 16\nstatic unsigned char watch_1_bits[] = {\n   0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xf9, 0xcf, 0xfc, 0x9f,\n   0xfc, 0x9f, 0x04, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x79, 0xcf, 0x79, 0xcf,\n   0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff};\n"
  },
  {
    "path": "src/BITMAPS/watch_2.xbm",
    "content": "#define watch_2_width 16\n#define watch_2_height 16\nstatic unsigned char watch_2_bits[] = {\n   0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xe9, 0xcf, 0xdc, 0x9f,\n   0xbc, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x79, 0xcf, 0x79, 0xcf,\n   0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff};\n"
  },
  {
    "path": "src/BITMAPS/watch_3.xbm",
    "content": "#define watch_3_width 16\n#define watch_3_height 16\nstatic unsigned char watch_3_bits[] = {\n   0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0x79, 0xcf, 0x79, 0xcf, 0x7c, 0x9f,\n   0x7c, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x79, 0xcf, 0x79, 0xcf,\n   0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff};\n"
  },
  {
    "path": "src/BITMAPS/watch_4.xbm",
    "content": "#define watch_4_width 16\n#define watch_4_height 16\nstatic unsigned char watch_4_bits[] = {\n   0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xf9, 0xcb, 0xfc, 0x9d,\n   0xfc, 0x9e, 0x7c, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x79, 0xcf, 0x79, 0xcf,\n   0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff};\n"
  },
  {
    "path": "src/BITMAPS/watch_5.xbm",
    "content": "#define watch_5_width 16\n#define watch_5_height 16\nstatic unsigned char watch_5_bits[] = {\n   0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xf9, 0xcf, 0xfc, 0x9f,\n   0xfc, 0x9f, 0x7c, 0x90, 0x7c, 0x9f, 0x7c, 0x9f, 0x79, 0xcf, 0x79, 0xcf,\n   0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff};\n"
  },
  {
    "path": "src/BITMAPS/watch_6.xbm",
    "content": "#define watch_6_width 16\n#define watch_6_height 16\nstatic unsigned char watch_6_bits[] = {\n   0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xf9, 0xcf, 0xfc, 0x9f,\n   0xfc, 0x9f, 0x7c, 0x9f, 0x7c, 0x9e, 0x7c, 0x9d, 0x79, 0xcb, 0x79, 0xcf,\n   0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff};\n"
  },
  {
    "path": "src/BITMAPS/watch_7.xbm",
    "content": "#define watch_7_width 16\n#define watch_7_height 16\nstatic unsigned char watch_7_bits[] = {\n   0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xf9, 0xcf, 0xfc, 0x9f,\n   0xfc, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x7c, 0x9f, 0x79, 0xcf, 0x79, 0xcf,\n   0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff};\n"
  },
  {
    "path": "src/BITMAPS/watch_8.xbm",
    "content": "#define watch_8_width 16\n#define watch_8_height 16\nstatic unsigned char watch_8_bits[] = {\n   0x1f, 0x9c, 0x07, 0x10, 0xe3, 0x23, 0xf9, 0xcf, 0xf9, 0xcf, 0xfc, 0x9f,\n   0xfc, 0x9f, 0x7c, 0x9f, 0x3c, 0x9f, 0x5c, 0x9f, 0x69, 0xcf, 0x79, 0xcf,\n   0xe3, 0xe3, 0x07, 0xf0, 0x1f, 0xfc, 0xff, 0xff};\n"
  },
  {
    "path": "src/BITMAPS/watch_msk.xbm",
    "content": "#define watch_msk_width 16\n#define watch_msk_height 16\n#define watch_msk_x_hot 7\n#define watch_msk_y_hot 7\nstatic unsigned char watch_msk_bits[] = {\n   0xe0, 0x63, 0xf8, 0xef, 0xfc, 0xdf, 0xfe, 0xbf, 0xfe, 0x7f, 0xff, 0x7f,\n   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0x7f,\n   0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x1f, 0xc0, 0x07};\n"
  },
  {
    "path": "src/Makefile.am",
    "content": "SUBDIRS = BITMAPS\n\n# need this to keep autoconf quiet, but we don't actually use it ... see the\n# bison rule below\nYACC = bison\n\n# windows resource files ... see .rc.o rule later\nSUFFIXES = .rc\n\n# only build the cli wrapper on win32\nif OS_WIN32 \nbin_PROGRAMS = nip2 nip2-cli\nnip2_cli_SOURCES = nip2-cli.c\nnip2_CFLAGS=\"-mwindows\"\nCLI_DIST = \nelse\nbin_PROGRAMS = nip2 \nCLI_DIST = nip2-cli.c\nendif\n\nnip2_SOURCES = \\\n\tvipsobject.c \\\n\tvipsobject.h \\\n\tplotmodel.c \\\n\tplotmodel.h \\\n\tprogress.c \\\n\tprogress.h \\\n\tpanechild.c \\\n\tpanechild.h \\\n\tplotpresent.c \\\n\tplotpresent.h \\\n\tplotstatus.c \\\n\tplotstatus.h \\\n\tfloatwindow.c \\\n\tfloatwindow.h \\\n\tvobject.c \\\n\tvobject.h \\\n\taction.c \\\n\taction.h \\\n\tboxes.c \\\n\tboxes.h \\\n\tpopupbutton.c \\\n\tpopupbutton.h \\\n\timageheader.c \\\n\timageheader.h \\\n\tpreview.c \\\n\tpreview.h \\\n\tbuiltin.c \\\n\tbuiltin.h \\\n\ticontainer.c \\\n\ticontainer.h \\\n\tiobject.c \\\n\tiobject.h \\\n\tclass.c \\\n\tclass.h \\\n\tclassmodel.c \\\n\tclassmodel.h \\\n\tcolour.c \\\n\tcolour.h \\\n\tcolourdisplay.c \\\n\tcolourdisplay.h \\\n\tcolourview.c \\\n\tcolourview.h \\\n\tcolumn.c \\\n\tcolumn.h \\\n\tcolumnview.c \\\n\tcolumnview.h \\\n\tcompile.c \\\n\tcompile.h \\\n\tconversion.c \\\n\tconversion.h \\\n\tconversionview.c \\\n\tconversionview.h \\\n\tdoubleclick.c \\\n\tdoubleclick.h \\\n\tdump.c \\\n\tdump.h \\\n\texpr.c \\\n\texpr.h \\\n\tfilemodel.c \\\n\tfilemodel.h \\\n\tpane.c \\\n\tpane.h \\\n\tpathname.c \\\n\tpathname.h \\\n\tfontname.c \\\n\tfontname.h \\\n\tgroup.c \\\n\tgroup.h \\\n\tpathnameview.c \\\n\tpathnameview.h \\\n\tfontnameview.c \\\n\tfontnameview.h \\\n\tfilesel.c \\\n\tfilesel.h \\\n\tgraphwindow.c \\\n\tgraphwindow.h \\\n\tgraphicview.c \\\n\tgraphicview.h \\\n\tgtkutil.c \\\n\tgtkutil.h \\\n\theap.c \\\n\theap.h \\\n\theapmodel.c \\\n\theapmodel.h \\\n\thelpindex.h \\\n\tnipmarshal.h \\\n\tnipmarshal.c \\\n\tiarrow.c \\\n\tiarrow.h \\\n\tvalue.c \\\n\tvalue.h \\\n\tvalueview.c \\\n\tvalueview.h \\\n\tidialog.c \\\n\tidialog.h \\\n\tiimage.c \\\n\tiimage.h \\\n\tiimageview.c \\\n\tiimageview.h \\\n\timagedisplay.c \\\n\timagedisplay.h \\\n\tlog.c \\\n\tlog.h \\\n\terror.c \\\n\terror.h \\\n\tmanaged.c \\\n\tmanaged.h \\\n\tmanagedfile.c \\\n\tmanagedfile.h \\\n\tmanagedgvalue.c \\\n\tmanagedgvalue.h \\\n\tmanagedgobject.c \\\n\tmanagedgobject.h \\\n\tmanagedstring.c \\\n\tmanagedstring.h \\\n\timageinfo.c \\\n\timageinfo.h \\\n\timagemodel.c \\\n\timagemodel.h \\\n\timagepresent.c \\\n\timagepresent.h \\\n\timageview.c \\\n\timageview.h \\\n\tip.h \\\n\tiregion.c \\\n\tiregion.h \\\n\tiregiongroup.c \\\n\tiregiongroup.h \\\n\tiregiongroupview.c \\\n\tiregiongroupview.h \\\n\tiregionview.c \\\n\tiregionview.h \\\n\titext.c \\\n\titext.h \\\n\titextview.c \\\n\titextview.h \\\n\tiwindow.c \\\n\tiwindow.h \\\n\tparse.y \\\n\tparser.h \\\n\tprefs.c \\\n\tprefs.h \\\n\tprefworkspaceview.c \\\n\tprefworkspaceview.h \\\n\tprefcolumnview.c \\\n\tprefcolumnview.h \\\n\tlex.l \\\n\tlink.c \\\n\tlink.h \\\n\tmain.c \\\n\tmain.h \\\n\tmainw.c \\\n\tmainw.h \\\n\tmatrix.c \\\n\tmatrix.h \\\n\tmatrixview.c \\\n\tmatrixview.h \\\n\tplot.c \\\n\tplot.h \\\n\tplotview.c \\\n\tplotview.h \\\n\tplotwindow.c \\\n\tplotwindow.h \\\n\tmodel.c \\\n\tmodel.h \\\n\toption.c \\\n\toption.h \\\n\toptionview.c \\\n\toptionview.h \\\n\tformula.c \\\n\tformula.h \\\n\tpaintboxview.c \\\n\tpaintboxview.h \\\n\tpath.c \\\n\tpath.h \\\n\tpredicate.c \\\n\tpredicate.h \\\n\tprogram.c \\\n\tprogram.h \\\n\tstring.c \\\n\tistring.h \\\n\tnumber.c \\\n\tnumber.h \\\n\texpression.c \\\n\texpression.h \\\n\texpressionview.c \\\n\texpressionview.h \\\n\tstringview.c \\\n\tstringview.h \\\n\teditview.c \\\n\teditview.h \\\n\tnumberview.c \\\n\tnumberview.h \\\n\treal.c \\\n\treal.h \\\n\tvector.c \\\n\tvector.h \\\n\treduce.c \\\n\treduce.h \\\n\tregionview.c \\\n\tregionview.h \\\n\trhs.c \\\n\trhs.h \\\n\trhsview.c \\\n\trhsview.h \\\n\trow.c \\\n\trow.h \\\n\trowview.c \\\n\trowview.h \\\n\tsecret.c \\\n\tsecret.h \\\n\tslider.c \\\n\tslider.h \\\n\tsliderview.c \\\n\tsliderview.h \\\n\tclock.c \\\n\tclock.h \\\n\tspin.c \\\n\tspin.h \\\n\tstatusview.c \\\n\tstatusview.h \\\n\tsubcolumn.c \\\n\tsubcolumn.h \\\n\tsubcolumnview.c \\\n\tsubcolumnview.h \\\n\tsymbol.c \\\n\tsymbol.h \\\n\ttoggle.c \\\n\ttoggle.h \\\n\ttoggleview.c \\\n\ttoggleview.h \\\n\ttool.c \\\n\ttool.h \\\n\ttoolkit.c \\\n\ttoolkit.h \\\n\ttoolkitgroup.c \\\n\ttoolkitgroup.h \\\n\ttoolkitgroupview.c \\\n\ttoolkitgroupview.h \\\n\ttoolkitview.c \\\n\ttoolkitview.h \\\n\tdefbrowser.c \\\n\tdefbrowser.h \\\n\ttoolkitbrowser.c \\\n\ttoolkitbrowser.h \\\n\ttoolview.c \\\n\ttoolview.h \\\n\ttrace.c \\\n\ttrace.h \\\n\ttree.c \\\n\ttree.h \\\n\ttslider.c \\\n\ttslider.h \\\n\tutil.c \\\n\tutil.h \\\n\tview.c \\\n\tview.h \\\n\tcall.c \\\n\tcall.h \\\n\tcache.c \\\n\tcache.h \\\n\twatch.c \\\n\twatch.h \\\n\tworkspace.c \\\n\tworkspace.h \\\n\tworkspacegroup.c \\\n\tworkspacegroup.h \\\n\tworkspacegroupview.c \\\n\tworkspacegroupview.h \\\n\tworkspacedefs.c \\\n\tworkspacedefs.h \\\n\tworkspaceroot.c \\\n\tworkspaceroot.h \\\n\tworkspaceview.c \\\n\tworkspaceview.h \n\nif OS_WIN32\nnip2_SOURCES += \\\n\tnip2-icon.rc\nendif\n\nhelpindex.h: \n\t./makehelpindex.pl $(prefix) > helpindex.h\nnipmarshal.h:\n\tglib-genmarshal --prefix=nip --header nipmarshal.list > nipmarshal.h\nnipmarshal.c:\n\techo \"#include \\\"nipmarshal.h\\\"\" > nipmarshal.c \n\tglib-genmarshal --prefix=nip --body nipmarshal.list >> nipmarshal.c\n\n.rc.o:\n\tcp ${top_srcdir}/share/nip2/data/nip2-icon.ico .\n\t${WINDRES} $< -o $@ \n\n# we have to replace the standard .y.c rule: we are a bison-only GLR parser,\n# so we can't use autoconf's preferred -y yacc-compatibility stuff\n.y.c:\n\t$(BISON) --defines=$*.h -o $*.c $<\n\nnip2-model.o model.o: model.c parse.c\n\nAM_CPPFLAGS = @IP_CFLAGS@ \nLDADD = @IP_CFLAGS@ @IP_LIBS@ \nAM_LDFLAGS = @LDFLAGS@\n\ndist-hook:\n\t${RM} ${distdir}/parse.c ${distdir}/lex.c\n\nCLEANFILES = parse.c parse.h lex.c tags\n\nEXTRA_DIST = makehelpindex.pl helpindex.h \\\n\tnipmarshal.h nipmarshal.c nipmarshal.list \\\n\t$(CLI_DIST)\n"
  },
  {
    "path": "src/action.c",
    "content": "/* actions on the graph\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* Index with binop or uop.\n */\nconst char *operator_table[] = {\n\t\"none\",\t\t\t/* BI_NONE */\n\t\"add\",\t\t\t/* BI_ADD */\n\t\"subtract\",\t\t/* BI_SUB */\n\t\"remainder\",\t\t/* BI_REM */\n\t\"power\",\t\t/* BI_POW */\n\t\"subscript\",\t\t/* BI_SELECT */\n\t\"left_shift\",\t\t/* BI_LSHIFT */\n\t\"right_shift\",\t\t/* BI_RSHIFT */\n\t\"divide\",\t\t/* BI_DIV */\n\t\"join\",\t\t\t/* BI_JOIN */\n\t\"dot\",\t\t\t/* BI_DOT */\n\t\"comma\",\t\t/* BI_COMMA */\n\t\"multiply\",\t\t/* BI_MUL */\n\t\"logical_and\",\t\t/* BI_LAND */\n\t\"logical_or\",\t\t/* BI_LOR */\n\t\"bitwise_and\",\t\t/* BI_BAND */\n\t\"bitwise_or\",\t\t/* BI_BOR */\n\t\"eor\",\t\t\t/* BI_EOR */\n\t\"equal\",\t\t/* BI_EQ */\n\t\"not_equal\",\t\t/* BI_NOTEQ */\n\t\"pointer_equal\",\t/* BI_PEQ */\n\t\"pointer_not_equal\",\t/* BI_PNOTEQ */\n\t\"less\",\t\t\t/* BI_LESS */\n\t\"less_equal\",\t\t/* BI_LESSEQ */\n\t\"none\",\t\t\t/* BI_MORE */\t\t\n\t\"none\",\t\t\t/* BI_MOREEQ */\n\t\"if_then_else\",\t\t/* BI_IF */\n\t\"cons\",\t\t\t/* BI_CONS */\n\t\"none\",\t\t\t/* UN_NONE */\n\t\"cast_signed_char\",\t/* UN_CSCHAR */\n\t\"cast_unsigned_char\",\t/* UN_CUCHAR */\n\t\"cast_signed_short\",\t/* UN_CSSHORT */\n\t\"cast_unsigned_short\",\t/* UN_CUSHORT */\n\t\"cast_signed_int\",\t/* UN_CSINT */\n\t\"cast_unsigned_int\",\t/* UN_CUINT */\n\t\"cast_float\",\t\t/* UN_CFLOAT */\n\t\"cast_double\",\t\t/* UN_CDOUBLE */\n\t\"cast_complex\",\t\t/* UN_CCOMPLEX */\n\t\"cast_double_complex\",\t/* UN_CDCOMPLEX */\n\t\"unary_minus\",\t\t/* UN_MINUS */\n\t\"negate\",\t\t/* UN_NEG */\n\t\"complement\",\t\t/* UN_COMPLEMENT */\n\t\"unary_plus\"\t\t/* UN_PLUS */\n};\nconst int noperator_table = IM_NUMBER( operator_table );\n\n/* Bad bop error.\n */\nstatic void\naction_boperror( Reduce *rc, Compile *compile, const char *str, \n\tint op, const char *name, PElement *a, PElement *b )\n{\n\tconst char *top_str = str ? str : _( \"Bad arguments.\" );\n\tconst char *op_name = op >= 0 ? decode_BinOp( op ) : name;\n\n\tchar txt[MAX_ERROR_FRAG];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tchar txt2[MAX_ERROR_FRAG];\n\tVipsBuf buf2 = VIPS_BUF_STATIC( txt2 );\n\tchar txt3[MAX_ERROR_FRAG];\n\tVipsBuf buf3 = VIPS_BUF_STATIC( txt3 );\n\n\titext_value_ev( rc, &buf, a );\n\titext_value_ev( rc, &buf2, b );\n\tif( compile ) {\n\t\t/* Expands to eg. 'bad args to \"+\", called from \"fred\"'\n\t\t */\n\t\tvips_buf_appends( &buf3, _( \"Called from\" ) );\n\t\tvips_buf_appends( &buf3, \" \" );\n\t\tcompile_name( compile, &buf3 );\n\t}\n\n\terror_top( \"%s\", top_str );\n\terror_sub( _( \"Error in binary %s.\\n\"\n\t\t\"left = %s\\n\"\n\t\t\"right = %s\\n%s\" ),\n\t\top_name, \n\t\tvips_buf_all( &buf ), \n\t\tvips_buf_all( &buf2 ), \n\t\tvips_buf_all( &buf3 ) );\n\n\treduce_throw( rc );\n}\n\n/* Member not found in class instance error.\n */\nstatic void\naction_nomerror( Reduce *rc, Compile *compile, PElement *a, PElement *b )\n{\n\tchar txt[500];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tchar txt2[MAX_ERROR_FRAG];\n\tVipsBuf buf2 = VIPS_BUF_STATIC( txt2 );\n\tchar txt3[MAX_ERROR_FRAG];\n\tVipsBuf buf3 = VIPS_BUF_STATIC( txt3 );\n\n\tif( PEISCLASS( a ) ) \n\t\tsymbol_qualified_name( PEGETCLASSCOMPILE( a )->sym, &buf3 );\n\telse if( PEISSYMREF( a ) ) \n\t\tsymbol_qualified_name( PEGETSYMREF( a ), &buf3 );\n\telse if( PEISSYMBOL( a ) ) \n\t\tsymbol_qualified_name( PEGETSYMBOL( a ), &buf3 );\n\telse if( PEISCOMPILEREF( a ) ) \n\t\tsymbol_qualified_name( PEGETCOMPILE( a )->sym, &buf3 );\n\telse\n\t\tvips_buf_appends( &buf3, \"<thing>\" );\n\titext_value_ev( rc, &buf2, b );\n\tvips_buf_appendf( &buf, _( \"Member \\\"%s\\\" not found in class \\\"%s\\\".\" ),\n\t\tvips_buf_all( &buf2 ), vips_buf_all( &buf3 ) );\n\tvips_buf_appendf( &buf, \"\\n\" );\n\n\tvips_buf_rewind( &buf3 );\n\titext_value_ev( rc, &buf3, a );\n\tvips_buf_appendf( &buf, \"  \" );\n\tvips_buf_appendf( &buf, _( \"object = %s\" ), vips_buf_all( &buf3 ) );\n\tvips_buf_appendf( &buf, \"\\n\" );\n\n\tvips_buf_appendf( &buf, \"  \" );\n\tvips_buf_appendf( &buf, _( \"tag = %s\" ), vips_buf_all( &buf2 ) );\n\tvips_buf_appendf( &buf, \"\\n\" );\n\n\tvips_buf_rewind( &buf3 );\n\tsymbol_qualified_name( compile->sym, &buf3 );\n\tvips_buf_appendf( &buf, _( \"Reference attempted in \\\"%s\\\".\" ),\n\t\tvips_buf_all( &buf3 ) );\n\tvips_buf_appendf( &buf, \"\\n\" );\n\n\terror_top( _( \"Member not found.\" ) );\n\terror_sub( \"%s\", vips_buf_all( &buf ) );\n\treduce_throw( rc );\n}\n\n/* Bad uop error.\n */\nstatic void\naction_uoperror( Reduce *rc, Compile *compile, \n\tconst char *str, int op, const char *name, PElement *a )\n{\n\tconst char *top_str = str ? str : _( \"Bad argument.\" );\n\tconst char *op_name = op >= 0 ? decode_UnOp( op ) : name;\n\n\tchar txt[MAX_ERROR_FRAG];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tchar txt2[MAX_ERROR_FRAG];\n\tVipsBuf buf2 = VIPS_BUF_STATIC( txt2 );\n\n\titext_value_ev( rc, &buf, a );\n\n\tif( compile ) {\n\t\t/* Expands to eg. 'bad args to \"+\", called from \"fred\"'\n\t\t */\n\t\tvips_buf_appends( &buf2, _( \"Called from\" ) );\n\t\tvips_buf_appends( &buf2, \" \" );\n\t\tcompile_name( compile, &buf2 );\n\t}\n\n\terror_top( \"%s\", top_str );\n\terror_sub( _( \"Error in unary %s.\\n\"\n\t\t\"argument = %s\\n%s\" ),\n\t\top_name, vips_buf_all( &buf ), vips_buf_all( &buf2 ) );\n\n\treduce_throw( rc );\n}\n\n/* Clip real part of number a to a range.\n */\nstatic void\naction_set_range( Reduce *rc, double mn, double mx, PElement *a, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\tdouble d;\n\n\t/* Get real part.\n\t */\n\tif( PEISREAL( a ) )\n\t\td = PEGETREAL( a );\n\telse\n\t\td = PEGETREALPART( a );\n\n\tif( d < mn )\n\t\td = mn;\n\telse if( d > mx )\n\t\td = mx;\n\telse\n\t\td = (int) d;\n\n\tif( !heap_real_new( heap, d, out ) )\n\t\treduce_throw( rc );\n}\n\n/* EOR two things.\n */\nstatic void\naction_proc_eor( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\n\tif( PEISBOOL( a ) && PEISBOOL( b ) ) {\n\t\tPEPUTP( out, ELEMENT_BOOL, \n\t\t\tPEGETBOOL( a ) ^ PEGETBOOL( b ) );\n\t}\n\telse if( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\tint v1 = PEGETREAL( a );\n\t\tint v2 = PEGETREAL( b );\n\n\t\tif( !heap_real_new( heap, v1 ^ v2, out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISIMAGE( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \n\t\t\t\"im_eorimage\", PEGETII( a ), PEGETII( b ) ); \n\telse if( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\tcallva( rc, out, \"im_eorimageconst\", \n\t\t\tPEGETII( a ), (int) PEGETREAL( b ) ); \n\telse if( PEISREAL( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_eorimageconst\", \n\t\t\tPEGETII( b ), (int) PEGETREAL( a ) ); \n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\n/* OR two things.\n */\nstatic void\naction_proc_bor( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\n\tif( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\tint v1 = PEGETREAL( a );\n\t\tint v2 = PEGETREAL( b );\n\n\t\tif( !heap_real_new( heap, v1 | v2, out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISIMAGE( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_orimage\", \n\t\t\tPEGETII( a ), PEGETII( b ) ); \n\telse if( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\tcallva( rc, out, \"im_orimageconst\", \n\t\t\tPEGETII( a ), (int) PEGETREAL( b ) ); \n\telse if( PEISREAL( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_orimageconst\", \n\t\t\tPEGETII( b ), (int) PEGETREAL( a ) ); \n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\n/* AND two things.\n */\nstatic void\naction_proc_band( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\n\tif( PEISIMAGE( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \n\t\t\t\"im_andimage\", PEGETII( a ), PEGETII( b ) ); \n\telse if( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\tint v1 = PEGETREAL( a );\n\t\tint v2 = PEGETREAL( b );\n\n\t\tif( !heap_real_new( heap, v1 & v2, out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\tcallva( rc, out, \"im_andimageconst\", \n\t\t\tPEGETII( a ), (int) PEGETREAL( b ) ); \n\telse if( PEISREAL( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_andimageconst\", \n\t\t\tPEGETII( b ), (int) PEGETREAL( a ) ); \n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\nstatic void *\naction_proc_dot_add_link( Expr *expr, Symbol *child )\n{\n\treturn( link_add( child, expr, TRUE ) );\n}\n\nstatic char *\naction_proc_dot_tag( Reduce *rc, PElement *b, char *tag, int n )\n{\n\tif( PEISTAG( b ) ) \n\t\treturn( PEGETTAG( b ) );\n\telse if( reduce_is_string( rc, b ) ) { \n\t\t(void) reduce_get_string( rc, b, tag, n );\n\t\treturn( tag );\n\t}\n\n\treturn( NULL );\n}\n\n/* Extract field from object. Be careful, a can be equal to out. \n */\nstatic void\naction_proc_dot( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tchar tag[256];\n\tchar *p;\n\n\tif( PEISCLASS( a ) ) {\n\t\tPElement c;\n\n\t\tif( (p = action_proc_dot_tag( rc, b, tag, 256 )) ) {\n\t\t\tif( !class_get_member( a, p, NULL, &c ) )\n\t\t\t\taction_nomerror( rc, compile, a, b );\n\n\t\t\tPEPUTPE( out, &c );\n\t\t}\n\t\telse if( PEISSYMREF( b ) ) {\n\t\t\tif( !class_get_symbol( a, PEGETSYMREF( b ), &c ) )\n\t\t\t\taction_nomerror( rc, compile, a, b );\n\n\t\t\tPEPUTPE( out, &c );\n\t\t}\n\t\telse\n\t\t\taction_boperror( rc, compile, \n\t\t\t\t_( \"Bad right hand side of '.'.\" ),\n\t\t\t\top, name, a, b );\n\t}\n\n\telse if( PEISSYMREF( a ) ) {\n\t\tSymbol *sym = PEGETSYMREF( a );\n\t\tSymbol *child;\n\n\t\tif( !is_scope( sym ) )\n\t\t\taction_boperror( rc, compile,\n\t\t\t\t_( \"Symbol on left hand side of '.' \"\n\t\t\t\t\"is not scope\" ), \n\t\t\t\top, name, a, b );\n\n\t\tg_assert( sym->expr );\n\n\t\tif( !(p = action_proc_dot_tag( rc, b, tag, 256 )) ) \n\t\t\taction_boperror( rc, compile, \n\t\t\t\t_( \"Bad right hand side of '.'.\" ),\n\t\t\t\top, name, a, b );\n\t\tif( !(child = compile_lookup( sym->expr->compile, p )) )\n\t\t\taction_nomerror( rc, compile, a, b );\n\n\t\t/* Add all exprs which use compile to dynamic link graph.\n\t\t */\n\t\tif( slist_map( compile->exprs,\n\t\t\t(SListMapFn) action_proc_dot_add_link, child ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\n\t\t/* Don't check for dirty here ... wait for\n\t\t * link.\n\t\t */\n\t\tif( child->type == SYM_VALUE ) {\n\t\t\tPEPUTP( out, ELEMENT_SYMBOL, child );\n\t\t}\n\t\telse {\n\t\t\tPEPUTP( out, ELEMENT_SYMREF, child );\n\t\t}\n\t}\n\telse if( PEISMANAGEDGOBJECT( a ) ) {\n\t\tGObject *gobject = PEGETMANAGEDGOBJECT( a );\n\t\tGObjectClass *gclass = G_OBJECT_GET_CLASS( gobject );\n\t\tGValue value = { 0 };\n\t\tGParamSpec *pspec;\n\n\t\tif( !(p = action_proc_dot_tag( rc, b, tag, 256 )) )\n\t\t\taction_boperror( rc, compile, \n\t\t\t\t_( \"Bad right hand side of '.'.\" ),\n\t\t\t\top, name, a, b );\n\t\tif( !(pspec = g_object_class_find_property( gclass, p )) )\n\t\t\taction_boperror( rc, compile, \n\t\t\t\t_( \"Property not found.\" ),\n\t\t\t\top, name, a, b );\n\n\t\tg_value_init( &value, G_PARAM_SPEC_VALUE_TYPE( pspec ) );\n\t\tg_object_get_property( gobject, p, &value);\n\n\t\tif( !heap_gvalue_to_ip( &value, out ) ) {\n\t\t\tg_value_unset( &value );\n\t\t\treduce_throw( rc );\n\t\t}\n\n\t\tg_value_unset( &value );\n\t}\n\telse\n\t\taction_boperror( rc, compile, _( \"Bad left hand side of '.'.\" ),\n\t\t\top, name, a, b );\n}\n\n/* Less than or equal to.\n */\nstatic void\naction_proc_lesseq( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tif( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\tPEPUTP( out, ELEMENT_BOOL, PEGETREAL( a ) <= PEGETREAL( b ) );\n\t}\n\telse if( PEISCHAR( a ) && PEISCHAR( b ) ) {\n\t\tPEPUTP( out, ELEMENT_BOOL, PEGETCHAR( a ) <= PEGETCHAR( b ) );\n\t}\n\telse if( PEISLIST( a ) && PEISLIST( b ) &&\n\t\treduce_is_string( rc, a ) && reduce_is_string( rc, b ) ) {\n\t\tchar a_string[MAX_STRSIZE];\n\t\tchar b_string[MAX_STRSIZE];\n\n\t\treduce_get_string( rc, a, a_string, MAX_STRSIZE );\n\t\treduce_get_string( rc, b, b_string, MAX_STRSIZE );\n\n\t\tPEPUTP( out, ELEMENT_BOOL, strcmp( a_string, b_string ) <= 0 );\n\t}\n\telse if( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\tcallva( rc, out, \"im_lesseqconst\",\n\t\t\tPEGETII( a ), PEGETREAL( b ) ); \n\telse if( PEISREAL( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_moreeqconst\",\n\t\t\tPEGETII( b ), PEGETREAL( a ) ); \n\telse if( PEISIMAGE( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_lesseq\", PEGETII( a ), PEGETII( b ) ); \n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\n/* Strict less than.\n */\nstatic void\naction_proc_less( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tif( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\tPEPUTP( out, ELEMENT_BOOL, PEGETREAL( a ) < PEGETREAL( b ) );\n\t}\n\telse if( PEISCHAR( a ) && PEISCHAR( b ) ) {\n\t\tPEPUTP( out, ELEMENT_BOOL, PEGETCHAR( a ) < PEGETCHAR( b ) );\n\t}\n\telse if( PEISLIST( a ) && PEISLIST( b ) &&\n\t\treduce_is_string( rc, a ) && reduce_is_string( rc, b ) ) {\n\t\tchar a_string[MAX_STRSIZE];\n\t\tchar b_string[MAX_STRSIZE];\n\n\t\treduce_get_string( rc, a, a_string, MAX_STRSIZE );\n\t\treduce_get_string( rc, b, b_string, MAX_STRSIZE );\n\n\t\tPEPUTP( out, ELEMENT_BOOL, strcmp( a_string, b_string ) < 0 );\n\t}\n\telse if( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\tcallva( rc, out, \"im_lessconst\",\n\t\t\tPEGETII( a ), PEGETREAL( b ) ); \n\telse if( PEISREAL( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_moreconst\",\n\t\t\tPEGETII( b ), PEGETREAL( a ) ); \n\telse if( PEISIMAGE( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_less\", PEGETII( a ), PEGETII( b ) ); \n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\n/* Forward ref.\n */\nstatic gboolean action_element_equal( Reduce *rc, PElement *a, PElement *b );\n\n/* Test two nodes for equality.\n */\nstatic gboolean\naction_node_equal( Reduce *rc, HeapNode *a, HeapNode *b )\n{\n\tPElement la, ra;\n\tPElement lb, rb;\n\n\t/* Easy!\n\t */\n\tif( a->type != b->type )\n\t\treturn( FALSE );\n\t\n\tswitch( a->type ) {\n\tcase TAG_APPL:\n\tcase TAG_CLASS:\n\t\t/* Function compare ... don't allow it.\n\t\t */\n\t\treturn( FALSE );\n\n\tcase TAG_CONS:\n\t\t/* Compare the elements.\n\t\t */\n\t\tPEPOINTLEFT( a, &la );\n\t\tPEPOINTLEFT( b, &lb );\n\t\tPEPOINTRIGHT( a, &ra );\n\t\tPEPOINTRIGHT( b, &rb );\n\t\treturn( action_element_equal( rc, &la, &lb ) &&\n\t\t\taction_element_equal( rc, &ra, &rb ) );\n\n\tcase TAG_DOUBLE:\n\t\treturn( a->body.num == b->body.num );\n\n\tcase TAG_COMPLEX:\n\t\treturn( GETLEFT( a )->body.num == GETLEFT( b )->body.num &&\n\t\t\tGETRIGHT( a )->body.num == GETRIGHT( b )->body.num );\n\n\tcase TAG_GEN:\n\tcase TAG_FILE:\n\tcase TAG_FREE:\n\tcase TAG_SHARED:\n\tcase TAG_REFERENCE:\n\tdefault:\n\t\tg_assert( FALSE );\n\n\t\t/* Keep gcc happy.\n\t\t */\n\t\treturn( FALSE );\n\t}\n}\n\nstatic gboolean\naction_image_equal( Reduce *rc, Imageinfo *a, Imageinfo *b )\n{\n\tImageinfo *ii[2];\n\tIMAGE *t1;\n\tIMAGE *ai, *bi;\n\tgboolean use_luts;\n\tdouble mn;\n\n\t/* Easy tests first.\n\t */\n\tii[0] = a;\n\tii[1] = b;\n\tg_assert( !ii[0] && !ii[1] );\n\tif( ii[0] == ii[1] )\n\t\t/* Trivial!\n\t\t */\n\t\treturn( TRUE );\n\n\t/* Extract images ... get LUTs if the underlying image is the\n\t * same.\n\t */\n\tuse_luts = imageinfo_same_underlying( ii, 2 );\n\tif( !(ai = imageinfo_get( use_luts, ii[0] )) || \n\t\t!(bi = imageinfo_get( use_luts, ii[1] )) ) {\n\t\treduce_throw( rc );\n\n\t\t/* Never get here, but keeps gcc happy.\n\t\t */\n\t\treturn( FALSE );\n\t}\n\n\t/* Size and bands must be the same.\n\t */\n\tif( ai->Xsize != bi->Xsize ||\n\t\tai->Ysize != bi->Ysize ||\n\t\tai->Bands != bi->Bands ||\n\t\tai->Coding != bi->Coding )\n\t\treturn( FALSE );\n\n\t/* Exhaustive test.\n\t */\n\tif( !(t1 = im_open( \"equals:1\", \"p\" )) ) {\n\t\terror_vips_all();\n\t\treduce_throw( rc );\n\t}\n\tif( im_equal( ai, bi, t1 ) ||\n\t\tim_min( t1, &mn ) ) {\n\t\tim_close( t1 );\n\t\terror_vips_all();\n\t\treduce_throw( rc );\n\t}\n\tim_close( t1 );\n\n\treturn( mn == 255 );\n}\n\n/* One of p1/p2 is a managedstring. \n *\n * This is pretty dumb. We could have a special loop down the list side which\n * compared to the managedstring directly, but I doubt if this will ever be a\n * performance issue.\n */\nstatic gboolean\naction_string_equal( Reduce *rc, PElement *p1, PElement *p2 )\n{\n\tchar a_string[MAX_STRSIZE];\n\tchar b_string[MAX_STRSIZE];\n\n\treduce_get_string( rc, p1, a_string, MAX_STRSIZE );\n\treduce_get_string( rc, p2, b_string, MAX_STRSIZE );\n\n\treturn( strcmp( a_string, b_string ) == 0 );\n}\n\n/* Test two elements for equality. Force computation as required.\n */\nstatic gboolean\naction_element_equal( Reduce *rc, PElement *p1, PElement *p2 )\n{\n\t/* Reduce a bit.\n\t */\n\treduce_spine( rc, p1 );\n\treduce_spine( rc, p2 );\n\n\t/* We can often test for eg. \"fred\" == \"fred\" by just checking\n\t * pointers.\n\t */\n\tif( PEGETTYPE( p1 ) == PEGETTYPE( p2 ) ) {\n\t\tswitch( PEGETTYPE( p1 ) ) {\n\t\tcase ELEMENT_CHAR:\n\t\tcase ELEMENT_NODE:\n\t\tcase ELEMENT_BOOL:\n\t\tcase ELEMENT_MANAGED:\n\t\t\tif( PEGETVAL( p1 ) == PEGETVAL( p2 ) )\n\t\t\t\treturn( TRUE );\n\t\t\tbreak;\n\n\t\tcase ELEMENT_ELIST:\n\t\t\treturn( TRUE );\n\t\t}\n\t}\n\n\t/* Special case if either is a managedstring.\n\t */\n\tif( PEISMANAGEDSTRING( p1 ) ||\n\t\tPEISMANAGEDSTRING( p2 ) ) \n\t\treturn( action_string_equal( rc, p1, p2 ) );\n\n\t/* No other implicit conversions, so types must match.\n\t */\n\tif( PEGETTYPE( p1 ) != PEGETTYPE( p2 ) )\n\t\treturn( FALSE );\n\n\tswitch( PEGETTYPE( p1 ) ) {\n\tcase ELEMENT_TAG:\n\tcase ELEMENT_BINOP:\n\tcase ELEMENT_UNOP:\n\tcase ELEMENT_SYMBOL:\n\tcase ELEMENT_SYMREF:\n\tcase ELEMENT_COMPILEREF:\n\tcase ELEMENT_CONSTRUCTOR:\n\tcase ELEMENT_COMB:\n\t\t/* Don't allow function compare.\n\t\t */\n\t\treturn( FALSE );\n\n\tcase ELEMENT_NODE:\n\t\t/* Compare the HeapNodes.\n\t\t */\n\t\treturn( action_node_equal( rc, \n\t\t\tPEGETVAL( p1 ), PEGETVAL( p2 ) ) );\n\n\tcase ELEMENT_CHAR:\n\t\treturn( PEGETCHAR( p1 ) == PEGETCHAR( p2 ) );\n\n\tcase ELEMENT_BOOL:\n\t\treturn( PEGETBOOL( p1 ) == PEGETBOOL( p2 ) );\n\n\tcase ELEMENT_MANAGED:\n\t\tif( PEISIMAGE( p1 ) && PEISIMAGE( p2 ) )\n\t\t\treturn( action_image_equal( rc,\n\t\t\t\tPEGETII( p1 ), PEGETII( p2 ) ) );\n\t\telse\n\t\t\treturn( FALSE );\n\n\tcase ELEMENT_ELIST:\n\t\treturn( TRUE );\n\n\tcase ELEMENT_NOVAL:\n\tdefault:\n\t\tg_assert( FALSE );\n\n\t\t/* Keep gcc happy.\n\t\t */\n\t\treturn( FALSE );\n\t}\n}\n\n/* Top-level == ... special form for image args.\n */\nstatic void\naction_proc_equal( Reduce *rc, Compile *compile,\n\tint op, const char *name, HeapNode **arg, PElement *out )\n{\n\tgboolean res;\n\tPElement left, right;\n\tPElement *a = &left;\n\tPElement *b = &right;\n\n\tPEPOINTRIGHT( arg[1], &left );\n\tPEPOINTRIGHT( arg[0], &right );\n\n\tif( PEISIMAGE( a ) || PEISIMAGE( b ) ) {\n\t\t/* Special image equals form. Hyperstrict.\n\t\t */\n\t\treduce_spine_strict( rc, a );\n\t\treduce_spine_strict( rc, b );\n\n\t\tif( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\t\tcallva( rc, out, \"im_equalconst\", \n\t\t\t\tPEGETII( a ), PEGETREAL( b ) );\n\t\telse if( PEISREAL( a ) && PEISIMAGE( b ) ) \n\t\t\tcallva( rc, out, \"im_equalconst\", \n\t\t\t\tPEGETII( b ), PEGETREAL( a ) );\n\t\telse if( PEISIMAGE( a ) && PEISIMAGE( b ) ) \n\t\t\tcallva( rc, out, \"im_equal\", \n\t\t\t\tPEGETII( a ), PEGETII( b ) ); \n\t\telse\n\t\t\tPEPUTP( out, ELEMENT_BOOL, FALSE ); \n\t}\n\telse {\n\t\t/* Lazy form.\n\t\t */\n\t\tres = action_element_equal( rc, a, b );\n\t\tPEPUTP( out, ELEMENT_BOOL, res ); \n\t}\n}\n\n/* Top-level != ... special form for image args.\n */\nstatic void\naction_proc_notequal( Reduce *rc, Compile *compile,\n\tint op, const char *name, HeapNode **arg, PElement *out )\n{\n\tgboolean res;\n\tPElement left, right;\n\tPElement *a = &left;\n\tPElement *b = &right;\n\n\tPEPOINTRIGHT( arg[1], &left );\n\tPEPOINTRIGHT( arg[0], &right );\n\n\tif( PEISIMAGE( a ) || PEISIMAGE( b ) ) {\n\t\t/* Special image equals form. Hyperstrict.\n\t\t */\n\t\treduce_spine_strict( rc, a );\n\t\treduce_spine_strict( rc, b );\n\n\t\tif( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\t\tcallva( rc, out, \"im_notequalconst\", \n\t\t\t\tPEGETII( a ), PEGETREAL( b ) );\n\t\telse if( PEISREAL( a ) && PEISIMAGE( b ) ) \n\t\t\tcallva( rc, out, \"im_notequalconst\", \n\t\t\t\tPEGETII( b ), PEGETREAL( a ) );\n\t\telse if( PEISIMAGE( a ) && PEISIMAGE( b ) ) \n\t\t\tcallva( rc, out, \"im_notequal\", \n\t\t\t\tPEGETII( a ), PEGETII( b ) ); \n\t\telse\n\t\t\tPEPUTP( out, ELEMENT_BOOL, TRUE ); \n\t}\n\telse {\n\t\tres = action_element_equal( rc, a, b );\n\t\tPEPUTP( out, ELEMENT_BOOL, !res ); \n\t}\n}\n\nstatic void *\naction_proc_join_sub( Reduce *rc, PElement *pe, \n\tPElement *a, PElement *b, PElement *out )\n{\n\tif( !heap_list_cat( rc, a, b, pe ) ) \n\t\treturn( a );\n\n\tPEPUTPE( out, pe );\n\t\n\treturn( NULL );\n}\n\nstatic void\naction_proc_join( Reduce *rc, Compile *compile,\n\tint op, const char *name, HeapNode **arg, PElement *out )\n{\n\tPElement left, right;\n\tPElement *a = &left;\n\tPElement *b = &right;\n\n\tPEPOINTRIGHT( arg[1], &left );\n\tPEPOINTRIGHT( arg[0], &right );\n\n\tif( PEISIMAGE( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_bandjoin\", PEGETII( a ), PEGETII( b ) ); \n\telse if( PEISLIST( a ) && PEISLIST( b ) ) {\n\t\tif( reduce_safe_pointer( rc, \n\t\t\t(reduce_safe_pointer_fn) action_proc_join_sub,\n\t\t\ta, b, out, NULL ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISIMAGE( a ) && PEISELIST( b ) ) {\n\t\tPEPUTPE( out, a );\n\t}\n\telse if( PEISIMAGE( b ) && PEISELIST( a ) ) {\n\t\tPEPUTPE( out, b );\n\t}\n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\nstatic void\naction_proc_index( Reduce *rc, Compile *compile,\n\tint op, const char *name, HeapNode **arg, PElement *out )\n{\n\tPElement left, right;\n\tPElement *a = &left;\n\tPElement *b = &right;\n\n\tPEPOINTRIGHT( arg[1], &left );\n\tPEPOINTRIGHT( arg[0], &right );\n\n\tif( PEISLIST( a ) && PEISREAL( b ) ) {\n\t\tPElement result;\n\n\t\treduce_list_index( rc, a, PEGETREAL( b ), &result );\n\t\tPEPUTPE( out, &result );\n\t}\n\telse if( PEISIMAGE( a ) && PEISREAL( b ) ) {\n\t\tcallva( rc, out, \"im_extract_band\", \n\t\t\tPEGETII( a ), (int) PEGETREAL( b ) );\n\t}\n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\n/* Raise to power.\n */\nstatic void\naction_proc_exp( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\n\tif( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\tif( !heap_real_new( heap, \n\t\t\tpow( PEGETREAL( a ), PEGETREAL( b ) ), out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\tcallva( rc, out, \"im_powtra\", PEGETII( a ), PEGETREAL( b ) );\n\telse if( PEISREAL( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_expntra\", PEGETII( b ), PEGETREAL( a ) );\n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\n/* Left shift.\n */\nstatic void\naction_proc_lshift( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\n\tif( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\tint v1 = PEGETREAL( a );\n\t\tint v2 = PEGETREAL( b );\n\n\t\tif( !heap_real_new( heap, v1 << v2, out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\tcallva( rc, out, \"im_shiftleft\", \n\t\t\tPEGETII( a ), (int) PEGETREAL( b ) );\n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\n/* Right shift.\n */\nstatic void\naction_proc_rshift( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\n\tif( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\tint v1 = PEGETREAL( a );\n\t\tint v2 = PEGETREAL( b );\n\n\t\tif( !heap_real_new( heap, v1 >> v2, out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\tcallva( rc, out, \"im_shiftright\", \n\t\t\tPEGETII( a ), (int) PEGETREAL( b ) );\n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\n/* Remainder.\n */\nstatic void\naction_proc_rem( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\n\tif( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\tint v1 = PEGETREAL( a );\n\t\tint v2 = PEGETREAL( b );\n\t\t\n\t\tif( v2 == 0 )\n\t\t\taction_boperror( rc, compile, _( \"Division by zero.\" ), \n\t\t\t\top, name, a, b );\n\n\t\tif( !heap_real_new( heap, v1 % v2, out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISIMAGE( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_remainder\", \n\t\t\tPEGETII( a ), PEGETII( b ) );\n\telse if( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\tcallva( rc, out, \"im_remainderconst\", \n\t\t\tPEGETII( a ), PEGETREAL( b ) );\n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\n/* Divide two objects.\n */\nstatic void\naction_proc_div( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\n\tif( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\tif( !heap_real_new( heap, \n\t\t\tPEGETREAL( a ) / PEGETREAL( b ), out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISCOMPLEX( a ) && PEISCOMPLEX( b ) ) {\n\t\tdouble x1 = PEGETREALPART( a );\n\t\tdouble y1 = PEGETIMAGPART( a );\n\t\tdouble x2 = PEGETREALPART( b );\n\t\tdouble y2 = PEGETIMAGPART( b );\n\n\t\tif( !heap_complex_new( heap, \n\t\t\t(x1 * x2 + y1 * y2) / (x2 * x2 + y2 * y2),\n\t\t\t(y1 * x2 - x1 * y2) / (x2 * x2 + y2 * y2), out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISCOMPLEX( a ) && PEISREAL( b ) ) {\n\t\tdouble x1 = PEGETREALPART( a );\n\t\tdouble y1 = PEGETIMAGPART( a );\n\t\tdouble x2 = PEGETREAL( b );\n\n\t\tif( !heap_complex_new( heap, \n\t\t\t(x1 * x2) / (x2 * x2),\n\t\t\t(y1 * x2) / (x2 * x2), out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISREAL( a ) && PEISCOMPLEX( b ) ) {\n\t\tdouble x1 = PEGETREAL( a );\n\t\tdouble x2 = PEGETREALPART( b );\n\t\tdouble y2 = PEGETIMAGPART( b );\n\n\t\tif( !heap_complex_new( heap, \n\t\t\t(x1 * x2) / (x2 * x2 + y2 * y2),\n\t\t\t(-x1 * y2) / (x2 * x2 + y2 * y2), out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISIMAGE( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_divide\", \n\t\t\tPEGETII( a ), PEGETII( b ) );\n\telse if( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\tcallva( rc, out, \"im_lintra\", \n\t\t\t1.0 / PEGETREAL( b ), PEGETII( a ), 0.0 );\n\telse if( PEISREAL( a ) && PEISIMAGE( b ) ) {\n\t\tHeapNode hn;\n\t\tPElement rhs;\n\n\t\t/* Use this for intermediates.\n\t\t */\n\t\tPEPOINTRIGHT( &hn, &rhs );\n\n\t\t/* Take recip.\n\t\t */\n\t\tcallva( rc, &rhs, \"im_powtra\", PEGETII( b ), -1.0 );\n\n\t\t/* Now multiply by const.\n\t\t */\n\t\tcallva( rc, out, \"im_lintra\",\n\t\t\tPEGETREAL( a ), PEGETII( &rhs ), 0.0 );\n\t}\n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\n/* Multiply two objects.\n */\nstatic void\naction_proc_mul( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\n\tif( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\tif( !heap_real_new( heap, \n\t\t\tPEGETREAL( a ) * PEGETREAL( b ), out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISCOMPLEX( a ) && PEISCOMPLEX( b ) ) {\n\t\tdouble x1 = PEGETREALPART( a );\n\t\tdouble y1 = PEGETIMAGPART( a );\n\t\tdouble x2 = PEGETREALPART( b );\n\t\tdouble y2 = PEGETIMAGPART( b );\n\n\t\tif( !heap_complex_new( heap, \n\t\t\tx1*x2 - y1*y2, x1*y2 + x2*y1, out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISCOMPLEX( a ) && PEISREAL( b ) ) {\n\t\tif( !heap_complex_new( heap, \n\t\t\tPEGETREALPART( a ) * PEGETREAL( b ), \n\t\t\tPEGETIMAGPART( a ) * PEGETREAL( b ), out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISREAL( a ) && PEISCOMPLEX( b ) ) {\n\t\tif( !heap_complex_new( heap, \n\t\t\tPEGETREAL( a ) * PEGETREALPART( b ),\n\t\t\tPEGETREAL( a ) * PEGETIMAGPART( b ), out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISIMAGE( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_multiply\", \n\t\t\tPEGETII( a ), PEGETII( b ) );\n\telse if( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\tcallva( rc, out, \"im_lintra\", \n\t\t\tPEGETREAL( b ), PEGETII( a ), 0.0 );\n\telse if( PEISREAL( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_lintra\", \n\t\t\tPEGETREAL( a ), PEGETII( b ), 0.0 );\n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\n/* Subtract two objects.\n */\nstatic void\naction_proc_sub( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\n\tif( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\tif( !heap_real_new( heap, \n\t\t\tPEGETREAL( a ) - PEGETREAL( b ), out ) )\n\t\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISCOMPLEX( a ) && PEISCOMPLEX( b ) ) {\n\t\tif( !heap_complex_new( heap, \n\t\t\tPEGETREALPART( a ) - PEGETREALPART( b ), \n\t\t\tPEGETIMAGPART( a ) - PEGETIMAGPART( b ), \n\t\t\tout ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISCOMPLEX( a ) && PEISREAL( b ) ) {\n\t\tif( !heap_complex_new( heap, \n\t\t\tPEGETREALPART( a ) - PEGETREAL( b ), \n\t\t\tPEGETIMAGPART( a ), out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISREAL( a ) && PEISCOMPLEX( b ) ) {\n\t\tif( !heap_complex_new( heap, \n\t\t\tPEGETREAL( a ) - PEGETREALPART( b ),\n\t\t\tPEGETIMAGPART( b ), out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISIMAGE( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_subtract\", \n\t\t\tPEGETII( a ), PEGETII( b ) );\n\telse if( PEISIMAGE( a ) && PEISREAL( b ) ) \n\t\tcallva( rc, out, \"im_lintra\", \n\t\t\t1.0, PEGETII( a ), -PEGETREAL( b ) );\n\telse if( PEISREAL( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_lintra\", \n\t\t\t-1.0, PEGETII( b ), PEGETREAL( a ) );\n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\n/* Add two objects.\n */\nstatic void\naction_proc_add( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\n\tif( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\tif( !heap_real_new( heap, \n\t\t\tPEGETREAL( a ) + PEGETREAL( b ), out ) )\n\t\t\taction_boperror( rc, compile, \n\t\t\t\terror_get_sub(), op, name, a, b );\n\t}\n\telse if( PEISCOMPLEX( a ) && PEISCOMPLEX( b ) ) {\n\t\tif( !heap_complex_new( heap, \n\t\t\tPEGETREALPART( a ) + PEGETREALPART( b ), \n\t\t\tPEGETIMAGPART( a ) + PEGETIMAGPART( b ), \n\t\t\tout ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISCOMPLEX( a ) && PEISREAL( b ) ) {\n\t\tif( !heap_complex_new( heap, \n\t\t\tPEGETREALPART( a ) + PEGETREAL( b ), \n\t\t\tPEGETIMAGPART( a ), out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISREAL( a ) && PEISCOMPLEX( b ) ) {\n\t\tif( !heap_complex_new( heap, \n\t\t\tPEGETREAL( a ) + PEGETREALPART( b ),\n\t\t\tPEGETIMAGPART( b ), out ) )\n\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\top, name, a, b );\n\t}\n\telse if( PEISIMAGE( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_add\", \n\t\t\tPEGETII( a ), PEGETII( b ) );\n\telse if( PEISIMAGE( a ) && PEISREAL( b ) )  \n\t\tcallva( rc, out, \"im_lintra\", \n\t\t\t1.0, PEGETII( a ), PEGETREAL( b ) );\n\telse if( PEISREAL( a ) && PEISIMAGE( b ) ) \n\t\tcallva( rc, out, \"im_lintra\", \n\t\t\t1.0, PEGETII( b ), PEGETREAL( a ) );\n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n}\n\n/* Evaluate a binary operator on args a and b, write the result to out. a and\n * b already reduced.\n *\n * Call one of the things above. Not all combinations implemented, got bored :/\n * Implement simple things in the switch, break to the functions above for \n * the rest.\n *\n * out can be rhs of argv[0], careful.\n */\nstatic void\naction_proc_bop_strict( Reduce *rc, Compile *compile,\n\tint op, const char *name, HeapNode **arg, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\tHeapNode *hn;\n\tPElement left, right;\n\tPElement *a = &left;\n\tPElement *b = &right;\n\n\tPEPOINTRIGHT( arg[1], &left );\n\tPEPOINTRIGHT( arg[0], &right );\n\n\tswitch( op ) {\n\tcase BI_SELECT:\n\t\taction_proc_index( rc, compile, op, name, arg, out );\n\t\tbreak;\n\n\tcase BI_JOIN:\n\t\taction_proc_join( rc, compile, op, name, arg, out );\n\t\tbreak;\n\n\tcase BI_EQ:\n\t\taction_proc_equal( rc, compile, op, name, arg, out );\n\t\tbreak;\n\n\tcase BI_NOTEQ:\n\t\taction_proc_notequal( rc, compile, op, name, arg, out );\n\t\tbreak;\n\n\tcase BI_PEQ:\n\t\tPEPUTP( out, ELEMENT_BOOL, \n\t\t\tPEGETTYPE( a ) == PEGETTYPE( b ) && \n\t\t\tPEGETVAL( a ) == PEGETVAL( b ) );\n\t\tbreak;\n\n\tcase BI_PNOTEQ:\n\t\tPEPUTP( out, ELEMENT_BOOL, \n\t\t\tPEGETTYPE( a ) != PEGETTYPE( b ) ||\n\t\t\tPEGETVAL( a ) != PEGETVAL( b ) );\n\t\tbreak;\n\n\tcase BI_ADD:\n\t\taction_proc_add( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_SUB:\n\t\taction_proc_sub( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_MUL:\n\t\taction_proc_mul( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_DIV:\n\t\taction_proc_div( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_DOT:\n\t\taction_proc_dot( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_POW:\n\t\taction_proc_exp( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_LSHIFT:\n\t\taction_proc_lshift( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_RSHIFT:\n\t\taction_proc_rshift( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_REM:\n\t\taction_proc_rem( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_LESS:\n\t\taction_proc_less( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_LESSEQ:\n\t\taction_proc_lesseq( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_COMMA:\n\t\tif( PEISREAL( a ) && PEISREAL( b ) ) {\n\t\t\tif( NEWNODE( heap, hn ) )\n\t\t\t\taction_boperror( rc, compile, error_get_sub(), \n\t\t\t\t\top, name, a, b );\n\n\t\t\t/* Form complex node.\n\t\t\t */\n\t\t\thn->type = TAG_COMPLEX;\n\t\t\tPPUT( hn, \n\t\t\t\tELEMENT_NODE, PEGETVAL( a ),\n\t\t\t\tELEMENT_NODE, PEGETVAL( b ) );\n\n\t\t\tPEPUTP( out, ELEMENT_NODE, hn );\n\t\t}\n\t\telse if( PEISIMAGE( a ) && PEISIMAGE( b ) ) {\n\t\t\tcallva( rc, out, \"im_ri2c\", \n\t\t\t\tPEGETII( a ), PEGETII( b ) ); \n\t\t}\n\t\telse\n\t\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n\n\t\tbreak;\n\n\tcase BI_BAND:\n\t\taction_proc_band( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_BOR:\n\t\taction_proc_bor( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_EOR:\n\t\taction_proc_eor( rc, compile, op, name, a, b, out );\n\t\tbreak;\n\n\tcase BI_NONE:\n\tdefault:\n\t\taction_boperror( rc, compile,\n\t\t\t_( \"Unimplemented.\" ), op, name, a, b );\n\t\tbreak;\n\t}\n}\n\n/* Evaluate a unary operator on arg a, write the result to out. a \n * already reduced.\n */\nvoid\naction_proc_uop( Reduce *rc, Compile *compile,\n\tint op, const char *name, HeapNode **arg, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\tPElement pe, *a = &pe;\n\tPElement rhs;\n\n\tPEPOINTRIGHT( arg[0], &pe );\n\n\tswitch( op ) {\n\tcase UN_NEG:\n\t\tif( PEISREAL( a ) ) {\n\t\t\tif( !heap_real_new( heap, !PEGETREAL( a ), out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISCOMPLEX( a ) ) {\n\t\t\tif( !heap_complex_new( heap, !PEGETREALPART( a ), \n\t\t\t\t!PEGETIMAGPART( a ), out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISBOOL( a ) ) {\n\t\t\tPEPUTP( out, ELEMENT_BOOL, !PEGETBOOL( a ) );\n\t\t}\n\t\telse if( PEISIMAGE( a ) ) \n\t\t\tcallva( rc, out, \"im_equalconst\", PEGETII( a ), 0.0 );\n\t\telse\n\t\t\taction_uoperror( rc, compile, NULL, op, name, a ); \n\n\t\tbreak;\n\n\tcase UN_MINUS:\n\t\tif( PEISREAL( a ) ) {\n\t\t\tif( !heap_real_new( heap, -PEGETREAL( a ), out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISCOMPLEX( a ) ) {\n\t\t\tif( !heap_complex_new( heap, -PEGETREALPART( a ), \n\t\t\t\t-PEGETIMAGPART( a ), out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISIMAGE( a ) ) \n\t\t\tcallva( rc, out, \"im_lintra\", \n\t\t\t\t-1.0, PEGETII( a ), 0.0 );\n\t\telse\n\t\t\taction_uoperror( rc, compile, NULL, op, name, a ); \n\n\t\tbreak;\n\n\tcase UN_COMPLEMENT:\n\t\tif( PEISREAL( a ) ) {\n\t\t\tint v = PEGETREAL( a );\n\n\t\t\tif( !heap_real_new( heap, ~v, out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISIMAGE( a ) ) \n\t\t\tcallva( rc, out, \"im_eorimageconst\", \n\t\t\t\tPEGETII( a ), -1 );\n\t\telse\n\t\t\taction_uoperror( rc, compile, NULL, op, name, a ); \n\t\tbreak;\n\n\tcase UN_PLUS:\n\t\tPEPUTPE( out, a );\n\t\tbreak;\n\n\n\tcase UN_CSCHAR:\n\t\t/* Convert to signed char.\n\t\t */\n\t\tif( PEISNUM( a ) ) {\n\t\t\taction_set_range( rc, SCHAR_MIN, SCHAR_MAX, a, out );\n\t\t}\n\t\telse if( PEISCHAR( a ) ) {\n\t\t\tif( !heap_real_new( heap, PEGETCHAR( a ), out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISIMAGE( a ) ) \n\t\t\tcallva( rc, out, \"im_clip2c\", PEGETII( a ) );\n\t\telse\n\t\t\taction_uoperror( rc, compile, NULL, op, name, a ); \n\n\t\tbreak;\n\n\tcase UN_CUCHAR:\n\t\t/* Convert to unsigned char, eg. 65 => 'A'.\n\t\t */\n\t\tif( PEISREAL( a ) ) {\n\t\t\tdouble v = PEGETREAL( a );\n\n\t\t\tv = IM_CLIP( 0, v, UCHAR_MAX );\n\n\t\t\tPEPUTP( out, ELEMENT_CHAR, (int) v );\n\t\t}\n\t\telse if( PEISCOMPLEX( a ) ) {\n\t\t\tdouble v = PEGETREALPART( a );\n\n\t\t\tv = IM_CLIP( 0, v, UCHAR_MAX );\n\n\t\t\tPEPUTP( out, ELEMENT_CHAR, (int) v );\n\t\t}\n\t\telse if( PEISCHAR( a ) ) {\n\t\t\tPEPUTPE( out, a );\n\t\t}\n\t\telse if( PEISIMAGE( a ) ) \n\t\t\tcallva( rc, out, \"im_clip\", PEGETII( a ) );\n\t\telse\n\t\t\taction_uoperror( rc, compile, NULL, op, name, a ); \n\n\t\tbreak;\n\n\tcase UN_CSINT:\n\t\t/* Convert to signed int.\n\t\t */\n\t\tif( PEISNUM( a ) ) \n\t\t\taction_set_range( rc, \n\t\t\t\tINT_MIN, INT_MAX, a, out );\n\t\telse if( PEISCHAR( a ) ) {\n\t\t\tif( !heap_real_new( heap, PEGETCHAR( a ), out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISIMAGE( a ) ) \n\t\t\tcallva( rc, out, \"im_clip2i\", PEGETII( a ) );\n\t\telse\n\t\t\taction_uoperror( rc, compile, NULL, op, name, a ); \n\n\t\tbreak;\n\n\tcase UN_CUINT:\n\t\t/* Convert to unsigned int.\n\t\t */\n\t\tif( PEISREAL( a ) || PEISCOMPLEX( a ) ) \n\t\t\taction_set_range( rc, 0, UINT_MAX, a, out );\n\t\telse if( PEISCHAR( a ) ) {\n\t\t\tif( !heap_real_new( heap, PEGETCHAR( a ), out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISIMAGE( a ) ) \n\t\t\tcallva( rc, out, \"im_clip2ui\", PEGETII( a ) );\n\t\telse\n\t\t\taction_uoperror( rc, compile, NULL, op, name, a ); \n\n\t\tbreak;\n\n\tcase UN_CSSHORT:\n\t\t/* Convert to signed short.\n\t\t */\n\t\tif( PEISREAL( a ) || PEISCOMPLEX( a ) ) \n\t\t\taction_set_range( rc, \n\t\t\t\tSHRT_MIN, SHRT_MAX, a, out );\n\t\telse if( PEISCHAR( a ) ) {\n\t\t\tif( !heap_real_new( heap, PEGETCHAR( a ), out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISIMAGE( a ) ) \n\t\t\tcallva( rc, out, \"im_clip2s\", PEGETII( a ) );\n\t\telse\n\t\t\taction_uoperror( rc, compile, NULL, op, name, a ); \n\n\t\tbreak;\n\n\tcase UN_CUSHORT:\n\t\t/* Convert to unsigned short.\n\t\t */\n\t\tif( PEISREAL( a ) || PEISCOMPLEX( a ) ) \n\t\t\taction_set_range( rc, 0, USHRT_MAX, a, out );\n\t\telse if( PEISCHAR( a ) ) {\n\t\t\tif( !heap_real_new( heap, PEGETCHAR( a ), out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISIMAGE( a ) ) \n\t\t\tcallva( rc, out, \"im_clip2us\", PEGETII( a ) );\n\t\telse\n\t\t\taction_uoperror( rc, compile, NULL, op, name, a ); \n\n\t\tbreak;\n\n\tcase UN_CFLOAT:\n\t\t/* Convert to float ... just drop imag part.\n\t\t */\n\t\tif( PEISCOMPLEX( a ) ) {\n\t\t\tif( !heap_real_new( heap, \n\t\t\t\tPEGETREALPART( a ), out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISREAL( a ) ) {\n\t\t\tPEPUTPE( out, a );\n\t\t}\n\t\telse if( PEISCHAR( a ) ) {\n\t\t\tif( !heap_real_new( heap, PEGETCHAR( a ), out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISIMAGE( a ) ) \n\t\t\tcallva( rc, out, \"im_clip2f\", PEGETII( a ) );\n\t\telse\n\t\t\taction_uoperror( rc, compile, NULL, op, name, a ); \n\n\t\tbreak;\n\n\tcase UN_CDOUBLE:\n\t\t/* Convert to double ... just drop imag part.\n\t\t */\n\t\tif( PEISCOMPLEX( a ) ) {\n\t\t\tif( !heap_real_new( heap, \n\t\t\t\tPEGETREALPART( a ), out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISREAL( a ) ) {\n\t\t\tPEPUTPE( out, a );\n\t\t}\n\t\telse if( PEISCHAR( a ) ) {\n\t\t\tif( !heap_real_new( heap, PEGETCHAR( a ), out ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISIMAGE( a ) ) \n\t\t\tcallva( rc, out, \"im_clip2d\", PEGETII( a ) );\n\t\telse\n\t\t\taction_uoperror( rc, compile, NULL, op, name, a ); \n\n\t\tbreak;\n\n\tcase UN_CDCOMPLEX:\n\tcase UN_CCOMPLEX:\n\t\t/* Convert to complex ... set imag = 0.\n\t\t */\n\t\tif( PEISREAL( a ) ) {\n\t\t\t/* Make base node.\n\t\t\t */\n\t\t\tif( !heap_complex_element_new( heap, a, a, out ) )\n\t\t\t\treduce_throw( rc );\n\n\t\t\t/* Install new imag part. \n\t\t\t */\n\t\t\tPEPOINTRIGHT( PEGETVAL( out ), &rhs );\n\t\t\tif( !heap_real_new( heap, 0, &rhs ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISCOMPLEX( a ) ) {\n\t\t\tPEPUTPE( out, a );\n\t\t}\n\t\telse if( PEISCHAR( a ) ) {\n\t\t\t/* Make base node.\n\t\t\t */\n\t\t\tif( !heap_complex_element_new( heap, a, a, out ) )\n\t\t\t\treduce_throw( rc );\n\n\t\t\t/* Install new real and imag parts.\n\t\t\t */\n\t\t\tPEPOINTLEFT( PEGETVAL( out ), &rhs );\n\t\t\tif( !heap_real_new( heap, PEGETCHAR( a ), &rhs ) )\n\t\t\t\treduce_throw( rc );\n\t\t\tPEPOINTRIGHT( PEGETVAL( out ), &rhs );\n\t\t\tif( !heap_real_new( heap, 0, &rhs ) )\n\t\t\t\treduce_throw( rc );\n\t\t}\n\t\telse if( PEISIMAGE( a ) ) {\n\t\t\tif( op == UN_CCOMPLEX )\n\t\t\t\tcallva( rc, out, \n\t\t\t\t\t\"im_clip2cm\", PEGETII( a ) );\n\t\t\telse\n\t\t\t\tcallva( rc, out, \n\t\t\t\t\t\"im_clip2dcm\", PEGETII( a ) );\n\t\t}\n\t\telse\n\t\t\taction_uoperror( rc, compile, NULL, op, name, a ); \n\n\t\tbreak;\n\n\tcase UN_NONE:\n\tdefault:\n\t\taction_uoperror( rc, compile, \n\t\t\t_( \"Unimplemented.\" ), op, name, a );\n\t\tbreak;\n\t}\n}\n\nstatic void *\naction_proc_construct_sub( Reduce *rc, PElement *pe,\n\tCompile *compile, HeapNode **arg, PElement *out )\n{\n\tif( !class_new( rc->heap, compile, arg, pe ) ) \n\t\treduce_throw( rc );\n\n\tPEPUTPE( out, pe );\n\n\treturn( NULL );\n}\n\n/* Eval a constructor. Nasty: out can be RHS of arg[0], so we have to build\n * instance in a safe spot, then write back to out afterwards.\n */\nvoid\naction_proc_construct( Reduce *rc, \n\tCompile *compile, HeapNode **arg, PElement *out )\n{\n\tif( trace_flags & TRACE_CLASS_NEW ) {\n\t\tVipsBuf *buf = trace_push();\n\n\t\tvips_buf_appendf( buf, \"constructor \\\"%s\\\" \", \n\t\t\tIOBJECT( compile->sym )->name );\n\t\ttrace_args( arg, compile->nparam + compile->nsecret );\n\t}\n\n\tif( reduce_safe_pointer( rc, \n\t\t(reduce_safe_pointer_fn) action_proc_construct_sub,\n\t\tcompile, arg, out, NULL ) )\n\t\treduce_throw( rc );\n\n\t/* Is it a class with a typecheck member? Return that instead.\n\t */\n\tif( compile_lookup( compile, MEMBER_CHECK ) &&\n\t\tclass_get_member( out, MEMBER_CHECK, NULL, out ) ) {\n#ifdef DEBUG\n\t\tprintf( \"reduce: invoking arg checker\\n\" );\n#endif \n\t}\n\n\tif( trace_flags & TRACE_CLASS_NEW ) {\n\t\ttrace_result( TRACE_CLASS_NEW, out );\n\t\ttrace_pop();\n\t}\n}\n\nstatic void *\naction_proc_class_binary_sub( Reduce *rc, PElement *pe,\n\tPElement *fn, const char *name, PElement *b, PElement *out )\n{\n\tPElement rhs;\n\tPElement base;\n\n\tbase = *pe;\n\theap_appl_init( &base, fn );\n\tif( !heap_appl_add( rc->heap, &base, &rhs ) ||\n\t\t!heap_managedstring_new( rc->heap, name, &rhs ) ||\n\t\t!heap_appl_add( rc->heap, &base, &rhs ) ) \n\t\treturn( out );\n\n\tPEPUTPE( &rhs, b );\n\tPEPUTPE( out, pe );\n\n\treturn( NULL );\n}\n\n/* Something like \"class + 12\" ... call (class.add 12)\n */\nstatic void\naction_proc_class_binary( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tTraceFlags flags = op >= 0 ? TRACE_OPERATOR : TRACE_BUILTIN;\n\tPElement fn;\n\n\tif( trace_flags & flags ) {\n\t\tVipsBuf *buf = trace_push();\n\n\t\tvips_buf_appendf( buf, \"%s\\n\", _( \"invoking method:\" ) );\n\t\tvips_buf_appends( buf, \"     \" );\n\t\ttrace_pelement( a );\n\t\tvips_buf_appendf( buf, \".%s \\\"%s\\\" \", MEMBER_OO_BINARY, name );\n\t\ttrace_pelement( b );\n\t\tvips_buf_appends( buf, \"\\n\" );\n\n\t\ttrace_text( flags, \"%s\", vips_buf_all( buf ) );\n\n\t\ttrace_pop();\n\t}\n\n\t/* Look up a.oo_binary and build (a.dispatch_binary \"add\" b) \n\t * application.\n\t */\n\tif( !class_get_member( a, MEMBER_OO_BINARY, NULL, &fn ) )\n\t\taction_boperror( rc, compile, error_get_sub(), op, name, a, b );\n\n\tif( reduce_safe_pointer( rc, \n\t\t(reduce_safe_pointer_fn) action_proc_class_binary_sub,\n\t\t&fn, (void *) name, b, out ) )\n\t\taction_boperror( rc, compile, error_get_sub(), op, name, a, b );\n}\n\n/* Something like \"12 + class\" ... call (class.add' 12)\n */\nstatic void\naction_proc_class_binary2( Reduce *rc, Compile *compile,\n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\tTraceFlags flags = op >= 0 ? TRACE_OPERATOR : TRACE_BUILTIN;\n\tPElement fn;\n\n\tif( trace_flags & flags ) {\n\t\tVipsBuf *buf = trace_push();\n\n\t\tvips_buf_appendf( buf, \"%s\\n\", _( \"invoking method:\" ) );\n\t\tvips_buf_appends( buf, \"     \" );\n\t\ttrace_pelement( b );\n\t\tvips_buf_appendf( buf, \".%s \\\"%s\\\" \", MEMBER_OO_BINARY2, name );\n\t\ttrace_pelement( a );\n\t\tvips_buf_appends( buf, \"\\n\" );\n\n\t\ttrace_text( flags, \"%s\", vips_buf_all( buf ) );\n\n\t\ttrace_pop();\n\t}\n\n\t/* Look up b.dispatch_binary2 and build \n\t * (b.dispatch_binary2 \"add\" a) application.\n\t */\n\tif( !class_get_member( b, MEMBER_OO_BINARY2, NULL, &fn ) )\n\t\taction_boperror( rc, compile, error_get_sub(), op, name, a, b );\n\n\tif( reduce_safe_pointer( rc, \n\t\t(reduce_safe_pointer_fn) action_proc_class_binary_sub,\n\t\t&fn, (void *) name, a, out ) )\n\t\taction_boperror( rc, compile, error_get_sub(), op, name, a, b );\n}\n\nstatic void\naction_landlor( Reduce *rc, Compile *compile, \n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\treduce_spine( rc, a );\n\n\tif( PEISCOMB( a ) && PEGETCOMB( a ) == COMB_I )\n\t\t/* The reduce_spine() did us recursively ... bounce back.\n\t\t */\n\t\treturn;\n\n\tif( trace_flags & TRACE_OPERATOR ) \n\t\ttrace_push();\n\n\t/* Examine the LHS and see if we can avoid RHS eval.\n\t */\n\tif( PEISCLASS( a ) )\n\t\taction_proc_class_binary( rc, compile, op, name, a, b, out );\n\telse if( PEISBOOL( a ) ) {\n\t\tif( op == BI_LOR && PEGETBOOL( a ) ) {\n\t\t\tif( trace_flags & TRACE_OPERATOR ) \n\t\t\t\ttrace_binop( compile, a, op, b );\n\n\t\t\tPEPUTP( out, ELEMENT_BOOL, TRUE );\n\n\t\t\tif( trace_flags & TRACE_OPERATOR ) \n\t\t\t\ttrace_result( TRACE_OPERATOR, out );\n\t\t}\n\t\telse if( op == BI_LAND && !PEGETBOOL( a ) ) {\n\t\t\tif( trace_flags & TRACE_OPERATOR ) \n\t\t\t\ttrace_binop( compile, a, op, b );\n\n\t\t\tPEPUTP( out, ELEMENT_BOOL, FALSE );\n\n\t\t\tif( trace_flags & TRACE_OPERATOR ) \n\t\t\t\ttrace_result( TRACE_OPERATOR, out );\n\t\t}\n\t\telse {\n\t\t\t/* Need to look at RHS too.\n\t\t\t */\n\t\t\treduce_spine( rc, b );\n\n\t\t\tif( PEISCOMB( b ) && PEGETCOMB( b ) != COMB_I ) {\n\t\t\t\tif( trace_flags & TRACE_OPERATOR ) \n\t\t\t\t\ttrace_pop();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif( PEISCLASS( b ) )\n\t\t\t\taction_proc_class_binary2( rc, compile, \n\t\t\t\t\top, name, a, b, out );\n\t\t\telse if( PEISBOOL( b ) ) {\n\t\t\t\tif( trace_flags & TRACE_OPERATOR ) \n\t\t\t\t\ttrace_binop( compile, a, op, b );\n\n\t\t\t\tPEPUTP( out, ELEMENT_BOOL, PEGETBOOL( b ) );\n\n\t\t\t\tif( trace_flags & TRACE_OPERATOR ) \n\t\t\t\t\ttrace_result( TRACE_OPERATOR, out );\n\t\t\t}\n\t\t\telse\n\t\t\t\taction_boperror( rc, compile, \n\t\t\t\t\tNULL, op, name, a, b );\n\t\t}\n\t}\n\telse\n\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n\n\tif( trace_flags & TRACE_OPERATOR ) \n\t\ttrace_pop();\n}\n\nstatic void\naction_if( Reduce *rc, Compile *compile, \n\tint op, const char *name, PElement *a, PElement *b, PElement *out )\n{\n\treduce_spine( rc, a );\n\n\tif( PEISCOMB( a ) && PEGETCOMB( a ) == COMB_I )\n\t\t/* The reduce_spine() did us recursively ... bounce back.\n\t\t */\n\t\treturn;\n\n\tif( PEISCLASS( a ) )\n\t\taction_proc_class_binary( rc, compile, op, name, a, b, out );\n\telse {\n\t\tPElement t, e;\n\n\t\t/* a is condition, b should be [then-part, else-part] ... \n\t\t * look down b and find them. Block trace for this, not very\n\t\t * interesting.\n\t\t */\n\t\ttrace_block();\n\t\treduce_list_index( rc, b, 0, &t );\n\t\treduce_list_index( rc, b, 1, &e );\n\t\ttrace_unblock();\n\n\t\t/* Can be BOOL or image.\n\t\t */\n\t\tif( PEISBOOL( a ) ) {\n\t\t\tif( trace_flags & TRACE_OPERATOR ) {\n\t\t\t\tVipsBuf *buf = trace_push();\n\n\t\t\t\tvips_buf_appendf( buf, \"if \" );\n\t\t\t\ttrace_pelement( a );\n\t\t\t\tvips_buf_appendf( buf, \" then \" );\n\t\t\t\ttrace_pelement( &t );\n\t\t\t\tvips_buf_appendf( buf, \" else \" );\n\t\t\t\ttrace_pelement( &e );\n\t\t\t\tvips_buf_appendf( buf, \" ->\\n\" );\n\t\t\t}\n\n\t\t\tif( PEGETBOOL( a ) ) {\n\t\t\t\tPEPUTPE( out, &t );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tPEPUTPE( out, &e );\n\t\t\t}\n\n\t\t\tif( trace_flags & TRACE_OPERATOR ) {\n\t\t\t\ttrace_result( TRACE_OPERATOR, out );\n\t\t\t\ttrace_pop();\n\t\t\t}\n\t\t}\n\t\telse if( PEISIMAGE( a ) ) {\n\t\t\treduce_spine_strict( rc, &t );\n\t\t\treduce_spine_strict( rc, &e );\n\n\t\t\t/* then/else parts must both be image.\n\t\t\t */\n\t\t\tif( !PEISIMAGE( &t ) || !PEISIMAGE( &e ) ) \n\t\t\t\taction_boperror( rc, compile, NULL, \n\t\t\t\t\top, name, a, b );\n\n\t\t\tcallva( rc, out, \"im_ifthenelse\", \n\t\t\t\tPEGETII( a ), PEGETII( &t ), PEGETII( &e ) ); \n\t\t}\n\t\telse \n\t\t\taction_boperror( rc, compile, NULL, op, name, a, b );\n\t}\n}\n\n/* Do a binary operator. Result in arg[0].\n */\nvoid\naction_proc_bop( Reduce *rc, Compile *compile, BinOp bop, HeapNode **arg )\n{\n\tPElement a, b, out;\n\n\tswitch( bop ) {\n\tcase BI_LAND:\n\tcase BI_LOR:\n\t\t/* Special ninja magic :-( we need to handle reduce carefully \n\t\t * here.\n\t\t */\n\t\tPEPOINTRIGHT( arg[0], &b );\n\t\tPEPOINTRIGHT( arg[1], &a );\n\t\tPEPOINTRIGHT( arg[0], &out );\n\n\t\taction_landlor( rc, compile, \n\t\t\tbop, OPERATOR_NAME( bop ), &a, &b, &out );\n\n\t\t/* Overwrite arg[0] with I node, in case this is a\n\t\t * shared node.\n\t\t */\n\t\tPPUTLEFT( arg[0], ELEMENT_COMB, COMB_I );\n\n\t\tbreak;\n\n\tcase BI_IF:\n\t\t/* If is lazy-ish in it's 2nd argument too.\n\t\t */\n\t\tPEPOINTRIGHT( arg[0], &b );\n\t\tPEPOINTRIGHT( arg[1], &a );\n\t\tPEPOINTRIGHT( arg[0], &out );\n\n\t\taction_if( rc, compile, \n\t\t\tbop, OPERATOR_NAME( bop ), &a, &b, &out );\n\n\t\t/* Overwrite arg[0] with I node, in case this is a\n\t\t * shared node.\n\t\t */\n\t\tPPUTLEFT( arg[0], ELEMENT_COMB, COMB_I );\n\n\t\tbreak;\n\n\tcase BI_DOT:\n\tcase BI_PEQ:\n\tcase BI_PNOTEQ:\n\t\t/* Strict, not overrideable.\n\t\t */\n\t\taction_dispatch( rc, compile, reduce_spine, \n\t\t\tbop, OPERATOR_NAME( bop ), FALSE,\n\t\t\t(ActionFn) action_proc_bop_strict, 2, arg, NULL );\n\n\t\tbreak;\n\n\tdefault:\n\t\t/* Strict, overrideable.\n\t\t */\n\t\taction_dispatch( rc, compile, reduce_spine, \n\t\t\tbop, OPERATOR_NAME( bop ), TRUE,\n\t\t\t(ActionFn) action_proc_bop_strict, 2, arg, NULL );\n\t}\n}\n\nstatic void *\naction_proc_class_unary_sub( Reduce *rc, PElement *pe,\n\tPElement *fn, const char *name, PElement *out )\n{\n\tPElement rhs;\n\tPElement base;\n\n\tbase = *pe;\n\theap_appl_init( &base, fn );\n\tif( !heap_appl_add( rc->heap, &base, &rhs ) ||\n\t\t!heap_managedstring_new( rc->heap, name, &rhs ) )\n\t\treturn( out );\n\n\tPEPUTPE( out, pe );\n\n\treturn( NULL );\n}\n\nstatic void\naction_proc_class_unary( Reduce *rc, Compile *compile, \n\tint op, const char *name, PElement *a, PElement *out )\n{\n\tTraceFlags flags = op >= 0 ? TRACE_OPERATOR : TRACE_BUILTIN;\n\tPElement fn;\n\n\tif( trace_flags & flags ) {\n\t\tVipsBuf *buf = trace_push();\n\n\t\tvips_buf_appendf( buf, \"%s\\n\", _( \"invoking method:\" ) );\n\t\tvips_buf_appends( buf, \"     \" );\n\t\ttrace_pelement( a );\n\t\tvips_buf_appendf( buf, \".%s \\\"%s\\\"\\n\", MEMBER_OO_UNARY, name );\n\n\t\ttrace_text( flags, \"%s\", vips_buf_all( buf ) );\n\n\t\ttrace_pop();\n\t}\n\n\t/* Look up a.dispatch_unary and build \n\t * (a.oo_unary \"minus\") application.\n\t */\n\tif( !class_get_member( a, MEMBER_OO_UNARY, NULL, &fn ) )\n\t\taction_uoperror( rc, compile, error_get_sub(), op, name, a );\n\n\tif( reduce_safe_pointer( rc, \n\t\t(reduce_safe_pointer_fn) action_proc_class_unary_sub,\n\t\t&fn, (void *) name, out, NULL ) )\n\t\taction_uoperror( rc, compile, error_get_sub(), op, name, a );\n}\n\n/* Run a function on the graph ... eval all the args, avoid eval if we reduce\n * ourselves as a side effect (happens on recursive calls). Result in RHS of \n * arg[0].\n */\nvoid\naction_dispatch( Reduce *rc, Compile *compile, ReduceFunction rfn, \n\tint op, const char *name, gboolean override,\n\tActionFn afn, int nargs, HeapNode **arg, void *user )\n{ \n\tTraceFlags flags = op >= 0 ? TRACE_OPERATOR : TRACE_BUILTIN;\n\tPElement a, b;\n\tint i;\n\n\t/* Don't allow nargs == 0. We rely on having a bit of graph we can\n\t * replace with (I result) for caching.\n\t */\n\tg_assert( nargs > 0 );\n\n\t/* We need to have the \n\t */\n\tg_assert( noperator_table == UN_LAST );\n\n\t/* Reduce all the args.\n\t */\n\tfor( i = 0; i < nargs; i++ ) {\n\t\tPElement rhs;\n\n\t\tPEPOINTRIGHT( arg[i], &rhs );\n\t\trfn( rc, &rhs );\n\t}\n\n\t/* We may have evaled ourselves already.\n\t */\n\tPEPOINTLEFT( arg[0], &b );\n\tif( PEISCOMB( &b ) && PEGETCOMB( &b ) == COMB_I ) \n\t\treturn;\n\n\tPEPOINTRIGHT( arg[0], &b );\n\tPEPOINTRIGHT( arg[1], &a );\n\n\tif( trace_flags & flags ) {\n\t\tVipsBuf *buf = trace_push();\n\n\t\tvips_buf_appendf( buf, \"\\\"%s\\\" \", name );\n\t\ttrace_args( arg, nargs );\n\t}\n\n\tif( override && nargs == 2 && PEISCLASS( &a ) )\n\t\taction_proc_class_binary( rc, compile, op, name, &a, &b, &b );\n\telse if( override && nargs == 2 && PEISCLASS( &b ) )\n\t\taction_proc_class_binary2( rc, compile, op, name, &a, &b, &b );\n\telse if( override && nargs == 1 && PEISCLASS( &b ) )\n\t\taction_proc_class_unary( rc, compile, op, name, &b, &b );\n\telse \n\t\tafn( rc, compile, op, name, arg, &b, user );\n\n\tPPUTLEFT( arg[0], ELEMENT_COMB, COMB_I );\n\n\tif( trace_flags & flags ) {\n\t\ttrace_result( flags, &b );\n\t\ttrace_pop();\n\t}\n}\n"
  },
  {
    "path": "src/action.h",
    "content": "/* Graph actions.\n */\n\n/* A strict action on the graph.\n */\ntypedef void (*ActionFn)( Reduce *, Compile *,\n\tint, const char *, HeapNode **, PElement *, void * );\n\n/* A sort of reducer (eg. lazy or strict, or hyperstrict)\n */\ntypedef void (*ReduceFunction)( Reduce *, PElement * );\n\n#define OPERATOR_NAME( OP ) ( \\\n\t(int) (OP) >= 0 && (int) (OP) < noperator_table ? \\\n\t\toperator_table[(int) (OP)] : \"<unknown>\" \\\n)\n\nextern const char *operator_table[];\nextern const int noperator_table;\n\nvoid action_proc_uop( Reduce *rc, Compile *compile,\n\tint op, const char *name, HeapNode **arg, PElement *out );\nvoid action_proc_construct( Reduce *rc, Compile *compile, \n\tHeapNode **arg, PElement *out );\n\nvoid action_proc_bop( Reduce *rc, Compile *compile, \n\tBinOp bop, HeapNode **arg );\n\nvoid action_dispatch( Reduce *rc, Compile *compile, ReduceFunction rfn, \n\tint op, const char *name, gboolean override,\n\tActionFn afn, int nargs, HeapNode **arg, void *user );\n"
  },
  {
    "path": "src/boxes.c",
    "content": "/* Make various little popup dialogs ... error, info, question.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk \n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* Max amount of text in a info/error/question dialog.\n */\n#define MAX_DIALOG_TEXT (2000)\n\n/* Find a window to use as dialog parent.\n */\nstatic GtkWidget *\nbox_pick_parent( GtkWidget *par )\n{\n\tif( !par ) \n\t\treturn( GTK_WIDGET( mainw_pick_one() ) );\n\telse \n\t\treturn( par );\n}\n\n/* Make the insides of a error, info or question dialog.\n */\nstatic void\nbox_build( iDialog *idlg, \n\tGtkWidget *work, char *s, const char *stock_id )\n{\t\n\tGtkWidget *icon;\n\tGtkWidget *hb;\n\tGtkWidget *lab;\n\n\thb = gtk_hbox_new( FALSE, 12 );\n\tgtk_container_border_width( GTK_CONTAINER( hb ), 0 );\n\tgtk_container_add( GTK_CONTAINER( work ), hb );\n\tgtk_widget_show( hb );\n\n\ticon = gtk_image_new_from_stock( stock_id, GTK_ICON_SIZE_DIALOG );\n\tgtk_misc_set_alignment( GTK_MISC( icon ), 0.0, 0.0 );\n        gtk_box_pack_start( GTK_BOX( hb ), icon, FALSE, FALSE, 0 );\n\tgtk_widget_show( icon );\n\n\tlab = gtk_label_new( NULL );\n\tgtk_label_set_markup( GTK_LABEL( lab ), s );\n        gtk_label_set_justify( GTK_LABEL( lab ), GTK_JUSTIFY_LEFT );\n        gtk_label_set_selectable( GTK_LABEL( lab ), TRUE );\n\tgtk_label_set_line_wrap( GTK_LABEL( lab ), TRUE );\n        gtk_box_pack_start( GTK_BOX( hb ), lab, FALSE, FALSE, 0 );\n\tgtk_widget_show( lab );\n}\n\n/* Make an error dialog.\n */\n/*VARARGS2*/\nstatic void\nbox_error( GtkWidget *par, const char *fmt, ... )\n{\n\tva_list ap;\n\tchar buf[MAX_DIALOG_TEXT];\n\tGtkWidget *idlg;\n\n        va_start( ap, fmt );\n\t(void) im_vsnprintf( buf, MAX_DIALOG_TEXT, fmt, ap );\n        va_end( ap );\n\n\tidlg = idialog_new();\n\tidialog_set_build( IDIALOG( idlg ), \n\t\t(iWindowBuildFn) box_build, buf, GTK_STOCK_DIALOG_ERROR, NULL );\n\tidialog_set_callbacks( IDIALOG( idlg ), NULL, NULL, NULL, NULL );\n\tidialog_add_ok( IDIALOG( idlg ), iwindow_true_cb, GTK_STOCK_OK );\n\tiwindow_set_parent( IWINDOW( idlg ), box_pick_parent( par ) );\n\tiwindow_build( IWINDOW( idlg ) );\n\n\tgtk_widget_show( GTK_WIDGET( idlg ) );\n}\n\n/* Mark up a top/sub pair for a dialog box.\n */\nstatic void\nbox_vmarkup( char *out, const char *top, const char *sub, va_list ap )\n{\n\tchar buf1[MAX_DIALOG_TEXT];\n\tchar buf2[MAX_DIALOG_TEXT];\n\tchar buf3[MAX_DIALOG_TEXT];\n\n\tescape_markup( top, buf1, MAX_DIALOG_TEXT );\n\t(void) im_vsnprintf( buf2, MAX_DIALOG_TEXT, sub, ap );\n\tescape_markup( buf2, buf3, MAX_DIALOG_TEXT );\n\n\t(void) im_snprintf( out, MAX_DIALOG_TEXT, \n\t\t\"<b><big>%s</big></b>\", buf1 );\n\tif( strcmp( buf3, \"\" ) != 0 ) {\n\t\tint len = strlen( out );\n\n\t\t(void) im_snprintf( out + len, MAX_DIALOG_TEXT - len, \n\t\t\t\"\\n\\n%s\", buf3 );\n\t}\n}\n\nstatic void\nbox_markup( char *out, const char *top, const char *sub, ... )\n{\n\tva_list ap;\n\n        va_start( ap, sub );\n\tbox_vmarkup( out, top, sub, ap );\n        va_end( ap );\n}\n\n/* Display buffered errors in an error dialog. \n */\nvoid\nbox_alert( GtkWidget *par )\n{\n\tchar buf[MAX_DIALOG_TEXT];\n\n\tif( main_option_batch ) {\n\t\t/* No X, just print.\n\t\t */\n\t\tfprintf( stderr, \"%s\\n\", error_get_top() );\n\t\tfprintf( stderr, \"%s\\n\", error_get_sub() );\n\t\treturn;\n\t}\n\n\tbox_markup( buf, error_get_top(), \"%s\", error_get_sub() );\n\tbox_error( par, \"%s\", buf );\n}\n\n/* Make an information dialog.\n */\nvoid\nbox_vinfo( GtkWidget *par, const char *top, const char *sub, va_list ap )\n{\n\tchar buf[MAX_DIALOG_TEXT];\n\tGtkWidget *idlg;\n\n\tbox_vmarkup( buf, top, sub, ap );\n\n\tidlg = idialog_new();\n\tidialog_set_build( IDIALOG( idlg ), \n\t\t(iWindowBuildFn) box_build, \n\t\t\tbuf, GTK_STOCK_DIALOG_INFO, NULL );\n\tidialog_set_callbacks( IDIALOG( idlg ), NULL, NULL, NULL, NULL );\n\tidialog_add_ok( IDIALOG( idlg ), iwindow_true_cb, GTK_STOCK_OK );\n\tiwindow_set_parent( IWINDOW( idlg ), box_pick_parent( par ) );\n\tiwindow_build( IWINDOW( idlg ) );\n\n\tgtk_widget_show( GTK_WIDGET( idlg ) );\n}\n\n/* Make an information dialog.\n */\nvoid\nbox_info( GtkWidget *par, const char *top, const char *sub, ... )\n{\n\tva_list ap;\n\n        va_start( ap, sub );\n\tbox_vinfo( par, top, sub, ap );\n        va_end( ap );\n}\n\n/* Pop up an 'Are you sure?' window. \n */\niDialog *\nbox_yesno( GtkWidget *par, \n\tiWindowFn okcb, iWindowFn cancelcb, void *client, /* Call client */\n\tiWindowNotifyFn nfn, void *sys,\t\t\t  /* Call parent */\n\tconst char *yes_label, \n\tconst char *top, const char *sub, ... )\n{\n\tva_list ap;\n\tchar buf[MAX_DIALOG_TEXT];\n\tGtkWidget *idlg;\n\n\tva_start( ap, sub );\n\tbox_vmarkup( buf, top, sub, ap );\n\tva_end( ap );\n\n\tidlg = idialog_new();\n\tidialog_set_build( IDIALOG( idlg ), \n\t\t(iWindowBuildFn) box_build, \n\t\t\tbuf, GTK_STOCK_DIALOG_QUESTION, NULL );\n\tidialog_set_callbacks( IDIALOG( idlg ), cancelcb, NULL, NULL, client );\n\tidialog_add_ok( IDIALOG( idlg ), okcb, \"%s\", yes_label );\n\tidialog_set_notify( IDIALOG( idlg ), nfn, sys );\n\tiwindow_set_parent( IWINDOW( idlg ), box_pick_parent( par ) );\n\tiwindow_build( IWINDOW( idlg ) );\n\n\tgtk_widget_show( GTK_WIDGET( idlg ) );\n\n\treturn( IDIALOG( idlg ) );\n}\n\n/* Pop up a `save'/`don't save'/`cancel' dialog.\n */\nvoid\nbox_savenosave( GtkWidget *par, \n\tiWindowFn save, iWindowFn nosave, void *client,   /* Call client */\n\tiWindowNotifyFn nfn, void *sys,\t\t\t  /* Call parent */\n\tconst char *top, const char *sub, ... )\n{\n\tva_list ap;\n\tchar buf[MAX_DIALOG_TEXT];\n\tGtkWidget *idlg;\n\n\tva_start( ap, sub );\n\tbox_vmarkup( buf, top, sub, ap );\n\tva_end( ap );\n\n\tidlg = idialog_new();\n\tidialog_set_build( IDIALOG( idlg ), \n\t\t(iWindowBuildFn) box_build, \n\t\t\tbuf, GTK_STOCK_DIALOG_QUESTION, NULL );\n\tidialog_set_callbacks( IDIALOG( idlg ), \n\t\tiwindow_true_cb, NULL, NULL, client );\n\tidialog_add_ok( IDIALOG( idlg ), nosave, _( \"Close _without Saving\" ) );\n\tidialog_add_ok( IDIALOG( idlg ), save, GTK_STOCK_SAVE );\n\tidialog_set_notify( IDIALOG( idlg ), nfn, sys );\n\tiwindow_set_parent( IWINDOW( idlg ), box_pick_parent( par ) );\n\tiwindow_build( IWINDOW( idlg ) );\n\n\tgtk_widget_show( GTK_WIDGET( idlg ) );\n}\n\n#define ABOUT(A) ((About *) (A))\n\n/* Make the insides of an about box.\n */\nstatic void\nabout_build( iDialog *idlg, GtkWidget *work )\n{\t\n\t/* Translators: translate this to a credit for you, and it'll appear in\n\t * the About box.\n\t */\n\tchar *translator_credits = _( \"translator_credits\" );\n\n\tGtkWidget *hb;\n\tGtkWidget *lab;\n\tchar txt[MAX_DIALOG_TEXT];\n\tchar txt2[MAX_DIALOG_TEXT];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tGtkWidget *image;\n\n\tim_snprintf( txt2, MAX_DIALOG_TEXT, _( \"About %s.\" ), PACKAGE );\n\tvips_buf_appendf( &buf, \"<b><big>%s</big></b>\\n\\n\", txt2 );\n\tim_snprintf( txt2, MAX_DIALOG_TEXT, \n\t\t_( \"%s is an image processing package.\" ), PACKAGE );\n\tvips_buf_appendf( &buf, \"%s\\n\\n\", txt2 );\n\n\tim_snprintf( txt2, MAX_DIALOG_TEXT, \n\t\t_( \"%s comes with ABSOLUTELY NO WARRANTY. This is \"\n\t\t\"free software and you are welcome to redistribute \"\n\t\t\"it under certain conditions, see http://www.gnu.org.\" ), \n\t\tPACKAGE );\n\tvips_buf_appendf( &buf, \"%s\\n\\n\", txt2 );\n\n\tim_snprintf( txt2, MAX_DIALOG_TEXT, _( NIP_COPYRIGHT ), PACKAGE );\n\tvips_buf_appendf( &buf, \"%s\\n\\n\", txt2 );\n\n{\n\tchar buf1[FILENAME_MAX];\n\tchar buf2[FILENAME_MAX];\n\n\tim_snprintf( buf1, FILENAME_MAX, \"%s\" G_DIR_SEPARATOR_S \"start\",\n\t\tget_savedir() );\n\texpand_variables( buf1, buf2 );\n        nativeize_path( buf2 );\n\tescape_markup( buf2, buf1, FILENAME_MAX );\n\tvips_buf_appendf( &buf, \"<b>%s:</b> %s\\n\", \n\t\t_( \"Personal start folder\" ), buf1 );\n}\n\n\tvips_buf_appendf( &buf, \"<b>%s:</b> %s\\n\", \n\t\t_( \"Homepage\" ), VIPS_HOMEPAGE );\n\tescape_markup( im_version_string(), txt2, MAX_DIALOG_TEXT );\n\tvips_buf_appendf( &buf, \"<b>%s:</b> %s\\n\", \n\t\t_( \"Linked to VIPS\" ), txt2 );\n\tescape_markup( IM_VERSION_STRING, txt2, MAX_DIALOG_TEXT );\n\tvips_buf_appendf( &buf, \"<b>%s:</b> %s\\n\", \n\t\t_( \"Built against VIPS\" ), txt2 );\n\tescape_markup( PACKAGE, txt2, MAX_DIALOG_TEXT );\n\tvips_buf_appendf( &buf, \"<b>$PACKAGE:</b> %s\\n\", txt2 );\n\tescape_markup( VERSION, txt2, MAX_DIALOG_TEXT );\n\tvips_buf_appendf( &buf, \"<b>$VERSION:</b> %s\\n\", txt2 );\n\tescape_markup( NN( g_getenv( \"VIPSHOME\" ) ), txt2, MAX_DIALOG_TEXT );\n\tvips_buf_appendf( &buf, \"<b>$VIPSHOME:</b> %s\\n\", txt2 );\n\tescape_markup( NN( g_getenv( \"HOME\" ) ), txt2, MAX_DIALOG_TEXT );\n\tvips_buf_appendf( &buf, \"<b>$HOME:</b> %s\\n\", txt2 );\n\tescape_markup( NN( g_getenv( \"SAVEDIR\" ) ), txt2, MAX_DIALOG_TEXT );\n\tvips_buf_appendf( &buf, \"<b>$SAVEDIR:</b> %s\\n\", txt2 );\n\tescape_markup( PATH_TMP, txt2, MAX_DIALOG_TEXT );\n\tvips_buf_appendf( &buf, \"<b>%s:</b> %s\\n\", \n\t\t_( \"Temp files in\" ), txt2 );\n\tif( strcmp( translator_credits, \"translator_credits\" ) != 0 ) {\n\t\tvips_buf_appendf( &buf, \"\\n\" ); \n\t\tvips_buf_appends( &buf, translator_credits );\n\t}\n\n\tvips_buf_appendf( &buf, \"\\n\" ); \n\n\tmainw_find_disc( &buf );\n\t/* Expands to (eg.) \"14GB free in /pics/tmp\" */\n        vips_buf_appendf( &buf, _( \" in \\\"%s\\\"\" ), PATH_TMP );\n        vips_buf_appends( &buf, \"\\n\" );\n\n        vips_buf_appendf( &buf, \n\t\t_( \"%d cells in heap, %d cells free, %d cells maximum\" ),\n                reduce_context->heap->ncells, \n\t\treduce_context->heap->nfree, \n\t\treduce_context->heap->max_fn( reduce_context->heap ) );\n        vips_buf_appends( &buf, \"\\n\" );\n\n        vips_buf_appendf( &buf, _( \"%d vips calls cached by nip2\" ), \n\t\tcache_history_size );\n        vips_buf_appends( &buf, \"\\n\" );\n\n        vips_buf_appendf( &buf, _( \"%d vips operations cached by libvips\" ), \n\t\tvips_cache_get_size() );\n        vips_buf_appends( &buf, \"\\n\" );\n\n        vips_buf_appendf( &buf, _( \"using %d threads\" ), im_concurrency_get() );\n        vips_buf_appends( &buf, \"\\n\" );\n\n        vips_buf_appendf( &buf, _( \"%d pixel buffers in vips\" ), \n\t\tvips_tracked_get_allocs() );\n        vips_buf_appends( &buf, \"\\n\" );\n\n\tvips_buf_append_size( &buf, vips_tracked_get_mem() );\n        vips_buf_appendf( &buf, _( \" of ram in pixel buffers\" ) ); \n        vips_buf_appends( &buf, \"\\n\" );\n\n\tvips_buf_append_size( &buf, vips_tracked_get_mem_highwater() );\n        vips_buf_appendf( &buf, _( \" of ram highwater mark\" ) ); \n        vips_buf_appends( &buf, \"\\n\" );\n\n\thb = gtk_hbox_new( FALSE, 0 );\n\tgtk_container_border_width( GTK_CONTAINER( hb ), 10 );\n\tgtk_container_add( GTK_CONTAINER( work ), hb );\n\tgtk_widget_show( hb );\n\n\timage = image_new_from_file( \n\t\t\"$VIPSHOME/share/$PACKAGE/data/vips-128.png\" );\n        gtk_box_pack_start( GTK_BOX( hb ), image, FALSE, FALSE, 2 );\n\tgtk_widget_show( image );\n\n\tlab = gtk_label_new( \"\" );\n\tgtk_label_set_markup( GTK_LABEL( lab ), vips_buf_all( &buf ) );\n        gtk_label_set_justify( GTK_LABEL( lab ), GTK_JUSTIFY_LEFT );\n        gtk_label_set_selectable( GTK_LABEL( lab ), TRUE );\n\tgtk_label_set_line_wrap( GTK_LABEL( lab ), TRUE );\n        gtk_box_pack_start( GTK_BOX( hb ), lab, FALSE, FALSE, 2 );\n\tgtk_widget_show( lab );\n}\n\n/* Pop up an \"about\" window.\n */\nvoid\nbox_about( GtkWidget *par )\n{\n\tGtkWidget *idlg;\n\n\tidlg = idialog_new();\n\tidialog_set_build( IDIALOG( idlg ), \n\t\t(iWindowBuildFn) about_build, NULL, NULL, NULL );\n\tidialog_add_ok( IDIALOG( idlg ), iwindow_true_cb, GTK_STOCK_OK );\n\tiwindow_set_parent( IWINDOW( idlg ), box_pick_parent( par ) );\n\tiwindow_build( IWINDOW( idlg ) );\n\n\tgtk_widget_show( GTK_WIDGET( idlg ) );\n}\n\n/* A big list of all the help tags, plus the file and anchor they are defined\n * in. See makehelpindex.pl.\n */\nstatic const char *box_helpindex[][2] = {\n#include \"helpindex.h\"\n};\n\n/* Pop up a help window for a tag.\n */\nvoid\nbox_help( GtkWidget *par, const char *name )\n{\n\tint i;\n\n\tfor( i = 0; i < IM_NUMBER( box_helpindex ); i++ )\n\t\tif( strcmp( name, box_helpindex[i][0] ) == 0 ) {\n\t\t\tchar url[512];\n\n\t\t\tim_snprintf( url, 512, \"file://%s/%s\", \n\t\t\t\tNIP_DOCPATH, box_helpindex[i][1] );\n\t\t\tbox_url( par, url );\n\t\t\treturn;\n\t\t}\n\n\terror_top( _( \"Help page not found.\" ) );\n\terror_sub( _( \"No indexed help page found for tag \\\"%s\\\"\" ), name );\n\tiwindow_alert( par, GTK_MESSAGE_ERROR );\n}\n\n/* Name + caption dialog ... for new workspace / new column.\n */\n\nstatic iDialogClass *stringset_parent_class = NULL;\n\nvoid *\nstringset_child_destroy( StringsetChild *ssc )\n{\n\tssc->ss->children = g_slist_remove( ssc->ss->children, ssc );\n\n\tIM_FREE( ssc->label );\n\tIM_FREE( ssc->text );\n\tIM_FREE( ssc->tooltip );\n\tIM_FREE( ssc );\n\n\treturn( NULL );\n}\n\nStringsetChild *\nstringset_child_new( Stringset *ss,\n\tconst char *label, const char *text, const char *tooltip )\n{\n\tStringsetChild *ssc = INEW( NULL, StringsetChild );\n\n\tssc->ss = ss;\n\tssc->label = im_strdup( NULL, label );\n\tssc->text = im_strdup( NULL, text );\n\tssc->tooltip = im_strdup( NULL, tooltip );\n\n\tss->children = g_slist_append( ss->children, ssc );\n\n\treturn( ssc );\n}\n\nstatic void\nstringset_destroy( GtkObject *object )\n{\n\tStringset *ss;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_STRINGSET( object ) );\n\n\tss = STRINGSET( object );\n\n\tslist_map( ss->children,\n\t\t(SListMapFn) stringset_child_destroy, NULL );\n\tUNREF( ss->group );\n\n\tif( GTK_OBJECT_CLASS( stringset_parent_class )->destroy )\n\t\tGTK_OBJECT_CLASS( stringset_parent_class )->destroy( object );\n}\n\nstatic void *\nstringset_build_set_default( StringsetChild *ssc, iDialog *idlg )\n{\n\tidialog_set_default_entry( idlg, GTK_ENTRY( ssc->entry ) );\n\n\treturn( NULL );\n}\n\nstatic void\nstringset_build( GtkWidget *widget )\n{\n\tStringset *ss = STRINGSET( widget );\n\tiDialog *idlg = IDIALOG( widget );\n\tGSList *p;\n\n#ifdef DEBUG\n\tprintf( \"stringset_build: %s\\n\", IWINDOW( ss )->title );\n#endif /*DEBUG*/\n\n\t/* Call all builds in superclasses.\n\t */\n\tif( IWINDOW_CLASS( stringset_parent_class )->build )\n\t\tIWINDOW_CLASS( stringset_parent_class )->build( widget );\n\n\tss->group = gtk_size_group_new( GTK_SIZE_GROUP_HORIZONTAL );\n\n\tfor( p = ss->children; p; p = p->next ) {\n\t\tStringsetChild *ssc = (StringsetChild *) p->data;\n\n\t\tssc->entry = \n\t\t\tbuild_glabeltext4( idlg->work, ss->group, ssc->label );\n\t\tif( ssc->text )\n\t\t\tset_gentry( ssc->entry, \"%s\", ssc->text );\n\t\tif( ssc->tooltip )\n\t\t\tset_tooltip( ssc->entry, \"%s\", ssc->tooltip );\n\t}\n\n\t/* Set defaults in reverse, so we get top item with focus.\n\t */\n\t(void) slist_map_rev( ss->children,\n\t\t(SListMapFn) stringset_build_set_default, idlg );\n\n\tgtk_widget_show_all( idlg->work );\n}\n\nstatic void\nstringset_class_init( StringsetClass *class )\n{\n\tGtkObjectClass *object_class;\n\tiWindowClass *iwindow_class;\n\n\tobject_class = (GtkObjectClass *) class;\n\tiwindow_class = (iWindowClass *) class;\n\n\tobject_class->destroy = stringset_destroy;\n\tiwindow_class->build = stringset_build;\n\n\tstringset_parent_class = g_type_class_peek_parent( class );\n}\n\nstatic void\nstringset_init( Stringset *ss )\n{\n#ifdef DEBUG\n\tprintf( \"stringset_init: %s\\n\", IWINDOW( ss )->title );\n#endif /*DEBUG*/\n\n\tss->children = NULL;\n}\n\nGtkType\nstringset_get_type( void )\n{\n\tstatic GtkType stringset_type = 0;\n\n\tif( !stringset_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Stringset\",\n\t\t\tsizeof( Stringset ),\n\t\t\tsizeof( StringsetClass ),\n\t\t\t(GtkClassInitFunc) stringset_class_init,\n\t\t\t(GtkObjectInitFunc) stringset_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tstringset_type = gtk_type_unique( TYPE_IDIALOG, &info );\n\t}\n\n\treturn( stringset_type );\n}\n\nGtkWidget *\nstringset_new( void )\n{\n\tStringset *ss = gtk_type_new( TYPE_STRINGSET );\n\n\treturn( GTK_WIDGET( ss ) );\n}\n\nStringsetChild *\nstringset_child_get( Stringset *ss, const char *label )\n{\n\tGSList *p;\n\n\tfor( p = ss->children; p; p = p->next ) {\n\t\tStringsetChild *ssc = (StringsetChild *) p->data;\n\n\t\tif( strcmp( label, ssc->label ) == 0 )\n\t\t\treturn( ssc );\n\t}\n\n\treturn( NULL );\n}\n\n/* Find dialog.\n */\n\nstatic iDialogClass *find_parent_class = NULL;\n\nstatic void\nfind_build( GtkWidget *widget )\n{\n\tFind *find = FIND( widget );\n\tiDialog *idlg = IDIALOG( widget );\n\n#ifdef DEBUG\n\tprintf( \"find_build: %s\\n\", IWINDOW( find )->title );\n#endif /*DEBUG*/\n\n\t/* Call all builds in superclasses.\n\t */\n\tif( IWINDOW_CLASS( find_parent_class )->build )\n\t\t(*IWINDOW_CLASS( find_parent_class )->build)( widget );\n\n\tfind->search = build_glabeltext4( idlg->work, NULL, _( \"Search for\" ) );\n\tfind->csens = build_gtoggle( idlg->work, _( \"Case sensitive\" ) );\n#ifdef HAVE_GREGEX\n\tfind->regexp = build_gtoggle( idlg->work, _( \"Regular expression\" ) );\n#endif /*HAVE_GREGEX*/\n\tfind->fromtop = build_gtoggle( idlg->work, _( \"Search from start\" ) );\n\tidialog_set_default_entry( idlg, GTK_ENTRY( find->search ) );\n\tgtk_widget_show_all( idlg->work );\n}\n\nstatic void\nfind_class_init( FindClass *class )\n{\n\tiWindowClass *iwindow_class = (iWindowClass *) class;\n\n\tiwindow_class->build = find_build;\n\n\tfind_parent_class = g_type_class_peek_parent( class );\n}\n\nstatic void\nfind_init( Find *find )\n{\n#ifdef DEBUG\n\tprintf( \"find_init: %s\\n\", IWINDOW( find )->title );\n#endif /*DEBUG*/\n\n\tidialog_set_pinup( IDIALOG( find ), TRUE );\n}\n\nGtkType\nfind_get_type( void )\n{\n\tstatic GtkType find_type = 0;\n\n\tif( !find_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Find\",\n\t\t\tsizeof( Find ),\n\t\t\tsizeof( FindClass ),\n\t\t\t(GtkClassInitFunc) find_class_init,\n\t\t\t(GtkObjectInitFunc) find_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tfind_type = gtk_type_unique( TYPE_IDIALOG, &info );\n\t}\n\n\treturn( find_type );\n}\n\nGtkWidget *\nfind_new( void )\n{\n\tFind *find = gtk_type_new( TYPE_FIND );\n\n\treturn( GTK_WIDGET( find ) );\n}\n\n/* Launch a viewer on a URL.\n */\nvoid\nbox_url( GtkWidget *par, const char *url )\n{\n#ifdef OS_WIN32\n\tchar url2[FILENAME_MAX];\n\tint v;\n\t\n\texpand_variables( url, url2 );\n\tv = (int) ShellExecute( NULL, \"open\", url2, NULL, NULL, SW_SHOWNORMAL );\n\tif( v <= 32 ) {\n\t\terror_top( _( \"Unable to view help file.\" ) );\n\t\terror_sub( _( \"Unable to open URL \\\"%s\\\", \"\n\t\t\t\"windows error code = %d.\" ), url, v );\n\t\tiwindow_alert( par, GTK_MESSAGE_ERROR );\n\t}\n#elif defined OS_DARWIN\n\t(void) systemf( \"open %s\", url );\n#elif defined HAVE_XDG_OPEN\n\tstatic gboolean shown = FALSE;\n\n\tif( systemf( \"%s %s\", XDG_OPEN, url ) ) {\n\t\terror_top( _( \"Unable to view help file.\" ) );\n\t\terror_sub( _( \"Attempt to view URL with xdg-open failed\\n%s\" ),\n\t\t\turl );\n\t\tiwindow_alert( par, GTK_MESSAGE_ERROR );\n\t}\n\telse if( !shown ) {\n\t\terror_top( _( \"Browser window opened.\" ) );\n\t\terror_sub( \"%s\", \n\t\t\t_( \"You may need to switch desktops to see the \"\n\t\t\t\"new window.\" ) );\n\t\tiwindow_alert( par, GTK_MESSAGE_INFO );\n\t\tshown = TRUE;\n\t}\n#else /*default unix-y*/\n\tstatic gboolean shown = FALSE;\n\n\tchar txt[512];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tchar txt2[512];\n\tVipsBuf buf2 = VIPS_BUF_STATIC( txt2 );\n\n\tchar url2[FILENAME_MAX];\n\n\texpand_variables( url, url2 );\n\n\tvips_buf_appendf( &buf, \"%s %s\", BOX_BROWSER, BOX_BROWSER_REMOTE );\n\tvips_buf_appendf( &buf2, vips_buf_all( &buf ), url2 );\n\n\tif( systemf( \"%s\", vips_buf_all( &buf2 ) ) ) {\n\t\terror_top( _( \"Unable to view help file.\" ) );\n\t\terror_sub( _( \n\t\t\t\"Attempted to launch browser with command:\\n\"\n\t\t\t\"  %s\\n\"\n\t\t\t\"You can change this command in Preferences.\" ),\n\t\t\tvips_buf_all( &buf2 ) );\n\t\tiwindow_alert( par, GTK_MESSAGE_ERROR );\n\t}\n\telse if( !shown ) {\n\t\terror_top( _( \"Browser window opened.\" ) );\n\t\terror_sub( \"%s\",\n\t\t\t_( \"You may need to switch desktops to see the \"\n\t\t\t\"new window.\" ) );\n\t\tiwindow_alert( par, GTK_MESSAGE_INFO );\n\t\tshown = TRUE;\n\t}\n#endif /*lots*/\n}\n\n/* Fontchooser dialog.\n */\n\nstatic iDialogClass *fontchooser_parent_class = NULL;\n\nstatic void\nfontchooser_build( GtkWidget *widget )\n{\n\tFontchooser *fontchooser = FONTCHOOSER( widget );\n\tiDialog *idlg = IDIALOG( widget );\n\n#ifdef DEBUG\n\tprintf( \"fontchooser_build: %s\\n\", IWINDOW( fontchooser )->title );\n#endif /*DEBUG*/\n\n\t/* Call all builds in superclasses.\n\t */\n\tif( IWINDOW_CLASS( fontchooser_parent_class )->build )\n\t\t(*IWINDOW_CLASS( fontchooser_parent_class )->build)( widget );\n\n\tfontchooser->fontchooser = gtk_font_selection_new();\n        gtk_box_pack_start( GTK_BOX( idlg->work ), \n\t\tfontchooser->fontchooser, TRUE, TRUE, 2 );\n\n\tiwindow_set_title( IWINDOW( idlg ), _( \"Select Font\" ) );\n\n\tgtk_widget_show_all( idlg->work );\n}\n\nstatic void\nfontchooser_class_init( FontchooserClass *class )\n{\n\tiWindowClass *iwindow_class;\n\n\tfontchooser_parent_class = g_type_class_peek_parent( class );\n\n\tiwindow_class = (iWindowClass *) class;\n\n\tiwindow_class->build = fontchooser_build;\n}\n\nstatic void\nfontchooser_init( Fontchooser *fontchooser )\n{\n}\n\nGtkType\nfontchooser_get_type( void )\n{\n\tstatic GtkType fontchooser_type = 0;\n\n\tif( !fontchooser_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Fontchooser\",\n\t\t\tsizeof( Fontchooser ),\n\t\t\tsizeof( FontchooserClass ),\n\t\t\t(GtkClassInitFunc) fontchooser_class_init,\n\t\t\t(GtkObjectInitFunc) fontchooser_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tfontchooser_type = gtk_type_unique( TYPE_IDIALOG, &info );\n\t}\n\n\treturn( fontchooser_type );\n}\n\nFontchooser *\nfontchooser_new( void )\n{\n\tFontchooser *fontchooser = gtk_type_new( TYPE_FONTCHOOSER );\n\n\treturn( fontchooser );\n}\n\ngboolean \nfontchooser_set_font_name( Fontchooser *fontchooser, const char *font_name )\n{\n\tif( !gtk_font_selection_set_font_name( \n\t\tGTK_FONT_SELECTION( fontchooser->fontchooser ), font_name ) ) {\n\t\terror_top( _( \"Font not found.\" ) );\n\t\terror_sub( _( \"Font \\\"%s\\\" not found on system.\" ),\n\t\t\tfont_name );\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nchar *\nfontchooser_get_font_name( Fontchooser *fontchooser )\n{\n\treturn( gtk_font_selection_get_font_name( \n\t\tGTK_FONT_SELECTION( fontchooser->fontchooser ) ) );\n}\n\n/* Fontbutton.\n */\n\n/* Our signals. \n */\nenum {\n\tSIG_CHANGED,\t/* New font selected */\n\tSIG_LAST\n};\n\nstatic GtkButtonClass *fontbutton_parent_class = NULL;\n\nstatic guint fontbutton_signals[SIG_LAST] = { 0 };\n\nstatic void\nfontbutton_finalize( GObject *gobject )\n{\n\tFontbutton *fontbutton;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_FONTBUTTON( gobject ) );\n\n\tfontbutton = FONTBUTTON( gobject );\n\n\tIM_FREE( fontbutton->font_name );\n\n\tG_OBJECT_CLASS( fontbutton_parent_class )->finalize( gobject );\n}\n\nstatic void\nfontbutton_ok_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tFontchooser *fontchooser = FONTCHOOSER( iwnd );\n\tFontbutton *fontbutton = FONTBUTTON( client );\n\tchar *font_name;\n\n\tfont_name = fontchooser_get_font_name( fontchooser ); \n\tfontbutton_set_font_name( fontbutton, font_name );\n\tg_free( font_name );\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void \nfontbutton_popdown_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys ) \n{\n\tFontbutton *fontbutton = FONTBUTTON( client );\n\n\tfontbutton->fontchooser = NULL;\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nfontbutton_clicked( GtkButton *button )\n{\n\tFontbutton *fontbutton = FONTBUTTON( button );\n\n\tif( fontbutton->fontchooser ) \n\t\tgtk_window_present( GTK_WINDOW( fontbutton->fontchooser ) );\n\telse {\n\t\tfontbutton->fontchooser = fontchooser_new();\n\t\tiwindow_set_title( IWINDOW( fontbutton->fontchooser ), \n\t\t\t_( \"Pick a font\" ) );\n\t\tidialog_set_callbacks( IDIALOG( fontbutton->fontchooser ), \n\t\t\tiwindow_true_cb, fontbutton_popdown_cb, NULL,\n\t\t\tfontbutton );\n\t\tidialog_add_ok( IDIALOG( fontbutton->fontchooser ), \n\t\t\tfontbutton_ok_cb, _( \"Set Font\" ) );\n\t\tiwindow_set_parent( IWINDOW( fontbutton->fontchooser ), \n\t\t\tGTK_WIDGET( button ) );\n\t\tidialog_set_pinup( IDIALOG( fontbutton->fontchooser ), TRUE );\n\t\tiwindow_build( IWINDOW( fontbutton->fontchooser ) );\n\t\tfontchooser_set_font_name( fontbutton->fontchooser, \n\t\t\tfontbutton->font_name ); \n\n\t\tgtk_widget_show( GTK_WIDGET( fontbutton->fontchooser ) );\n\t}\n}\n\nstatic void\nfontbutton_real_changed( Fontbutton *fontbutton )\n{\n}\n\nstatic void\nfontbutton_class_init( FontbuttonClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tGtkButtonClass *bobject_class = (GtkButtonClass *) class;\n\n\tfontbutton_parent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = fontbutton_finalize;\n\n\tbobject_class->clicked = fontbutton_clicked;\n\n\tclass->changed = fontbutton_real_changed;\n\n\tfontbutton_signals[SIG_CHANGED] = g_signal_new( \"changed\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( FontbuttonClass, changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n}\n\nstatic void\nfontbutton_init( Fontbutton *fontbutton )\n{\n\tfontbutton->font_name = NULL;\n\tfontbutton->fontchooser = NULL;\n\n\tset_tooltip( GTK_WIDGET( fontbutton ), _( \"Click to select font\" ) );\n}\n\nGtkType\nfontbutton_get_type( void )\n{\n\tstatic GtkType fontbutton_type = 0;\n\n\tif( !fontbutton_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Fontbutton\",\n\t\t\tsizeof( Fontbutton ),\n\t\t\tsizeof( FontbuttonClass ),\n\t\t\t(GtkClassInitFunc) fontbutton_class_init,\n\t\t\t(GtkObjectInitFunc) fontbutton_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tfontbutton_type = gtk_type_unique( GTK_TYPE_BUTTON, &info );\n\t}\n\n\treturn( fontbutton_type );\n}\n\nFontbutton *\nfontbutton_new( void )\n{\n\tFontbutton *fontbutton = g_object_new( TYPE_FONTBUTTON, \n\t\t\"label\", \"Sans 12\", NULL );\n\n\treturn( fontbutton );\n}\n\nvoid\nfontbutton_set_font_name( Fontbutton *fontbutton, const char *font_name )\n{\n\tchar font[256];\n\tchar button_text[256];\n\tint i;\n\n\tif( !fontbutton->font_name ||\n\t\tstrcmp( fontbutton->font_name, font_name ) != 0 ) {\n\t\tIM_SETSTR( fontbutton->font_name, font_name );\n\n\t\tim_strncpy( font, font_name, 256 );\n\t\tfor( i = strlen( font ) - 1; i > 0 && isdigit( font[i] ); i-- )\n\t\t\tfont[i] = '\\0';\n\t\tim_snprintf( button_text, 256, \n\t\t\t\"<span font_desc=\\\"%s\\\" size=\\\"medium\\\">%s</span>\",\n\t\t\tfont, font_name );\n\t\tgtk_label_set_markup( \n\t\t\tGTK_LABEL( gtk_bin_get_child( GTK_BIN( fontbutton ) ) ),\n\t\t\tbutton_text );\n\n\t\tif( fontbutton->fontchooser )\n\t\t\tfontchooser_set_font_name( fontbutton->fontchooser,\n\t\t\t\tfont_name );\n\n\t\tg_signal_emit( G_OBJECT( fontbutton ), \n\t\t\tfontbutton_signals[SIG_CHANGED], 0 );\n\t}\n}\n\nconst char *\nfontbutton_get_font_name( Fontbutton *fontbutton )\n{\n\treturn( fontbutton->font_name );\n}\n\n/* Infobar. Optional: it's only in quite recent gtk.\n */\n#ifdef USE_INFOBAR\n\nstatic GtkInfoBarClass *infobar_parent_class = NULL;\n\nstatic void\ninfobar_destroy( GtkObject *object )\n{\n\tInfobar *infobar;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_INFOBAR( object ) );\n\n\tinfobar = INFOBAR( object );\n\n\tIM_FREEF( g_source_remove, infobar->close_timeout );\n\tIM_FREEF( g_source_remove, infobar->close_animation_timeout );\n\n\tGTK_OBJECT_CLASS( infobar_parent_class )->destroy( object );\n}\n\nstatic void\ninfobar_class_init( InfobarClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\n\tinfobar_parent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = infobar_destroy;\n}\n\nstatic void\ninfobar_init( Infobar *infobar )\n{\n\tinfobar->top = NULL;\n\tinfobar->sub = NULL;\n\tinfobar->close_timeout = 0;\n\tinfobar->close_animation_timeout = 0;\n\tinfobar->height = 0;\n}\n\nGType\ninfobar_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( InfobarClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) infobar_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Infobar ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) infobar_init,\n\t\t};\n\n\t\ttype = g_type_register_static( GTK_TYPE_INFO_BAR, \n\t\t\t\"Infobar\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\ninfobar_cancel_close( Infobar *infobar )\n{\n\tIM_FREEF( g_source_remove, infobar->close_timeout );\n\tIM_FREEF( g_source_remove, infobar->close_animation_timeout );\n\tgtk_widget_set_size_request( GTK_WIDGET( infobar ), -1, -1 );\n}\n\nstatic void\ninfobar_hide( Infobar *infobar )\n{\n\tinfobar_cancel_close( infobar );\n\tgtk_widget_hide( GTK_WIDGET( infobar ) );\n\tgtk_widget_hide( GTK_WIDGET( infobar->sub ) );\n\tgtk_widget_set_sensitive( GTK_WIDGET( infobar->info ), TRUE );\n}\n\nstatic gboolean\ninfobar_close_animation_timeout( Infobar *infobar )\n{\n\tinfobar->height -= 20;\n\tif( infobar->height <= 0 ) {\n\t\tinfobar_hide( infobar );\n\t\treturn( FALSE );\n\t}\n\tgtk_widget_set_size_request( GTK_WIDGET( infobar ), \n\t\t-1, infobar->height );\n\n\treturn( TRUE );\n}\n\nstatic void\ninfobar_start_close( Infobar *infobar )\n{\n\tinfobar_cancel_close( infobar );\n\n\tinfobar->height = GTK_WIDGET( infobar )->allocation.height;\n\tinfobar->close_animation_timeout = g_timeout_add( 50, \n\t\t(GSourceFunc) infobar_close_animation_timeout, infobar );\n}\n\nstatic gboolean\ninfobar_close_timeout( Infobar *infobar )\n{\n\tinfobar_start_close( infobar );\n\n\treturn( FALSE );\n}\n\nstatic void\ninfobar_show( Infobar *infobar )\n{\n\tinfobar_cancel_close( infobar );\n\n\tinfobar->close_timeout = g_timeout_add( 5000, \n\t\t(GSourceFunc) infobar_close_timeout, infobar );\n\n\tgtk_widget_show( GTK_WIDGET( infobar ) );\n}\n\nstatic void                \ninfobar_info_cb( GtkWidget *button, Infobar *infobar )\n{\n\tinfobar_cancel_close( infobar );\n\tgtk_widget_show( GTK_WIDGET( infobar->sub ) );\n\tgtk_widget_set_sensitive( GTK_WIDGET( infobar->info ), FALSE );\n}\n\nstatic void                \ninfobar_close_cb( GtkWidget *button, Infobar *infobar )\n{\n\tinfobar_start_close( infobar );\n}\n\nInfobar *\ninfobar_new( void )\n{\n\tInfobar *infobar;\n\tGtkWidget *vbox;\n\tGtkWidget *content_area;\n\tGtkWidget *hbox;\n\tGtkWidget *action_area;\n\tGtkWidget *button;\n\n\tinfobar = g_object_new( TYPE_INFOBAR, NULL );\n\n\tvbox = gtk_vbox_new( FALSE, 10 );\n\tcontent_area = gtk_info_bar_get_content_area( GTK_INFO_BAR( infobar ) );\n\tgtk_container_add( GTK_CONTAINER( content_area ), vbox );\n\tgtk_widget_show( vbox );\n\n\tinfobar->top = gtk_label_new( \"\" );\n        gtk_label_set_justify( GTK_LABEL( infobar->top ), GTK_JUSTIFY_LEFT );\n        gtk_label_set_selectable( GTK_LABEL( infobar->top ), TRUE );\n\tgtk_label_set_line_wrap( GTK_LABEL( infobar->top ), TRUE );\n\tgtk_container_add( GTK_CONTAINER( vbox ), infobar->top );\n\tgtk_widget_show( infobar->top );\n\n\tinfobar->sub = gtk_label_new( \"\" );\n        gtk_label_set_justify( GTK_LABEL( infobar->sub ), GTK_JUSTIFY_LEFT );\n        gtk_label_set_selectable( GTK_LABEL( infobar->sub ), TRUE );\n\tgtk_label_set_line_wrap( GTK_LABEL( infobar->sub ), TRUE );\n\tgtk_container_add( GTK_CONTAINER( vbox ), infobar->sub );\n\n\t/* We can't use gtk_info_bar_add_button(), we need the buttons\n\t * horizontally.\n\t */\n\n\thbox = gtk_hbox_new( FALSE, 2 );\n\taction_area = gtk_info_bar_get_action_area( GTK_INFO_BAR( infobar ) );\n\tgtk_container_add( GTK_CONTAINER( action_area ), hbox );\n\tgtk_widget_show( hbox );\n\n\tbutton = gtk_button_new_from_stock( GTK_STOCK_CLOSE );\n        gtk_box_pack_end( GTK_BOX( hbox ), button, TRUE, TRUE, 2 );\n\tg_signal_connect( button, \"clicked\",\n\t\tG_CALLBACK( infobar_close_cb ), infobar );\n\tgtk_widget_show( button );\n\n\tinfobar->info = gtk_button_new_from_stock( GTK_STOCK_INFO );\n        gtk_box_pack_end( GTK_BOX( hbox ), infobar->info, TRUE, TRUE, 2 );\n\tg_signal_connect( infobar->info, \"clicked\",\n\t\tG_CALLBACK( infobar_info_cb ), infobar );\n\tgtk_widget_show( infobar->info );\n\n\treturn( infobar );\n}\n\n#else /*!USE_INFOBAR*/\n\nInfobar *\ninfobar_new( void )\n{\n\treturn( NULL );\n}\n\n#endif /*USE_INFOBAR*/\n\n/* Set the label on an infobar to some marked-up text.\n */\nvoid\ninfobar_vset( Infobar *infobar, GtkMessageType type, \n\tconst char *top, const char *sub, va_list ap )\n{\n#ifdef USE_INFOBAR\n\tchar buf1[MAX_DIALOG_TEXT];\n\tchar buf2[MAX_DIALOG_TEXT];\n\tchar *p;\n\n\tescape_markup( top, buf1, MAX_DIALOG_TEXT );\n\tim_snprintf( buf2, MAX_DIALOG_TEXT, \"<b>%s</b>\", buf1 );\n\tgtk_label_set_markup( GTK_LABEL( infobar->top ), buf2 );\n\n\t(void) im_vsnprintf( buf1, MAX_DIALOG_TEXT, sub, ap );\n\tescape_markup( buf1, buf2, MAX_DIALOG_TEXT );\n\n\t/* Remove any trailing newlines, they make infobars rather large.\n\t */\n\twhile( (p = buf2 + strlen( buf2 )) > buf2 && p[-1] == '\\n' )\n\t\tp[-1] = '\\0';\n\n\tgtk_label_set_markup( GTK_LABEL( infobar->sub ), buf2 );\n\n\tgtk_info_bar_set_message_type( GTK_INFO_BAR( infobar ), type );\n\n\tinfobar_show( infobar );\n#endif /*USE_INFOBAR*/\n}\n\n/* Set the label on an infobar to some marked-up text.\n */\nvoid\ninfobar_set( Infobar *infobar, GtkMessageType type, \n\tconst char *top, const char *sub, ... )\n{\n\tva_list ap;\n\n        va_start( ap, sub );\n\tinfobar_vset( infobar, type, top, sub, ap );\n        va_end( ap );\n}\n"
  },
  {
    "path": "src/boxes.h",
    "content": "/* decls for boxes.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\nvoid box_alert( GtkWidget *par );\nvoid box_vinfo( GtkWidget *par, const char *top, const char *sub, va_list ap );\nvoid box_info( GtkWidget *par, const char *top, const char *sub, ... )\n\t__attribute__((format(printf, 3, 4)));\niDialog *box_yesno( GtkWidget *par, \n\tiWindowFn okcb, iWindowFn cancelcb, void *client, /* Call client */\n\tiWindowNotifyFn nfn, void *sys,\t\t\t  /* Call parent */\n\tconst char *yes_label, \n\tconst char *top, const char *sub, ... )\n\t__attribute__((format(printf, 9, 10)));\nvoid box_savenosave( GtkWidget *par, \n\tiWindowFn save, iWindowFn nosave, void *client,   /* Call client */\n\tiWindowNotifyFn nfn, void *sys,\t\t\t  /* Call parent */\n\tconst char *top, const char *sub, ... )\n\t__attribute__((format(printf, 8, 9)));\nvoid box_about( GtkWidget *par );\nvoid box_help( GtkWidget *par, const char *name );\n\n/* A dialog showing a bunch of editable strings ... eg. name and caption for\n * new toolkit etc. etc.\n */\n#define TYPE_STRINGSET (stringset_get_type())\n#define STRINGSET( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_STRINGSET, Stringset ))\n#define STRINGSET_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_STRINGSET, StringsetClass ))\n#define IS_STRINGSET( obj ) (GTK_CHECK_TYPE( (obj), TYPE_STRINGSET ))\n#define IS_STRINGSET_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_STRINGSET ))\n\n/* A Stringset is a bunch of these.\n */\ntypedef struct {\n\tstruct _Stringset *ss;\n\n\tGtkWidget *entry;\t\n\tchar *label;\t\n\tchar *text;\t/* Current text value */\n\tchar *tooltip;\n} StringsetChild;\n\ntypedef struct _Stringset {\n\tiDialog parent;\n\n\tGSList *children;\n\tGtkSizeGroup *group;\t/* Align labels with this */     \n} Stringset;\n\ntypedef struct _StringsetClass {\n\tiDialogClass parent_class;\n\n\t/* My methods.\n\t */\n} StringsetClass;\n\nvoid *stringset_child_destroy( StringsetChild *ssc );\nStringsetChild *stringset_child_new( Stringset *ss,\n\tconst char *label, const char *text, const char *tooltip );\nGtkType stringset_get_type( void );\nGtkWidget *stringset_new( void );\nStringsetChild *stringset_child_get( Stringset *, const char *label );\n\n/* Find dialog.\n */\n#define TYPE_FIND (find_get_type())\n#define FIND( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_FIND, Find ))\n#define FIND_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_FIND, FindClass ))\n#define IS_FIND( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FIND ))\n#define IS_FIND_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_FIND ))\n\ntypedef struct _Find {\n\tiDialog parent;\n\n\t/* My instance vars.\n\t */\n\tGtkWidget *search;\n#ifdef HAVE_GREGEX\n\tGtkWidget *regexp;\n#endif /*HAVE_GREGEX*/\n\tGtkWidget *csens;\n\tGtkWidget *fromtop;\n} Find;\n\ntypedef struct _FindClass {\n\tiDialogClass parent_class;\n\n\t/* My methods.\n\t */\n} FindClass;\n\nGtkType find_get_type( void );\nGtkWidget *find_new( void );\n\nvoid box_url( GtkWidget *par, const char *url );\n\n/* Font chooser window.\n */\n#define TYPE_FONTCHOOSER (fontchooser_get_type())\n#define FONTCHOOSER( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_FONTCHOOSER, Fontchooser ))\n#define FONTCHOOSER_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_FONTCHOOSER, FontchooserClass ))\n#define IS_FONTCHOOSER( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FONTCHOOSER ))\n#define IS_FONTCHOOSER_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_FONTCHOOSER ))\n\ntypedef struct _Fontchooser {\n\tiDialog parent_object;\n\n\tGtkWidget *fontchooser;\t\t/* gtk font select widget */\n} Fontchooser;\n\ntypedef struct _FontchooserClass {\n\tiDialogClass parent_class;\n\n\t/* My methods.\n\t */\n} FontchooserClass;\n\nGtkType fontchooser_get_type( void );\nFontchooser *fontchooser_new( void );\ngboolean fontchooser_set_font_name( Fontchooser *fontchooser, \n\tconst char *font_name );\nchar *fontchooser_get_font_name( Fontchooser * );\n\n/* Font button.\n */\n#define TYPE_FONTBUTTON (fontbutton_get_type())\n#define FONTBUTTON( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_FONTBUTTON, Fontbutton ))\n#define FONTBUTTON_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_FONTBUTTON, FontbuttonClass ))\n#define IS_FONTBUTTON( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FONTBUTTON ))\n#define IS_FONTBUTTON_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_FONTBUTTON ))\n\ntypedef struct _Fontbutton {\n\tGtkButton parent_object;\n\n\tchar *font_name;\t\t/* Current name */\n\n\tFontchooser *fontchooser;\t/* Pop up dialog */\n} Fontbutton;\n\ntypedef struct _FontbuttonClass {\n\tGtkButtonClass parent_class;\n\n\tvoid (*changed)( Fontbutton * );\n} FontbuttonClass;\n\nGtkType fontbutton_get_type( void );\nFontbutton *fontbutton_new( void );\nvoid fontbutton_set_font_name( Fontbutton *fontbutton, const char *font_name );\nconst char *fontbutton_get_font_name( Fontbutton * );\n\n/* Infobar subclass, with a close animation and a label.\n */\n#define TYPE_INFOBAR (infobar_get_type())\n#define INFOBAR( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_INFOBAR, Infobar ))\n#define INFOBAR_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_INFOBAR, InfobarClass ))\n#define IS_INFOBAR( obj ) (GTK_CHECK_TYPE( (obj), TYPE_INFOBAR ))\n#define IS_INFOBAR_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_INFOBAR ))\n\nstruct _Infobar {\n#ifdef USE_INFOBAR\n\tGtkInfoBar parent_object;\n#endif /*USE_INFOBAR*/\n\n\tGtkWidget *top;\n\tGtkWidget *sub;\n\tGtkWidget *info;\n\tguint close_timeout;\n\tguint close_animation_timeout;\n\tint height;\n};\n\ntypedef struct _InfobarClass {\n#ifdef USE_INFOBAR\n\tGtkInfoBarClass parent_class;\n#endif /*USE_INFOBAR*/\n\n} InfobarClass;\n\nGtkType infobar_get_type( void );\nInfobar *infobar_new( void );\nvoid infobar_vset( Infobar *infobar, GtkMessageType type, \n\tconst char *top, const char *sub, va_list ap );\nvoid infobar_set( Infobar *infobar, GtkMessageType type, \n\tconst char *top, const char *sub, ... );\n"
  },
  {
    "path": "src/builtin.c",
    "content": "/* Run builtin functions ... sin/error etc.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n#ifdef HAVE_GSL\n#include <gsl/gsl_sf_gamma.h>\n#include <gsl/gsl_errno.h>\n#endif /*HAVE_GSL*/\n\n/* Trace builtin calls.\n#define DEBUG\n */\n\n/* Spot something that might be an arg to sin/cos/tan etc.\n */\nstatic gboolean\nismatharg( Reduce *rc, PElement *base )\n{\n\treturn( PEISIMAGE( base ) || PEISREAL( base ) || PEISCOMPLEX( base ) );\n}\n\n/* Spot something that might be an arg to re/im etc.\n */\nstatic gboolean\niscomplexarg( Reduce *rc, PElement *base )\n{\n\treturn( PEISIMAGE( base ) || PEISCOMPLEX( base ) );\n}\n\n/* Spot anything.\n */\nstatic gboolean isany( Reduce *rc, PElement *base ) { return( TRUE ); }\n\n/* Other PEIS as functions.\n */\nstatic gboolean pe_is_image( Reduce *rc, PElement *base ) \n\t{ return( PEISIMAGE( base ) ); }\nstatic gboolean pe_is_real( Reduce *rc, PElement *base ) \n\t{ return( PEISREAL( base ) ); }\nstatic gboolean pe_is_complex( Reduce *rc, PElement *base ) \n\t{ return( PEISCOMPLEX( base ) ); }\nstatic gboolean pe_is_bool( Reduce *rc, PElement *base ) \n\t{ return( PEISBOOL( base ) ); }\nstatic gboolean pe_is_char( Reduce *rc, PElement *base ) \n\t{ return( PEISCHAR( base ) ); }\nstatic gboolean pe_is_list( Reduce *rc, PElement *base ) \n\t{ return( PEISLIST( base ) ); }\nstatic gboolean pe_is_flist( Reduce *rc, PElement *base ) \n\t{ return( PEISFLIST( base ) ); }\nstatic gboolean pe_is_class( Reduce *rc, PElement *base )\n        { return( PEISCLASS( base ) ); }\n\n\n/* The types we might want to spot for builtins.\n *\n * Others, eg.:\n *\nstatic BuiltinTypeSpot vimage_spot = { \"vips_image\", pe_is_image };\nstatic BuiltinTypeSpot bool_spot = { \"bool\", pe_is_bool };\nstatic BuiltinTypeSpot realvec_spot = { \"[real]\", reduce_is_realvec };\nstatic BuiltinTypeSpot matrix_spot = { \"[[real]]\", reduce_is_matrix };\nstatic BuiltinTypeSpot instance_spot = { \"class instance\", pe_is_class };\nstatic gboolean pe_is_gobject( Reduce *rc, PElement *base )\n        { return( PEISMANAGEDGOBJECT( base ) ); }\nstatic BuiltinTypeSpot gobject_spot = { \"GObject\", pe_is_gobject };\n *\n */\n\nstatic BuiltinTypeSpot real_spot = { \"real\", pe_is_real };\nstatic BuiltinTypeSpot complex_spot = { \"complex|image\", iscomplexarg };\nstatic BuiltinTypeSpot flist_spot = { \"non-empty list\", pe_is_flist };\nstatic BuiltinTypeSpot string_spot = { \"[char]\", reduce_is_finitestring };\nstatic BuiltinTypeSpot list_spot = { \"[*]\", reduce_is_list };\nstatic BuiltinTypeSpot math_spot = { \"image|real|complex\", ismatharg };\nstatic BuiltinTypeSpot any_spot = { \"any\", isany };\n\n/* Args for \"_\".\n */\nstatic BuiltinTypeSpot *underscore_args[] = {\n        &string_spot\n};\n\n/* Do a _ call. Args already spotted.\n */\nstatic void\napply_underscore_call( Reduce *rc, \n\tconst char *name, HeapNode **arg, PElement *out )\n{\n        PElement rhs;\n\tchar text[MAX_STRSIZE];\n\n\tPEPOINTRIGHT( arg[0], &rhs );\n\t(void) reduce_get_string( rc, &rhs, text, MAX_STRSIZE );\n\n\t/* Pump though gettext.\n\t */\n\tif( !heap_managedstring_new( rc->heap, _( text ), out ) )\n\t\treduce_throw( rc );\n}\n\n/* Args for \"has_member\".\n */\nstatic BuiltinTypeSpot *has_member_args[] = {\n        &string_spot,\n        &any_spot\n};\n\n/* Do a has_member call. Args already spotted.\n */\nstatic void\napply_has_member_call( Reduce *rc, \n\tconst char *name, HeapNode **arg, PElement *out )\n{\n        PElement rhs;\n\tchar mname[MAX_STRSIZE];\n        PElement member;\n\n\tPEPOINTRIGHT( arg[1], &rhs );\n\t(void) reduce_get_string( rc, &rhs, mname, MAX_STRSIZE );\n        PEPOINTRIGHT( arg[0], &rhs );\n\tPEPUTP( out, ELEMENT_BOOL, \n\t\tclass_get_member( &rhs, mname, NULL, &member ) );\n}\n\n/* Args for \"is_instanceof\".\n */\nstatic BuiltinTypeSpot *is_instanceof_args[] = {\n        &string_spot,\n        &any_spot\n};\n\n/* Do an is_instance call. Args already spotted.\n */\nstatic void\napply_is_instanceof_call( Reduce *rc, \n\tconst char *name, HeapNode **arg, PElement *out )\n{\n        PElement rhs;\n\tchar kname[MAX_STRSIZE];\n\n\tPEPOINTRIGHT( arg[1], &rhs );\n\t(void) reduce_get_string( rc, &rhs, kname, MAX_STRSIZE );\n        PEPOINTRIGHT( arg[0], &rhs );\n\tPEPUTP( out, ELEMENT_BOOL, reduce_is_instanceof( rc, kname, &rhs ) );\n}\n\n/* Args for builtin on complex.\n */\nstatic BuiltinTypeSpot *complex_args[] = {\n        &complex_spot\n};\n\n/* Do a complex op. Args already spotted.\n */\nstatic void\napply_complex_call( Reduce *rc, \n\tconst char *name, HeapNode **arg, PElement *out )\n{\n        PElement rhs;\n\n\tPEPOINTRIGHT( arg[0], &rhs );\n\n\tif( PEISIMAGE( &rhs ) ) {\n\t\tif( strcmp( name, \"re\" ) == 0 ) \n\t\t\tcall_spine( rc, \"im_c2real\", arg, out );\n\t\telse if( strcmp( name, \"im\" ) == 0 ) \n\t\t\tcall_spine( rc, \"im_c2imag\", arg, out );\n\t}\n\telse if( PEISCOMPLEX( &rhs ) ) {\n\t\tif( strcmp( name, \"re\" ) == 0 ) {\n\t\t\tPEPUTP( out, \n\t\t\t\tELEMENT_NODE, GETLEFT( PEGETVAL( &rhs ) ) );\n\t\t}\n\t\telse if( strcmp( name, \"im\" ) == 0 ) {\n\t\t\tPEPUTP( out, \n\t\t\t\tELEMENT_NODE, GETRIGHT( PEGETVAL( &rhs ) ) );\n\t\t}\n\t}\n\telse\n\t\terror( \"internal error #98743698437639487\" );\n}\n\n/* Args for builtin on list.\n */\nstatic BuiltinTypeSpot *flist_args[] = {\n        &flist_spot\n};\n\n/* Do a list op. Args already spotted.\n */\nstatic void\napply_list_call( Reduce *rc, \n\tconst char *name, HeapNode **arg, PElement *out )\n{\n        PElement rhs;\n        PElement a;\n\n\tPEPOINTRIGHT( arg[0], &rhs );\n\tg_assert( PEISFLIST( &rhs ) );\n\n\treduce_get_list( rc, &rhs );\n\n\tif( strcmp( name, \"hd\" ) == 0 ) {\n\t\tPEGETHD( &a, &rhs );\n\t\tPEPUTPE( out, &a );\n\t}\n\telse if( strcmp( name, \"tl\" ) == 0 ) {\n\t\tPEGETTL( &a, &rhs );\n\t\tPEPUTPE( out, &a );\n\t}\n\telse\n\t\terror( \"internal error #098734953\" );\n}\n\n/* \"gammq\"\n */\nstatic BuiltinTypeSpot *gammq_args[] = { \n\t&real_spot,\n\t&real_spot\n};\n\nstatic void\napply_gammq_call( Reduce *rc, \n\tconst char *name, HeapNode **arg, PElement *out )\n{\n\tPElement rhs;\n\tdouble a, x, Q;\n\n\tPEPOINTRIGHT( arg[1], &rhs );\n\ta = PEGETREAL( &rhs );\n\tPEPOINTRIGHT( arg[0], &rhs );\n\tx = PEGETREAL( &rhs );\n\n\tif( a <= 0 || x < 0 ) {\n\t\terror_top( _( \"Out of range.\" ) );\n\t\terror_sub( _( \"gammq arguments must be a > 0, x >= 0.\" ) );\n\t\treduce_throw( rc );\n\t}\n\n#ifdef HAVE_GSL\n\tQ = gsl_sf_gamma_inc_Q( a, x );\n#else /*!HAVE_GSL*/\n\terror_top( _( \"Not available.\" ) );\n\terror_sub( _( \"No GSL library available for gammq.\" ) );\n\treduce_throw( rc );\n#endif /*HAVE_GSL*/\n\n\tif( !heap_real_new( rc->heap, Q, out ) )\n\t\treduce_throw( rc );\n}\n\n/* Args for \"vips_image\". \n */\nstatic BuiltinTypeSpot *image_args[] = { \n\t&string_spot \n};\n\n/* Do a image call.\n */\nstatic void\napply_image_call( Reduce *rc, \n\tconst char *name, HeapNode **arg, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\n\tPElement rhs;\n\tchar buf[FILENAME_MAX];\n\tchar filename[FILENAME_MAX];\n\tchar mode[FILENAME_MAX];\n\tchar *fn;\n\tImageinfo *ii;\n\n\t/* Get string. \n\t */\n\tPEPOINTRIGHT( arg[0], &rhs );\n\t(void) reduce_get_string( rc, &rhs, buf, FILENAME_MAX );\n\n\t/* The buf might be something like n3862.pyr.tif:1, ie. contain some\n\t * load options. Split and search just for the filename component.\n\t */\n\tim_filename_split( buf, filename, mode );\n\n\t/* Try to load image from given string.\n\t */\n\tif( !(fn = path_find_file( filename )) )\n\t\treduce_throw( rc );\n\n\t/* Reattach the mode and load.\n\t */\n\tim_snprintf( buf, FILENAME_MAX, \"%s:%s\", fn, mode );\n\tif( !(ii = imageinfo_new_input( \n\t\tmain_imageinfogroup, NULL, heap, buf )) ) {\n\t\tIM_FREE( fn );\n\t\treduce_throw( rc );\n\t}\n\tIM_FREE( fn );\n\n\tPEPUTP( out, ELEMENT_MANAGED, ii );\n\tMANAGED_UNREF( ii );\n}\n\n/* Args for \"read\". \n */\nstatic BuiltinTypeSpot *read_args[] = { \n\t&string_spot \n};\n\n/* Do a read call.\n */\nstatic void\napply_read_call( Reduce *rc, \n\tconst char *name, HeapNode **arg, PElement *out )\n{\n\tPElement rhs;\n\tchar buf[FILENAME_MAX];\n\n\t/* Get string. \n\t */\n\tPEPOINTRIGHT( arg[0], &rhs );\n\t(void) reduce_get_string( rc, &rhs, buf, FILENAME_MAX );\n\n\tif( !heap_file_new( rc->heap, buf, out ) )\n\t\treduce_throw( rc );\n}\n\n/* Args for \"graph_export_image\". \n */\nstatic BuiltinTypeSpot *graph_export_image_args[] = { \n\t&real_spot,\n\t&any_spot \n};\n\n/* Do a graph_export_image call.\n */\nstatic void\napply_graph_export_image_call( Reduce *rc, \n\tconst char *name, HeapNode **arg, PElement *out )\n{\n#ifdef HAVE_LIBGOFFICE\n\tPElement rhs;\n\tdouble dpi;\n\tPlot *plot;\n\tImageinfo *ii;\n\n\tPEPOINTRIGHT( arg[1], &rhs );\n\tdpi = PEGETREAL( &rhs );\n\n\tPEPOINTRIGHT( arg[0], &rhs );\n\tif( !reduce_is_instanceof( rc, CLASS_PLOT, &rhs ) ) {\n\t\tchar txt[100];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\titext_value_ev( rc, &buf, &rhs );\n\t\terror_top( _( \"Bad argument.\" ) );\n\t\terror_sub( _( \"Argument 2 to \\\"%s\\\" should \"\n\t\t\t\"be instance of \\\"%s\\\", you passed:\\n  %s\" ),\n\t\t\tname, CLASS_PLOT,\n\t\t\tvips_buf_all( &buf ) );\n\t\treduce_throw( rc );\n\t}\n\n\tplot = g_object_new( TYPE_PLOT, NULL );\n\n\tif( !classmodel_update_members( CLASSMODEL( plot ), &rhs ) ) {\n\t\tUNREF( plot );\n\t\treduce_throw( rc );\n\t}\n\n\tif( !(ii = plot_to_image( plot, rc, dpi )) ) {\n\t\tUNREF( plot );\n\t\treduce_throw( rc );\n\t}\n\tUNREF( plot );\n\n\tPEPUTP( out, ELEMENT_MANAGED, ii );\n#else /*!HAVE_LIBGOFFICE*/\n\tPEPUTP( out, ELEMENT_BOOL, TRUE );\n#endif /*HAVE_LIBGOFFICE*/\n}\n\n/* Args for \"math\". \n */\nstatic BuiltinTypeSpot *math_args[] = { \n\t&math_spot \n};\n\n/* A math function ... name, number implementation, image implementation.\n */\ntypedef struct {\n\tconst char *name;\t\t/* ip name */\n\tdouble (*rfn)( double );\t/* Number implementation */\n\tconst char *ifn;\t\t/* VIPS name */\n} MathFn;\n\nstatic double ip_sin( double a ) { return( sin( IM_RAD( a ) ) ); }\nstatic double ip_cos( double a ) { return( cos( IM_RAD( a ) ) ); }\nstatic double ip_tan( double a ) { return( tan( IM_RAD( a ) ) ); }\nstatic double ip_asin( double a ) { return( IM_DEG( asin( a ) ) ); }\nstatic double ip_acos( double a ) { return( IM_DEG( acos( a ) ) ); }\nstatic double ip_atan( double a ) { return( IM_DEG( atan( a ) ) ); }\nstatic double ip_exp10( double a ) { return( pow( 10.0, a ) ); }\nstatic double ip_ceil( double a ) { return( ceil( a ) ); }\nstatic double ip_floor( double a ) { return( floor( a ) ); }\n\n/* Table of math functions ... number implementations, image implementations.\n */\nstatic MathFn math_fn[] = {\n\t{ \"sin\", &ip_sin, \"im_sintra\" },\n\t{ \"cos\", &ip_cos, \"im_costra\" },\n\t{ \"tan\", &ip_tan, \"im_tantra\" },\n\t{ \"asin\", &ip_asin, \"im_asintra\" },\n\t{ \"acos\", &ip_acos, \"im_acostra\" },\n\t{ \"atan\", &ip_atan, \"im_atantra\" },\n\t{ \"log\", &log, \"im_logtra\" },\n\t{ \"log10\", &log10, \"im_log10tra\" },\n\t{ \"exp\", &exp, \"im_exptra\" },\n\t{ \"exp10\", &ip_exp10, \"im_exp10tra\" },\n\t{ \"ceil\", &ip_ceil, \"im_ceil\" },\n\t{ \"floor\", &ip_floor, \"im_floor\" }\n};\n\n/* Do a math function (eg. sin, cos, tan).\n */\nstatic void\napply_math_call( Reduce *rc, \n\tconst char *name, HeapNode **arg, PElement *out )\n{\n\tPElement rhs;\n\tint i;\n\n\t/* Find implementation.\n\t */\n\tfor( i = 0; i < IM_NUMBER( math_fn ); i++ )\n\t\tif( strcmp( name, math_fn[i].name ) == 0 )\n\t\t\tbreak;\n\tif( i == IM_NUMBER( math_fn ) )\n\t\terror( \"internal error #928456936\" );\n\n\t/* Get arg type ... real/complex/image\n\t */\n\tPEPOINTRIGHT( arg[0], &rhs );\n\tif( PEISIMAGE( &rhs ) ) {\n\t\t/* Easy ... pass to VIPS.\n\t\t */\n\t\tcall_spine( rc, math_fn[i].ifn, arg, out );\n\t}\n\telse if( PEISREAL( &rhs ) ) {\n\t\tdouble a = PEGETREAL( &rhs );\n\t\tdouble b = math_fn[i].rfn( a );\n\n\t\tif( !heap_real_new( rc->heap, b, out ) )\n\t\t\treduce_throw( rc );\n\t}\n\telse if( PEISCOMPLEX( &rhs ) ) {\n\t\terror_top( _( \"Not implemented.\" ) );\n\t\terror_sub( _( \"Complex math ops not implemented.\" ) );\n\t\treduce_throw( rc );\n\t}\n\telse\n\t\terror( \"internal error #92870653\" );\n}\n\n/* Args for \"predicate\". \n */\nstatic BuiltinTypeSpot *pred_args[] = { \n\t&any_spot \n};\n\n/* A predicate function ... name, implementation.\n */\ntypedef struct {\n\tconst char *name;\t\t\t\t/* ip name */\n\tgboolean (*fn)( Reduce *, PElement * );\t/* Implementation */\n} PredicateFn;\n\n/* Table of predicate functions ... name and implementation.\n */\nstatic PredicateFn predicate_fn[] = {\n\t{ \"is_image\", &pe_is_image },\n\t{ \"is_bool\", &pe_is_bool },\n\t{ \"is_real\", &pe_is_real },\n\t{ \"is_char\", &pe_is_char },\n\t{ \"is_class\", &pe_is_class },\n\t{ \"is_list\", &pe_is_list },\n\t{ \"is_complex\", &pe_is_complex }\n};\n\n/* Do a predicate function (eg. is_bool)\n */\nstatic void\napply_pred_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out )\n{\n\tPElement rhs;\n\tgboolean res;\n\tint i;\n\n\t/* Find implementation.\n\t */\n\tfor( i = 0; i < IM_NUMBER( predicate_fn ); i++ )\n\t\tif( strcmp( name, predicate_fn[i].name ) == 0 )\n\t\t\tbreak;\n\tif( i == IM_NUMBER( predicate_fn ) )\n\t\terror( \"internal error #928456936\" );\n\n\t/* Call!\n\t */\n\tPEPOINTRIGHT( arg[0], &rhs );\n\tres = predicate_fn[i].fn( rc, &rhs );\n\tPEPUTP( out, ELEMENT_BOOL, res );\n}\n\n/* Args for \"error\". \n */\nstatic BuiltinTypeSpot *error_args[] = { \n\t&string_spot \n};\n\n/* Do \"error\".\n */\nstatic void\napply_error_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out )\n{\n\tchar buf[MAX_STRSIZE];\n\tPElement rhs;\n\n\t/* Get string. \n\t */\n\tPEPOINTRIGHT( arg[0], &rhs );\n\t(void) reduce_get_string( rc, &rhs, buf, MAX_STRSIZE );\n\n\terror_top( _( \"Macro error.\" ) );\n\terror_sub( \"%s\", buf );\n\treduce_throw( rc );\n}\n\n/* Args for \"search\". \n */\nstatic BuiltinTypeSpot *search_args[] = { \n\t&string_spot \n};\n\n/* Do \"search\".\n */\nstatic void\napply_search_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out )\n{\n\tchar buf[MAX_STRSIZE];\n\tPElement rhs;\n\tchar *fn;\n\n\t/* Get string. \n\t */\n\tPEPOINTRIGHT( arg[0], &rhs );\n\t(void) reduce_get_string( rc, &rhs, buf, MAX_STRSIZE );\n\n\tif( !(fn = path_find_file( buf )) )\n\t\t/* If not found, return [].\n\t\t */\n\t\tfn = im_strdup( NULL, \"\" );\n\n\tif( !heap_managedstring_new( rc->heap, fn, out ) ) {\n\t\tIM_FREE( fn );\n\t\treduce_throw( rc );\n\t}\n\tIM_FREE( fn );\n}\n\n/* Args for \"print\". \n */\nstatic BuiltinTypeSpot *print_args[] = { \n\t&any_spot \n};\n\n/* Do \"print\".\n */\nstatic void\napply_print_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out )\n{\n\tPElement rhs;\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tPEPOINTRIGHT( arg[0], &rhs );\n\titext_value_ev( rc, &buf, &rhs );\n\n\tif( !heap_managedstring_new( rc->heap, vips_buf_all( &buf ), out ) )\n\t\treduce_throw( rc );\n}\n\n/* Args for \"dir\". \n */\nstatic BuiltinTypeSpot *dir_args[] = { \n\t&any_spot \n};\n\nstatic void *\ndir_object_member( Symbol *sym, PElement *value, \n\tReduce *rc, PElement *list )\n{\n\tPElement t;\n\n\tif( !heap_list_add( rc->heap, list, &t ) ||\n\t\t!heap_managedstring_new( rc->heap, IOBJECT( sym )->name, &t ) )\n\t\treduce_throw( rc );\n\t(void) heap_list_next( list );\n\n\treturn( NULL );\n}\n\nstatic void *\ndir_object( Reduce *rc, PElement *list, PElement *instance, PElement *out )\n{\n\tPElement p;\n\n\t/* p walks down the list as we build it, list stays pointing at the\n\t * head ready to be written to out.\n\t */\n\tp = *list;\n\theap_list_init( &p );\n\tclass_map( instance, (class_map_fn) dir_object_member, rc, &p );\n\tPEPUTPE( out, list );\n\n\treturn( NULL );\n}\n\nstatic void *\ndir_scope( Symbol *sym, Reduce *rc, PElement *list )\n{\n\tPElement t;\n\n\tif( !heap_list_add( rc->heap, list, &t ) ||\n\t\t!heap_managedstring_new( rc->heap, IOBJECT( sym )->name, &t ) )\n\t\treduce_throw( rc );\n\t(void) heap_list_next( list );\n\n\treturn( NULL );\n}\n\nstatic void *\ndir_gtype( GType type, void *a, void *b )\n{\n\tReduce *rc = (Reduce *) a;\n\tPElement *list = (PElement *) b;\n\tPElement t;\n\n\tif( !heap_list_add( rc->heap, list, &t ) ||\n\t\t!heap_real_new( rc->heap, type, &t ) )\n\t\treturn( rc );\n\t(void) heap_list_next( list );\n\n\treturn( NULL );\n}\n\nstatic void\ndir_gobject( Reduce *rc, \n\tGParamSpec **properties, guint n_properties, PElement *out )\n{\n\tint i;\n\tPElement list;\n\n\tlist = *out;\n\theap_list_init( &list );\n\n\tfor( i = 0; i < n_properties; i++ ) {\n\t\tPElement t;\n\n\t\tif( !heap_list_add( rc->heap, &list, &t ) ||\n\t\t\t!heap_managedstring_new( rc->heap, \n\t\t\t\tproperties[i]->name, &t ) )\n\t\t\treduce_throw( rc );\n\t\t(void) heap_list_next( &list );\n\t}\n}\n\n/* Do \"dir\". \n */\nstatic void\napply_dir_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out )\n{\n\tPElement rhs;\n\n        PEPOINTRIGHT( arg[0], &rhs );\n\n\tif( PEISCLASS( &rhs ) ) \n\t\t/* This is more complex than it looks. We have to walk a class\n\t\t * instance generating a list of member names, while not\n\t\t * destroying the instance as we go, in the case that out will\n\t\t * overwrite (rhs) arg[0].\n\t\t */\n\t\treduce_safe_pointer( rc, (reduce_safe_pointer_fn) dir_object,\n\t\t\t&rhs, out, NULL, NULL );\n\telse if( PEISSYMREF( &rhs ) ) {\n\t\tSymbol *sym = PEGETSYMREF( &rhs );\n\n\t\tif( is_scope( sym ) && sym->expr && sym->expr->compile ) {\n\t\t\tPElement list;\n\n\t\t\tlist = *out;\n\t\t\theap_list_init( &list );\n\n\t\t\ticontainer_map( ICONTAINER( sym->expr->compile ),\n\t\t\t\t(icontainer_map_fn) dir_scope, rc, &list );\n\t\t}\n\t}\n\telse if( PEISREAL( &rhs ) ) {\n\t\t/* Assume this is a gtype and try to get the children of that\n\t\t * type.\n\t\t */\n\t\tGType type = PEGETREAL( &rhs );\n\t\tPElement list;\n\n\t\tlist = *out;\n\t\theap_list_init( &list );\n\n\t\tif( !g_type_name( type ) ) {\n\t\t\terror_top( _( \"No such type\" ) );\n\t\t\terror_sub( _( \"GType %u not found.\" ), \n\t\t\t\t(unsigned int) type );\n\t\t\treduce_throw( rc );\n\t\t}\n\n\t\tif( vips_type_map( type, dir_gtype, rc, &list ) ) \n\t\t\treduce_throw( rc );\n\t}\n\telse if( PEISMANAGEDGOBJECT( &rhs ) ) {\n\t\tguint n_properties;\n\t\tManagedgobjectClass *class = \n\t\t\tMANAGEDGOBJECT_GET_CLASS( PEGETMANAGEDGOBJECT( &rhs ) ); \n\t\tGParamSpec **properties;\n\n\t\tproperties = g_object_class_list_properties( \n\t\t\tG_OBJECT_CLASS( class ), &n_properties );\n\t\tdir_gobject( rc, properties, n_properties, out );\n\t\tg_free( properties);\n\t}\n\telse \n\t\t/* Just [], ie. no names possible.\n\t\t */\n\t\theap_list_init( out );\n}\n\n/* Args for \"expand\". \n */\nstatic BuiltinTypeSpot *expand_args[] = { \n\t&string_spot \n};\n\n/* Do \"expand\".\n */\nstatic void\napply_expand_call( Reduce *rc, const char *name, HeapNode **arg, PElement *out )\n{\n\tPElement rhs;\n\tchar txt[FILENAME_MAX];\n\tchar txt2[FILENAME_MAX];\n\n\tPEPOINTRIGHT( arg[0], &rhs );\n\t(void) reduce_get_string( rc, &rhs, txt, FILENAME_MAX );\n\texpand_variables( txt, txt2 );\n\n\tif( !heap_managedstring_new( rc->heap, txt2, out ) )\n\t\treduce_throw( rc );\n}\n\n/* Args for \"name2gtype\". \n */\nstatic BuiltinTypeSpot *name2gtype_args[] = { \n\t&string_spot \n};\n\n/* Do \"name2gtype\".\n */\nstatic void\napply_name2gtype_call( Reduce *rc, const char *name, \n\tHeapNode **arg, PElement *out )\n{\n\tPElement rhs;\n\tchar txt[FILENAME_MAX];\n\tint gtype;\n\n\tPEPOINTRIGHT( arg[0], &rhs );\n\t(void) reduce_get_string( rc, &rhs, txt, FILENAME_MAX );\n\n\tgtype = g_type_from_name( txt );\n\n\tif( !heap_real_new( rc->heap, gtype, out ) )\n\t\treduce_throw( rc );\n}\n\n/* Args for \"gtype2name\". \n */\nstatic BuiltinTypeSpot *gtype2name_args[] = { \n\t&real_spot \n};\n\n/* Do \"gtype2name\".\n */\nstatic void\napply_gtype2name_call( Reduce *rc, const char *name, \n\tHeapNode **arg, PElement *out )\n{\n\tPElement rhs;\n\tint gtype;\n\n\tPEPOINTRIGHT( arg[0], &rhs );\n\tgtype = PEGETREAL( &rhs );\n\n\tif( !heap_managedstring_new( rc->heap, g_type_name( gtype ), out ) )\n\t\treduce_throw( rc );\n}\n\n/* Args for \"vips_object_new\". \n */\nstatic BuiltinTypeSpot *vo_new_args[] = { \n\t&string_spot,\n\t&list_spot,\n\t&list_spot \n};\n\n/* Do a vips_object_new call.\n */\nstatic void\napply_vo_new_call( Reduce *rc, \n\tconst char *name, HeapNode **arg, PElement *out )\n{\n\tPElement rhs;\n\tchar buf[256];\n\tPElement required;\n\tPElement optional;\n\n\tPEPOINTRIGHT( arg[2], &rhs );\n\treduce_get_string( rc, &rhs, buf, 256 );\n\tPEPOINTRIGHT( arg[1], &required );\n\tPEPOINTRIGHT( arg[0], &optional );\n\n\tvo_object_new( rc, buf, &required, &optional, out );\n}\n\n/* Args for \"vips_call\". \n */\nstatic BuiltinTypeSpot *vo_call_args[] = { \n\t&string_spot,\n\t&list_spot,\n\t&list_spot \n};\n\n/* Do a vips_call call.\n */\nstatic void\napply_vo_call_call( Reduce *rc, \n\tconst char *name, HeapNode **arg, PElement *out )\n{\n\tPElement rhs;\n\tchar buf[256];\n\tPElement required;\n\tPElement optional;\n\n\tPEPOINTRIGHT( arg[2], &rhs );\n\treduce_get_string( rc, &rhs, buf, 256 );\n\tPEPOINTRIGHT( arg[1], &required );\n\tPEPOINTRIGHT( arg[0], &optional );\n\n\tvo_call( rc, buf, &required, &optional, out );\n}\n\n/* All ip's builtin functions. \n */\nstatic BuiltinInfo builtin_table[] = {\n\t/* Other.\n\t */\n\t{ \"dir\", N_( \"return list of names of members\" ),\n\t\tFALSE, IM_NUMBER( dir_args ),\n\t\t&dir_args[0], &apply_dir_call },\n\t{ \"search\", N_( \"search for file\" ),\n\t\tFALSE, IM_NUMBER( search_args ),\n\t\t&search_args[0], &apply_search_call },\n\t{ \"error\", N_( \"raise error\" ),\n\t\tFALSE, IM_NUMBER( error_args ),\n\t\t&error_args[0], &apply_error_call },\n\t{ \"print\", N_( \"convert to [char]\" ),\n\t\tFALSE, IM_NUMBER( print_args ),\n\t\t&print_args[0], &apply_print_call },\n\t{ \"expand\", N_( \"expand environment variables\" ),\n\t\tFALSE, IM_NUMBER( expand_args ),\n\t\t&expand_args[0], &apply_expand_call },\n\t{ \"name2gtype\", N_( \"convert [char] to GType\" ),\n\t\tFALSE, IM_NUMBER( name2gtype_args ),\n\t\t&name2gtype_args[0], &apply_name2gtype_call },\n\t{ \"gtype2name\", N_( \"convert GType to [char]\" ),\n\t\tFALSE, IM_NUMBER( gtype2name_args ),\n\t\t&gtype2name_args[0], &apply_gtype2name_call },\n\t{ \"_\", N_( \"look up localised string\" ),\n\t\tFALSE, IM_NUMBER( underscore_args ), \n\t\t&underscore_args[0], &apply_underscore_call },\n\n\t/* vips8 wrapper.\n\t */\n\t{ \"vips_object_new\", N_( \"create new vips8 object\" ),\n\t\tFALSE, IM_NUMBER( vo_new_args ), \n\t\t&vo_new_args[0], apply_vo_new_call },\n\t{ \"vips_call\", N_( \"call vips8 operator\" ),\n\t\tFALSE, IM_NUMBER( vo_call_args ), \n\t\t&vo_call_args[0], apply_vo_call_call },\n\n\t/* Predicates.\n\t */\n\t{ \"is_image\", N_( \"true if argument is primitive image\" ),\n\t\tFALSE, IM_NUMBER( pred_args ), \n\t\t&pred_args[0], apply_pred_call },\n\t{ \"is_bool\", N_( \"true if argument is primitive bool\" ),\n\t\tFALSE, IM_NUMBER( pred_args ), \n\t\t&pred_args[0], apply_pred_call },\n\t{ \"is_real\", N_( \"true if argument is primitive real number\" ),\n\t\tFALSE, IM_NUMBER( pred_args ), \n\t\t&pred_args[0], apply_pred_call },\n\t{ \"is_class\", N_( \"true if argument is class\" ),\n\t\tFALSE, IM_NUMBER( pred_args ), \n\t\t&pred_args[0], apply_pred_call },\n\t{ \"is_char\", N_( \"true if argument is primitive char\" ),\n\t\tFALSE, IM_NUMBER( pred_args ), \n\t\t&pred_args[0], apply_pred_call },\n\t{ \"is_list\", N_( \"true if argument is primitive list\" ),\n\t\tFALSE, IM_NUMBER( pred_args ), \n\t\t&pred_args[0], apply_pred_call },\n\t{ \"is_complex\", N_( \"true if argument is primitive complex\" ),\n\t\tFALSE, IM_NUMBER( pred_args ), \n\t\t&pred_args[0], apply_pred_call },\n\t{ \"is_instanceof\", N_( \"true if argument class instance of type\" ),\n\t\tFALSE, IM_NUMBER( is_instanceof_args ), \n\t\t&is_instanceof_args[0], apply_is_instanceof_call },\n\t{ \"has_member\", N_( \"true if class has named member\" ),\n\t\tFALSE, IM_NUMBER( has_member_args ), \n\t\t&has_member_args[0], apply_has_member_call },\n\n\t/* List and complex projections.\n\t */\n\t{ \"re\", N_( \"real part of complex\" ),\n\t\tTRUE, IM_NUMBER( complex_args ), \n\t\t&complex_args[0], apply_complex_call },\n\t{ \"im\", N_( \"imaginary part of complex\" ),\n\t\tTRUE, IM_NUMBER( complex_args ), \n\t\t&complex_args[0], apply_complex_call },\n\t{ \"hd\", N_( \"head of list\" ),\n\t\tTRUE, IM_NUMBER( flist_args ), \n\t\t&flist_args[0], apply_list_call },\n\t{ \"tl\", N_( \"tail of list\" ),\n\t\tTRUE, IM_NUMBER( flist_args ), \n\t\t&flist_args[0], apply_list_call },\n\n\t/* Math.\n\t */\n\t{ \"sin\", N_( \"sine of real number\" ),\n\t\tTRUE, IM_NUMBER( math_args ), \n\t\t&math_args[0], apply_math_call },\n\t{ \"cos\", N_( \"cosine of real number\" ),\n\t\tTRUE, IM_NUMBER( math_args ), \n\t\t&math_args[0], apply_math_call },\n\t{ \"tan\", N_( \"tangent of real number\" ),\n\t\tTRUE, IM_NUMBER( math_args ), \n\t\t&math_args[0], apply_math_call }, \n\t{ \"asin\", N_( \"arc sine of real number\" ),\n\t\tTRUE, IM_NUMBER( math_args ), \n\t\t&math_args[0], apply_math_call },\n\t{ \"acos\", N_( \"arc cosine of real number\" ),\n\t\tTRUE, IM_NUMBER( math_args ), \n\t\t&math_args[0], apply_math_call },\n\t{ \"atan\", N_( \"arc tangent of real number\" ),\n\t\tTRUE, IM_NUMBER( math_args ), \n\t\t&math_args[0], apply_math_call }, \n\t{ \"log\", N_( \"log base e of real number\" ),\n\t\tTRUE, IM_NUMBER( math_args ), \n\t\t&math_args[0], apply_math_call },\n\t{ \"log10\", N_( \"log base 10 of real number\" ),\n\t\tTRUE, IM_NUMBER( math_args ), \n\t\t&math_args[0], apply_math_call },\n\t{ \"exp\", N_( \"e to the power of real number\" ),\n\t\tTRUE, IM_NUMBER( math_args ), \n\t\t&math_args[0], apply_math_call },\n\t{ \"exp10\", N_( \"10 to the power of real number\" ),\n\t\tTRUE, IM_NUMBER( math_args ), \n\t\t&math_args[0], apply_math_call },\n\t{ \"ceil\", N_( \"real to int, rounding up\" ),\n\t\tTRUE, IM_NUMBER( math_args ), \n\t\t&math_args[0], apply_math_call },\n\t{ \"floor\", N_( \"real to int, rounding down\" ),\n\t\tTRUE, IM_NUMBER( math_args ), \n\t\t&math_args[0], apply_math_call },\n\n\t/* Optional GSL funcs.\n\t */\n\t{ \"gammq\", N_( \"gamma function\" ),\n\t\tTRUE, IM_NUMBER( gammq_args ), \n\t\t&gammq_args[0], apply_gammq_call },\n\n\t/* Constructors.\n\t */\n\t{ \"vips_image\", N_( \"load vips image\" ),\n\t\tFALSE, IM_NUMBER( image_args ), \n\t\t&image_args[0], apply_image_call },\n\t{ \"read\", N_( \"load text file\" ),\n\t\tFALSE, IM_NUMBER( read_args ), \n\t\t&read_args[0], apply_read_call },\n\t{ \"graph_export_image\", N_( \"generate image from Plot object\" ),\n\t\tFALSE, IM_NUMBER( graph_export_image_args ), \n\t\t&graph_export_image_args[0], apply_graph_export_image_call },\n\n};\n\n#ifdef HAVE_GSL\nstatic void\nbuiltin_gsl_error( const char *reason, const char *file, \n\tint line, int gsl_errno )\n{\n\terror_top( _( \"GSL library error.\" ) );\n\terror_sub( \"%s - (%s:%d) - %s\", \n\t\treason, file, line, gsl_strerror( gsl_errno ) );\n\n\treduce_throw( reduce_context );\n}\n#endif /*HAVE_GSL*/\n\nvoid\nbuiltin_init( void )\n{\n\tToolkit *kit;\n        int i;\n\n\t/* Make the _builtin toolkit and populate.\n\t */\n\tkit = toolkit_new( main_toolkitgroup, \"_builtin\" );\n\n        for( i = 0; i < IM_NUMBER( builtin_table ); i++ ) {\n\t\tSymbol *sym;\n\n\t\tsym = symbol_new( symbol_root->expr->compile,\n\t\t\tbuiltin_table[i].name );\n\t\tg_assert( sym->type == SYM_ZOMBIE );\n\t\tsym->type = SYM_BUILTIN;\n\t\tsym->builtin = &builtin_table[i];\n\t\t(void) tool_new_sym( kit, -1, sym );\n\t\tsymbol_made( sym );\n\t}\n\n\tfilemodel_set_auto_load( FILEMODEL( kit ) );\n\tfilemodel_set_modified( FILEMODEL( kit ), FALSE );\n\tkit->pseudo = TRUE;\n\n\t/* Start up GSL, if we have it.\n\t */\n#ifdef HAVE_GSL\n\tgsl_set_error_handler( builtin_gsl_error );\n#endif /*HAVE_GSL*/\n}\n\n/* Make a usage error.\n */\nvoid\nbuiltin_usage( VipsBuf *buf, BuiltinInfo *builtin )\n{\n\tint i;\n\n\tvips_buf_appendf( buf, \n\t\tngettext( \"Builtin \\\"%s\\\" takes %d argument.\", \n\t\t\t\"Builtin \\\"%s\\\" takes %d arguments.\", \n\t\t\tbuiltin->nargs ),\n\t\tbuiltin->name, builtin->nargs );\n        vips_buf_appends( buf, \"\\n\" );\n\n\tfor( i = 0; i < builtin->nargs; i++ )\n\t\tvips_buf_appendf( buf, \"    %d - %s\\n\", \n\t\ti + 1,\n\t\tbuiltin->args[i]->name );\n}\n\n#ifdef DEBUG\nstatic void\nbuiltin_trace_args( Heap *heap, const char *name, int n, HeapNode **arg )\n{\n\tint i;\n\tchar txt[100];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tfor( i = 0; i < n; i++ ) {\n\t\tPElement t;\n\n\t\tPEPOINTRIGHT( arg[n - i - 1], &t );\n\t\tvips_buf_appends( &buf, \"(\" );\n\t\tgraph_pelement( heap, &buf, &t, FALSE );\n\t\tvips_buf_appends( &buf, \") \" );\n\t}\n\n\tprintf( \"builtin: %s %s\\n\", name, vips_buf_all( &buf ) );\n}\n#endif /*DEBUG*/\n\n/* Execute the internal implementation of a builtin function.\n */\nvoid\nbuiltin_run( Reduce *rc, Compile *compile,\n\tint op, const char *name, HeapNode **arg, PElement *out,\n\tBuiltinInfo *builtin )\n{\n\tint i;\n\n\t/* Typecheck args.\n\t */\n\tfor( i = 0; i < builtin->nargs; i++ ) {\n\t\tBuiltinTypeSpot *ts = builtin->args[i];\n\t\tPElement base;\n\n\t\tPEPOINTRIGHT( arg[builtin->nargs - i - 1], &base );\n\t\tif( !ts->pred( rc, &base ) ) {\n\t\t\tchar txt[100];\n\t\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\t\titext_value_ev( rc, &buf, &base );\n\t\t\terror_top( _( \"Bad argument.\" ) );\n\t\t\terror_sub( _( \"Argument %d to builtin \\\"%s\\\" should \"\n\t\t\t\t\"be \\\"%s\\\", you passed:\\n  %s\" ),\n\t\t\t\ti + 1, name, ts->name,\n\t\t\t\tvips_buf_all( &buf ) );\n\t\t\treduce_throw( rc );\n\t\t}\n\t}\n\n#ifdef DEBUG\n\tbuiltin_trace_args( rc->heap, name, builtin->nargs, arg );\n#endif /*DEBUG*/\n\n\tbuiltin->fn( rc, name, arg, out );\n}\n"
  },
  {
    "path": "src/builtin.h",
    "content": "/* Execute builtin functions.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* A type spotter ... a type name (used in error messages), plus a predicate.\n */\ntypedef struct {\n\tconst char *name;\n\tgboolean (*pred)( Reduce *, PElement * );\n} BuiltinTypeSpot;\n\n/* A builtin function.\n */\ntypedef void (*builtin_fn)( Reduce *, const char *, HeapNode **, PElement * );\n\n/* A function name and a pointer to an implementation. \n */\nstruct _BuiltinInfo {\n\tconst char *name;\n\tconst char *desc;\n\tgboolean override;\n\tint nargs;\n\tBuiltinTypeSpot **args;\n\tbuiltin_fn fn;\n};\n\nvoid builtin_init( void );\nvoid builtin_usage( VipsBuf *buf, BuiltinInfo *builtin );\nvoid builtin_run( Reduce *rc, Compile *compile,\n\tint op, const char *name, HeapNode **arg, PElement *out,\n\tBuiltinInfo *builtin );\n"
  },
  {
    "path": "src/cache.c",
    "content": "/* Call vips functions, cache recent results\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/*\n#define DEBUG_TIME\n#define DEBUG_HISTORY_SANITY\n#define DEBUG_HISTORY_MISS\n#define DEBUG_HISTORY\n#define DEBUG\n */\n\n/* This is usually turned on from a -D in cflags.\n#define DEBUG_LEAK\n */\n\n/* Often want it off ... we get spurious complaints about leaks if an\n * operation has no images in or out (eg. im_version) because it'll never\n * get GCed.\n#undef DEBUG_LEAK\n */\n\n/* The previous function calls we are caching, plus an LRU queue for flushing.\n */\nstatic GHashTable *cache_history_table = NULL;\nstatic Queue *cache_history_lru = NULL;\nint cache_history_size = 0;\n\n/* Hash from a vargv ... just look at input args and the function name.\n */\nstatic unsigned int\ncache_hash( CallInfo *vi )\n{\n\tint i;\n\tunsigned int hash;\n\n\tif( vi->found_hash )\n\t\treturn( vi->hash );\n\n\thash = 0;\n\n/* add ints, floats, pointers and strings to the hash.\n\n\tFIXME ... could do better on double? could or top and bottom 32 bits\n\tbut would this be stupid on a 64 bit machine?\n\n */\n#define HASH_I( I ) hash = (hash << 1) | ((unsigned int) (I));\n#define HASH_D( D ) hash = (hash << 1) | ((unsigned int) (D));\n#define HASH_P( P ) hash = (hash << 1) | (GPOINTER_TO_UINT( P ));\n#define HASH_S( S ) hash = (hash << 1) | g_str_hash( S );\n\n\t/* Add the function to the hash. We often call many functions on\n\t * the same args, we'd like these calls to hash to different numbers.\n\t */\n\tHASH_P( vi->fn );\n\n        for( i = 0; i < vi->fn->argc; i++ ) {\n                im_type_desc *ty = vi->fn->argv[i].desc;\n\n                if( call_type_needs_input( ty ) ) {\n\t\t\tswitch( call_lookup_type( ty->type ) ) {\n\t\t\tcase CALL_DOUBLE:\n\t\t\t\tHASH_D( *((double *) vi->vargv[i]) );\n\t\t\t\tbreak;\n\n\t\t\tcase CALL_INT:\n\t\t\t\tHASH_I( *((int *) vi->vargv[i]) );\n\t\t\t\tbreak;\n\n\t\t\tcase CALL_COMPLEX:\n\t\t\t\tHASH_D( ((double *) vi->vargv[i])[0] );\n\t\t\t\tHASH_D( ((double *) vi->vargv[i])[1] );\n\t\t\t\tbreak;\n\n\t\t\tcase CALL_STRING:\n\t\t\t\tHASH_S( (char *) vi->vargv[i] );\n\t\t\t\tbreak;\n\n\t\t\tcase CALL_GVALUE:\n\t\t\tcase CALL_INTERPOLATE:\n\t\t\t\tbreak;\n\n\t\t\tcase CALL_DOUBLEVEC:\n\t\t\t{\n\t\t\t\tim_doublevec_object *v = \n\t\t\t\t\t(im_doublevec_object *) vi->vargv[i];\n\t\t\t\tint j;\n\n\t\t\t\tfor( j = 0; j < v->n; j++ )\n\t\t\t\t\tHASH_D( v->vec[j] );\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CALL_INTVEC:\n\t\t\t{\n\t\t\t\tim_intvec_object *v = \n\t\t\t\t\t(im_intvec_object *) vi->vargv[i];\n\t\t\t\tint j;\n\n\t\t\t\tfor( j = 0; j < v->n; j++ )\n\t\t\t\t\tHASH_I( v->vec[j] );\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CALL_DMASK:\n\t\t\t{\n\t\t\t\tim_mask_object *mo = vi->vargv[i];\n\t\t\t\tDOUBLEMASK *mask = mo->mask;\n\n\t\t\t\t/* mask can be NULL if we are called after \n\t\t\t\t * call_new() but before we've built the arg\n\t\t\t\t * list.\n\t\t\t\t */\n\t\t\t\tif( mask ) {\n\t\t\t\t\tint ne = mask->xsize * mask->ysize;\n\t\t\t\t\tint j;\n\n\t\t\t\t\tfor( j = 0; j < ne; j++ )\n\t\t\t\t\t\tHASH_D( mask->coeff[j] );\n\t\t\t\t\tHASH_D( mask->scale );\n\t\t\t\t\tHASH_D( mask->offset );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CALL_IMASK:\n\t\t\t{\n\t\t\t\tim_mask_object *mo = vi->vargv[i];\n\t\t\t\tINTMASK *mask = mo->mask;\n\n\t\t\t\t/* mask can be NULL if we are called after \n\t\t\t\t * call_new() but before we've built the arg\n\t\t\t\t * list.\n\t\t\t\t */\n\t\t\t\tif( mask ) {\n\t\t\t\t\tint ne = mask->xsize * mask->ysize;\n\t\t\t\t\tint j;\n\n\t\t\t\t\tfor( j = 0; j < ne; j++ )\n\t\t\t\t\t\tHASH_I( mask->coeff[j] );\n\t\t\t\t\tHASH_I( mask->scale );\n\t\t\t\t\tHASH_I( mask->offset );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault:\n\t\t\tcase CALL_NONE:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n        }\n\n\t/* And the input images.\n\t */\n\tfor( i = 0; i < vi->ninii; i++ )\n\t\tHASH_P( vi->inii[i] );\n\n\tvi->found_hash = TRUE;\n\tvi->hash = hash;\n\n\treturn( hash );\n}\n\n/* Are two function calls equal. Check the func and the input args.\n */\nstatic gboolean\ncache_equal( CallInfo *vi1, CallInfo *vi2 ) \n{\n\tint i;\n\tim_function *fn = vi1->fn;\n\n\tif( vi1 == vi2 )\n\t\treturn( TRUE );\n\n\tif( vi1->fn != vi2->fn )\n\t\treturn( FALSE );\n\n        for( i = 0; i < fn->argc; i++ ) {\n                im_type_desc *ty = fn->argv[i].desc;\n\n                if( call_type_needs_input( ty ) ) {\n\t\t\tswitch( call_lookup_type( ty->type ) ) {\n\t\t\tcase CALL_DOUBLE:\n\t\t\t\tif( *((double *) vi1->vargv[i]) != \n\t\t\t\t\t*((double *) vi2->vargv[i]) )\n\t\t\t\t\treturn( FALSE );\n\t\t\t\tbreak;\n\n\t\t\tcase CALL_INT:\n\t\t\t\tif( *((int *) vi1->vargv[i]) != \n\t\t\t\t\t*((int *) vi2->vargv[i]) )\n\t\t\t\t\treturn( FALSE );\n\t\t\t\tbreak;\n\n\t\t\tcase CALL_COMPLEX:\n\t\t\t\tif( ((double *) vi1->vargv[i])[0] != \n\t\t\t\t\t((double *) vi2->vargv[i])[0] )\n\t\t\t\t\treturn( FALSE );\n\t\t\t\tif( ((double *) vi1->vargv[i])[1] != \n\t\t\t\t\t((double *) vi2->vargv[i])[1] )\n\t\t\t\t\treturn( FALSE );\n\t\t\t\tbreak;\n\n\t\t\tcase CALL_STRING:\n\t\t\t\tif( strcmp( (char *) vi1->vargv[i],\n\t\t\t\t\t(char *) vi2->vargv[i] ) != 0 )\n\t\t\t\t\treturn( FALSE );\n\t\t\t\tbreak;\n\n\t\t\tcase CALL_DOUBLEVEC:\n\t\t\t{\n\t\t\t\tim_doublevec_object *v1 = \n\t\t\t\t\t(im_doublevec_object *) vi1->vargv[i];\n\t\t\t\tim_doublevec_object *v2 = \n\t\t\t\t\t(im_doublevec_object *) vi2->vargv[i];\n\t\t\t\tint j;\n\n\t\t\t\tfor( j = 0; j < v1->n; j++ )\n\t\t\t\t\tif( v1->vec[j] != v2->vec[j] )\n\t\t\t\t\t\treturn( FALSE );\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CALL_INTVEC:\n\t\t\t{\n\t\t\t\tim_intvec_object *v1 = \n\t\t\t\t\t(im_intvec_object *) vi1->vargv[i];\n\t\t\t\tim_intvec_object *v2 = \n\t\t\t\t\t(im_intvec_object *) vi2->vargv[i];\n\t\t\t\tint j;\n\n\t\t\t\tfor( j = 0; j < v1->n; j++ )\n\t\t\t\t\tif( v1->vec[j] != v2->vec[j] )\n\t\t\t\t\t\treturn( FALSE );\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CALL_DMASK:\n\t\t\t{\n\t\t\t\tim_mask_object *mo1 = \n\t\t\t\t\t(im_mask_object *) vi1->vargv[i];\n\t\t\t\tim_mask_object *mo2 = \n\t\t\t\t\t(im_mask_object *) vi2->vargv[i];\n\t\t\t\tDOUBLEMASK *mask1 = mo1->mask;\n\t\t\t\tDOUBLEMASK *mask2 = mo2->mask;\n\t\t\t\tint ne = mask1->xsize * mask2->ysize;\n\t\t\t\tint j;\n\t\n\t\t\t\tif( mask1->xsize != mask2->xsize ||\n\t\t\t\t\tmask1->ysize != mask2->ysize )\n\t\t\t\t\treturn( FALSE );\n\n\t\t\t\tfor( j = 0; j < ne; j++ )\n\t\t\t\t\tif( mask1->coeff[j] != mask2->coeff[j] )\n\t\t\t\t\t\treturn( FALSE );\n\n\t\t\t\tif( mask1->scale != mask2->scale )\n\t\t\t\t\treturn( FALSE );\n\t\t\t\tif( mask1->offset != mask2->offset ) \n\t\t\t\t\treturn( FALSE );\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CALL_IMASK:\n\t\t\t{\n\t\t\t\tim_mask_object *mo1 = \n\t\t\t\t\t(im_mask_object *) vi1->vargv[i];\n\t\t\t\tim_mask_object *mo2 = \n\t\t\t\t\t(im_mask_object *) vi2->vargv[i];\n\t\t\t\tINTMASK *mask1 = mo1->mask;\n\t\t\t\tINTMASK *mask2 = mo2->mask;\n\t\t\t\tint ne = mask1->xsize * mask2->ysize;\n\t\t\t\tint j;\n\t\n\t\t\t\tif( mask1->xsize != mask2->xsize ||\n\t\t\t\t\tmask1->ysize != mask2->ysize )\n\t\t\t\t\treturn( FALSE );\n\n\t\t\t\tfor( j = 0; j < ne; j++ )\n\t\t\t\t\tif( mask1->coeff[j] != mask2->coeff[j] )\n\t\t\t\t\t\treturn( FALSE );\n\n\t\t\t\tif( mask1->scale != mask2->scale )\n\t\t\t\t\treturn( FALSE );\n\t\t\t\tif( mask1->offset != mask2->offset ) \n\t\t\t\t\treturn( FALSE );\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CALL_IMAGEVEC:\n\t\t\t{\n\t\t\t\tim_imagevec_object *v1 = \n\t\t\t\t\t(im_imagevec_object *) vi1->vargv[i];\n\t\t\t\tim_imagevec_object *v2 = \n\t\t\t\t\t(im_imagevec_object *) vi2->vargv[i];\n\n\t\t\t\tif( v1->n != v2->n )\n\t\t\t\t\treturn( FALSE );\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Very strict. Could be more generous here: we'd need\n\t\t\t * to have a pspec for each argument type and then use \n\t\t\t * g_param_values_cmp() to test equality.\n\t\t\t */\n\t\t\tcase CALL_GVALUE:\n\t\t\t\tif( vi1->vargv[i] != vi2->vargv[i] )\n\t\t\t\t\treturn( FALSE );\n\t\t\t\tbreak;\n\n\t\t\tcase CALL_INTERPOLATE:\n\t\t\t\tif( vi1->vargv[i] != vi2->vargv[i] )\n\t\t\t\t\treturn( FALSE );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\tcase CALL_NONE:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n        }\n\n\t/* And the input images.\n\t */\n\tif( vi1->ninii != vi2->ninii )\n\t\treturn( FALSE );\n\tfor( i = 0; i < vi1->ninii; i++ )\n\t\tif( vi1->inii[i] != vi2->inii[i] )\n\t\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n#ifdef DEBUG_HISTORY_SANITY\nstatic void\ncache_history_sanity_sub( CallInfo *vi )\n{\n\tg_assert( g_slist_find( cache_history_lru->list, vi ) );\n}\n\nstatic void\ncache_history_sanity( void )\n{\n\tGSList *p;\n\n\tif( !cache_history_lru || !cache_history_table )\n\t\treturn;\n\n\t/* Everything that's on the LRU should be in the history table.\n\t */\n\tfor( p = cache_history_lru->list; p; p = p->next ) {\n\t\tCallInfo *vi = (CallInfo *) p->data;\n\n\t\tg_assert( g_hash_table_lookup( cache_history_table, vi ) );\n\n\t\tg_assert( vi->fn );\n\t\tg_assert( vi->fn->argc > 0 && vi->fn->argc < MAX_CALL_ARGS );\n\t\tg_assert( vi->in_cache );\n\t}\n\n\t/* Everything that's on the history table should be in the LRU.\n\t */\n\tg_hash_table_foreach( cache_history_table,\n\t\t(GHFunc) cache_history_sanity_sub, NULL );\n}\n#endif /*DEBUG_HISTORY_SANITY */\n\n/* Is a function call in our history? Return the old one. \n */\nstatic CallInfo *\ncache_history_lookup( CallInfo *vi )\n{\n\tCallInfo *old_vi;\n\n\tif( !cache_history_table ) {\n\t\tcache_history_table = g_hash_table_new( \n\t\t\t(GHashFunc) cache_hash, (GEqualFunc) cache_equal );\n\t\tcache_history_lru = queue_new();\n\t}\n\n\told_vi = (CallInfo *) g_hash_table_lookup( cache_history_table, vi );\n\n#ifdef DEBUG_HISTORY\n\tif( old_vi ) \n\t\tprintf( \"cache_history_lookup: found \\\"%s\\\"\\n\", old_vi->name );\n#endif /*DEBUG_HISTORY*/\n#ifdef DEBUG_HISTORY_SANITY\n\tcache_history_sanity();\n#endif /*DEBUG_HISTORY_SANITY*/\n\n\treturn( old_vi );\n}\n\n/* Bump to end of LRU.\n */\nstatic void\ncache_history_touch( CallInfo *vi )\n{\n\tg_assert( vi->in_cache );\n\n\tqueue_remove( cache_history_lru, vi );\n\tqueue_add( cache_history_lru, vi );\n\n#ifdef DEBUG_HISTORY_SANITY\n\tcache_history_sanity();\n#endif /*DEBUG_HISTORY_SANITY*/\n#ifdef DEBUG_HISTORY\n\tprintf( \"cache_history_touch: bumping \\\"%s\\\"\\n\", vi->name );\n#endif /*DEBUG_HISTORY*/\n}\n\n/* Are we in the history? Remove us. Called from cache_info_dispose() on unref, \n * don't call this directly.\n */\nvoid\ncache_history_remove( CallInfo *vi )\n{\n\tint i;\n\n\tif( vi->in_cache ) {\n\t\tqueue_remove( cache_history_lru, vi );\n\t\tg_hash_table_remove( cache_history_table, vi );\n\t\tcache_history_size -= 1;\n\t\tvi->in_cache = FALSE;\n\n#ifdef DEBUG_HISTORY\n\t\tprintf( \"cache_history_remove: removing \\\"%s\\\"\\n\", vi->name );\n#endif /*DEBUG_HISTORY*/\n\t}\n\n\t/* Disconnect signals.\n\t */\n\tfor( i = 0; i < vi->noutii; i++ ) \n\t\tFREESID( vi->outii_destroy_sid[i], vi->outii[i] ); \n\tfor( i = 0; i < vi->ninii; i++ ) {\n\t\tFREESID( vi->inii_destroy_sid[i], vi->inii[i] ); \n\t\tFREESID( vi->inii_invalidate_sid[i], vi->inii[i] ); \n\t}\n\n#ifdef DEBUG_HISTORY_SANITY\n\tcache_history_sanity();\n#endif /*DEBUG_HISTORY_SANITY*/\n}\n\nstatic void\ncache_history_remove_lru( void )\n{\n\tCallInfo *vi;\n\n\tvi = (CallInfo *) queue_head( cache_history_lru );\n\n#ifdef DEBUG_HISTORY\n\tprintf( \"cache_history_remove_lru: flushing \\\"%s\\\"\\n\", vi->name );\n#endif /*DEBUG_HISTORY*/\n\n\tg_object_unref( vi );\n\n#ifdef DEBUG_HISTORY_SANITY\n\tcache_history_sanity();\n#endif /*DEBUG_HISTORY_SANITY*/\n}\n\nstatic void\ncache_history_destroy_cb( Imageinfo *ii, CallInfo *vi )\n{\n#ifdef DEBUG_HISTORY\n\tprintf( \"cache_history_destroy_cb: on death of ii, uncaching \\\"%s\\\"\\n\", \n\t\tvi->name );\n#endif /*DEBUG_HISTORY*/\n\n\tg_object_unref( vi );\n}\n\nstatic void\ncache_history_invalidate_cb( Imageinfo *ii, CallInfo *vi )\n{\n#ifdef DEBUG_HISTORY\n\tprintf( \"cache_history_invalidate_cb: \"\n\t\t\"on invalidate of ii, uncaching \\\"%s\\\"\\n\", vi->name );\n#endif /*DEBUG_HISTORY*/\n\n\tg_object_unref( vi );\n}\n\n/* Add a function call to the history. \n */\nstatic void\ncache_history_add( CallInfo *vi )\n{\n\tint i;\n\n#ifdef DEBUG_HISTORY_SANITY\n\tcache_history_sanity();\n#endif /*DEBUG_HISTORY_SANITY*/\n\n#ifdef DEBUG_HISTORY\n\tprintf( \"cache_history_add: adding \\\"%s\\\" (%p), hash = %u\\n\", \n\t\tvi->name, vi, vi->hash );\n#endif /*DEBUG_HISTORY*/\n\n\tg_assert( !g_hash_table_lookup( cache_history_table, vi ) );\n\tg_assert( !vi->in_cache );\n\n\tg_hash_table_insert( cache_history_table, vi, vi );\n\tcache_history_size += 1;\n\n\tg_assert( g_hash_table_lookup( cache_history_table, vi ) );\n\n\tqueue_add( cache_history_lru, vi );\n\tvi->in_cache = TRUE;\n\tg_object_ref( vi );\n\n\t/* If any of our ii are destroyed, we must go too.\n\t */\n\tfor( i = 0; i < vi->noutii; i++ )\n\t\tvi->outii_destroy_sid[i] = g_signal_connect( vi->outii[i], \n\t\t\t\"destroy\", \n\t\t\tG_CALLBACK( cache_history_destroy_cb ), vi );\n\n\t/* If any of our input ii are destroyed or painted on, we must also \n\t * uncache.\n\t */\n\tfor( i = 0; i < vi->ninii; i++ ) {\n\t\tvi->inii_destroy_sid[i] = g_signal_connect( vi->inii[i], \n\t\t\t\"destroy\", \n\t\t\tG_CALLBACK( cache_history_destroy_cb ), vi );\n\t\tvi->inii_invalidate_sid[i] = g_signal_connect( vi->inii[i], \n\t\t\t\"invalidate\", \n\t\t\tG_CALLBACK( cache_history_invalidate_cb ), vi );\n\t}\n\n\t/* History too big? Flush!\n\t */\n\tif( queue_length( cache_history_lru ) > CALL_HISTORY_MAX ) \n\t\tcache_history_remove_lru();\n\n#ifdef DEBUG_HISTORY_SANITY\n\tcache_history_sanity();\n#endif /*DEBUG_HISTORY_SANITY*/\n}\n\n/* Sort out the input images. \n */\nstatic gboolean\ncache_gather( CallInfo *vi ) \n{\n\tint i, j;\n\tint ni;\n\n\t/* No input images.\n\t */\n\tif( vi->ninii == 0 )\n\t\treturn( TRUE );\n\n\t/* Can we LUT? Function needs to be LUTable, all input images\n\t * have to be the same underlying image, and image must be uncoded\n\t * IM_BANDFMT_UCHAR.\n\t */\n\tvi->use_lut = (vi->fn->flags & IM_FN_PTOP) && \n\t\timageinfo_same_underlying( vi->inii, vi->ninii ) &&\n\t\timageinfo_get_underlying( vi->inii[0] )->Coding == \n\t\t\tIM_CODING_NONE &&\n\t\timageinfo_get_underlying( vi->inii[0] )->BandFmt == \n\t\t\tIM_BANDFMT_UCHAR;\n\n\tif( vi->use_lut ) \n\t\tfor( i = 0; i < vi->noutii; i++ )\n\t\t\timageinfo_set_underlying( vi->outii[i], vi->inii[0] );\n\n\t/* Now fill the vargv vector with the IMAGE pointers.\n\t */\n\tni = 0;\n\tfor( i = 0; i < vi->fn->argc; i++ ) {\n\t\tim_type_desc *ty = vi->fn->argv[i].desc;\n\n\t\tif( !call_type_needs_input( ty ) ) \n\t\t\tcontinue;\n\n\t\tif( strcmp( ty->type, IM_TYPE_IMAGE ) == 0 ) { \n\t\t\tImageinfo *inii = vi->inii[ni++];\n\t\t\tIMAGE *im;\n\n\t\t\tif( !(im = imageinfo_get( vi->use_lut, inii )) )\n\t\t\t\treturn( FALSE );\n\n\t\t\t/* RW operations need an extra copy. Tyhe vargv will\n\t\t\t * already have been created by cache_build_output().\n\t\t\t */\n\t\t\tif( ty->flags & IM_TYPE_RW ) {\n\t\t\t\tif( im_copy( im, vi->vargv[i] ) )\n\t\t\t\t\treturn( FALSE );\n\t\t\t}\n\t\t\telse\n\t\t\t\tvi->vargv[i] = im; \n\t\t}\n\n\t\tif( strcmp( ty->type, IM_TYPE_IMAGEVEC ) == 0 ) {\n\t\t\tim_imagevec_object *iv = \n\t\t\t\t(im_imagevec_object *) vi->vargv[i];\n\n\t\t\t/* Found an input image vector. Add all the imageinfo\n\t\t\t * in the vector.\n\t\t\t */\n\t\t\tfor( j = 0; j < iv->n; j++ ) {\n\t\t\t\tImageinfo *inii = vi->inii[ni++];\n\t\t\t\tIMAGE *im;\n\n\t\t\t\tif( !(im = imageinfo_get( vi->use_lut, inii )) )\n\t\t\t\t\treturn( FALSE );\n\n\t\t\t\tiv->vec[j] = im;\n\t\t\t}\n\t\t}\n\t}\n\n\t/* We should have used up all the images exactly.\n\t */\n\tg_assert( ni == vi->ninii );\n\n\treturn( TRUE );\n}\n\n/* VIPS types -> a string buffer. Yuk! Should be a method on object type. This\n * is used to generate vips history, so it has to be in sh format.\n */\nvoid\ncache_tochar_shell( CallInfo *vi, int i, VipsBuf *buf )\n{\n\tim_object obj = vi->vargv[i];\n\tim_type_desc *ty = vi->fn->argv[i].desc;\n\n\tswitch( call_lookup_type( ty->type ) ) {\n\tcase CALL_DOUBLE:\n\t\tvips_buf_appendf( buf, \"%g\", *((double*)obj) );\n\t\tbreak;\n\n\tcase CALL_INT:\n\t\tvips_buf_appendf( buf, \"%d\", *((int*)obj) );\n\t\tbreak;\n\n\tcase CALL_COMPLEX:\n\t\tvips_buf_appendf( buf, \"(%g, %g)\", \n\t\t\t((double*)obj)[0], ((double*)obj)[1] );\n\t\tbreak;\n\n\tcase CALL_STRING:\n\t\tvips_buf_appendf( buf, \"\\\"%s\\\"\", (char*)obj );\n\t\tbreak;\n\n\tcase CALL_IMAGE:\n{\n\t\tIMAGE *im = (IMAGE *) obj;\n\n\t\t/* In quotes, in case there are spaces in the\n\t\t * filename. We also need to test im, as we might be called\n\t\t * before the im has been generated.\n\t\t */\n\t\tvips_buf_appendf( buf, \"\\\"%s\\\"\", im ? im->filename : \"null\" );\n\n\t\tbreak;\n}\n\n\tcase CALL_DMASK:\n\tcase CALL_IMASK:\n\t{\n\t\tim_mask_object *mo = obj;\n\n\t\tvips_buf_appendf( buf, \"%s\", NN( mo->name ) );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_DOUBLEVEC:\n\t{\n\t\tim_doublevec_object *v = (im_doublevec_object *) obj;\n\t\tint j;\n\n\t\tvips_buf_appendf( buf, \"\\\"\" );\n\t\tfor( j = 0; j < v->n; j++ )\n\t\t\tvips_buf_appendf( buf, \"%g \", v->vec[j] );\n\t\tvips_buf_appendf( buf, \"\\\"\" );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_INTVEC:\n\t{\n\t\tim_intvec_object *v = (im_intvec_object *) obj;\n\t\tint j;\n\n\t\tvips_buf_appendf( buf, \"\\\"\" );\n\t\tfor( j = 0; j < v->n; j++ )\n\t\t\tvips_buf_appendf( buf, \"%d \", v->vec[j] );\n\t\tvips_buf_appendf( buf, \"\\\"\" );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_IMAGEVEC:\n\t{\n\t\tim_imagevec_object *v = (im_imagevec_object *) obj;\n\t\tint j;\n\n\t\tvips_buf_appendf( buf, \"\\\"\" );\n\t\tfor( j = 0; j < v->n; j++ ) \n\t\t\tvips_buf_appendf( buf, \"%s \", v->vec[j]->filename );\n\t\tvips_buf_appendf( buf, \"\\\"\" );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_GVALUE:\n\t{\n\t\tGValue *value = (GValue *) obj;\n\n\t\tvips_buf_appendgv( buf, value );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_INTERPOLATE:\n\t\tvips_object_to_string( VIPS_OBJECT( obj ), buf );\n\t\tbreak;\n\n\tcase CALL_NONE:\n\t\tif( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 ) \n\t\t\t/* Just assume sRGB.\n\t\t\t */\n\t\t\tvips_buf_appendf( buf, \"sRGB\" );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n}\n\n/* VIPS types -> a buffer. For tracing calls and debug.\n */\nvoid\ncache_tochar_trace( CallInfo *vi, int i, VipsBuf *buf )\n{\n\tim_object obj = vi->vargv[i];\n\tim_type_desc *vips = vi->fn->argv[i].desc;\n\n\tswitch( call_lookup_type( vips->type ) ) {\n\tcase CALL_DOUBLE:\n\t\tvips_buf_appendf( buf, \"%g\", *((double*)obj) );\n\t\tbreak;\n\n\tcase CALL_INT:\n\t\tvips_buf_appendf( buf, \"%d\", *((int*)obj) );\n\t\tbreak;\n\n\tcase CALL_COMPLEX:\n\t\tvips_buf_appendf( buf, \"(%g, %g)\", \n\t\t\t((double*)obj)[0], ((double*)obj)[1] );\n\t\tbreak;\n\n\tcase CALL_STRING:\n\t\tvips_buf_appendf( buf, \"\\\"%s\\\"\", (char*) obj );\n\t\tbreak;\n\n\tcase CALL_IMAGE:\n\t\tvips_buf_appendi( buf, (IMAGE *) obj );\n\t\tbreak;\n\n\tcase CALL_DMASK:\n\t\tvips_buf_appendf( buf, \"dmask\" );\n\t\tbreak;\n\n\tcase CALL_IMASK:\n\t\tvips_buf_appendf( buf, \"imask\" );\n\t\tbreak;\n\n\tcase CALL_DOUBLEVEC:\n\t\tvips_buf_appendf( buf, \"doublevec\" );\n\t\tbreak;\n\n\tcase CALL_INTVEC:\n\t\tvips_buf_appendf( buf, \"intvec\" );\n\t\tbreak;\n\n\tcase CALL_IMAGEVEC:\n\t\tvips_buf_appendf( buf, \"imagevec\" );\n\t\tbreak;\n\n\tcase CALL_GVALUE:\n\t{\n\t\tGValue *value = (GValue *) obj;\n\n\t\tvips_buf_appends( buf, \"(gvalue\" );\n\t\tvips_buf_appendgv( buf, value );\n\t\tvips_buf_appendf( buf, \")\" );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_INTERPOLATE:\n\t\tvips_object_to_string( VIPS_OBJECT( obj ), buf );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n}\n\n/* Get the args from the VIPS call buffer.\n */\nstatic void\ncache_args_vips( CallInfo *vi, VipsBuf *buf )\n{\n\tint i;\n\n\tvips_buf_appendf( buf, _( \"You passed:\" ) );\n\tvips_buf_appendf( buf, \"\\n\" );\n        for( i = 0; i < vi->fn->argc; i++ ) {\n                im_type_desc *ty = vi->fn->argv[i].desc;\n                char *name = vi->fn->argv[i].name;\n\n                if( call_type_needs_input( ty ) ) {\n                        vips_buf_appendf( buf, \"   %s - \", name );\n                        cache_tochar_trace( vi, i, buf );\n                        vips_buf_appendf( buf, \"\\n\" );\n                }\n        }\n}\n\n/* There's a problem calling the function. Show args from the vips call\n * struct.\n */\nstatic void\ncache_error_fn_vips( CallInfo *vi )\n{\n\tchar txt[1000];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\terror_top( _( \"VIPS library error.\" ) );\n\n\tvips_buf_appendf( &buf, \n\t\t_( \"Error calling library function \\\"%s\\\" (%s).\" ),\n\t\tvi->name, vi->fn->desc );\n\tvips_buf_appendf( &buf, \"\\n\" );\n\tvips_buf_appendf( &buf, _( \"VIPS library: %s\" ), im_error_buffer() );\n\tim_error_clear();\n\tvips_buf_appendf( &buf, \"\\n\" );\n\tcache_args_vips( vi, &buf );\n\tvips_buf_appendf( &buf, \"\\n\" );\n\tcall_usage( &buf, vi->fn );\n\terror_sub( \"%s\", vips_buf_all( &buf ) );\n}\n\nstatic gboolean\ncache_build_argv( CallInfo *vi, char **argv )\n{\n\tint i;\n\n\tfor( i = 0; i < vi->fn->argc; i++ ) {\n\t\tchar txt[512];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\tcache_tochar_shell( vi, i, &buf );\n\t\tif( !(argv[i] = im_strdup( NULL, vips_buf_all( &buf ) )) )\n\t\t\treturn( FALSE );\n\t}\n\n#ifdef DEBUG\n\tprintf( \"cache_build_argv: argv for %s is:\\n  \", vi->fn->name );\n\tfor( i = 0; i < vi->fn->argc; i++ )\n\t\tprintf( \"%s \", NN( argv[i] ) );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\treturn( TRUE );\n}\n\nstatic void\ncache_free_argv( int argc, char **argv )\n{\n\tint i;\n\n\tfor( i = 0; i < argc; i++ ) {\n\t\tIM_FREE( argv[i] );\n\t}\n\tIM_FREE( argv );\n}\n\n/* Update the VIPS hist for all output images.\n */\nstatic void\ncache_update_hist( CallInfo *vi )\n{\n\tint argc = vi->fn->argc;\n\tchar **argv;\n\tint i;\n\n#ifdef DEBUG\n\tprintf( \"cache_update_hist: %s\\n\", vi->name );\n#endif /*DEBUG*/\n\n\t/* No output images? Nothing to do.\n\t */\n\tif( vi->nires == 0 )\n\t\treturn;\n\n\t/* Build an argv for this call. +1 for NULL termination.\n\t */\n\tif( !(argv = IM_ARRAY( NULL, argc + 1, char * )) )\n\t\treturn;\n\tfor( i = 0; i < argc + 1; i++ )\n\t\targv[i] = NULL;\n\tif( !cache_build_argv( vi, argv ) ) {\n\t\tcache_free_argv( argc, argv );\n\t\treturn;\n\t}\n\n\tfor( i = 0; i < vi->nres; i++ ) {\n\t\tint j = vi->outpos[i];\n\t\tim_type_desc *ty = vi->fn->argv[j].desc;\n\n\t\t/* Image output.\n\t\t */\n\t\tif( call_lookup_type( ty->type ) == CALL_IMAGE ) {\n#ifdef DEBUG\n\t\t\tprintf( \"cache_update_hist: adding to arg %d\\n\", j );\n#endif /*DEBUG*/\n\n\t\t\tim_updatehist( vi->vargv[j], vi->fn->name, argc, argv );\n\t\t}\n\t}\n\n\tcache_free_argv( argc, argv );\n}\n\n/* Call a vips operation. \n *\n * The cache takes ownership of the CallInfo passed in, and returns a ref to a\n * CallInfo (might be a different one) that contains the result. Should be \n * unreffed when you're done with it.\n *\n * On error, return NULL.\n */\nCallInfo *\ncache_dispatch( CallInfo *vi, PElement *out )\n{\n\tCallInfo *old_vi;\n\n#ifdef DEBUG_HISTORY_SANITY\n\tcache_history_sanity();\n#endif /*DEBUG_HISTORY_SANITY*/\n\n\t/* Calculate the hash for this vi after building it, but before we do\n\t * cache_gather();\n\t *\n\t * We want the hash to reflect the args as supplied by nip2, not the\n\t * args as transformed by cache_gather() for this specific call.\n\t */\n\t(void) cache_hash( vi );\n\n\t/* Look over the images we have and turn input Imageinfos to IMAGEs.\n\t * If we can do this with a lut, set all that up.\n\t */\n\tif( !cache_gather( vi ) ) {\n\t\tg_object_unref( vi );\n\t\treturn( NULL );\n\t}\n\n\t/* We have to show args after gather, since the tracer wants IMAGE not\n\t * Imageinfo.\n\t */\n#ifdef DEBUG\n{\n\tint i;\n\n\tfor( i = 0; i < vi->fn->argc; i++ ) {\n\t\tim_type_desc *ty = vi->fn->argv[i].desc;\n\n\t\tchar txt[512];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\tprintf( \"cache_fill_spine: arg[%d] (%s) = \", i, ty->type );\n\t\tcache_tochar_trace( vi, i, &buf );\n\t\tprintf( \"%s\\n\", vips_buf_all( &buf ) );\n\t}\n}\n#endif /*DEBUG*/\n\n\t/* Is this function call in the history?\n\t */\n\tif( (old_vi = cache_history_lookup( vi )) ) {\n\t\t/* Yes: reuse! unref our arg to junk it, adda ref to the\n\t\t * cached call for our caller.\n\t\t */\n\t\tg_object_unref( vi );\n\t\tvi = old_vi;\n\t\tg_object_ref( vi );\n\n\t\tif( trace_flags & TRACE_VIPS ) \n\t\t\tvips_buf_appendf( trace_current(), \"(from cache) \" );\n\n#ifdef DEBUG_HISTORY\n\t\tprintf( \"cache_dispatch: found %s in history\\n\", vi->name );\n#endif /*DEBUG_HISTORY*/\n\t}\n\telse {\n\t\t/* No: call function.\n\t\t */\n\t\tint result;\n\n#ifdef DEBUG_TIME\n\t\tstatic GTimer *timer = NULL;\n\n\t\tif( !timer )\n\t\t\ttimer = g_timer_new();\n\t\tg_timer_reset( timer );\n#endif /*DEBUG_TIME*/\n\n#ifdef DEBUG_HISTORY_MISS\n\t\tprintf( \"cache_dispatch: calling %s\\n\", vi->name );\n#endif /*DEBUG_HISTORY_MISS*/\n\n\t\t/* Be careful. Eval callbacks from this may do anything,\n\t\t * including call cache_dispatch().\n\t\t */\n\t\tresult = vi->fn->disp( vi->vargv );\n\n#ifdef DEBUG_TIME\n\t\tprintf( \"cache_dispatch: %s - %g seconds\\n\", \n\t\t\tvi->name, g_timer_elapsed( timer, NULL ) );\n#endif /*DEBUG_TIME*/\n\n\t\tif( result ) {\n\t\t\tcache_error_fn_vips( vi );\n\t\t\tg_object_unref( vi );\n\t\t\treturn( NULL );\n\t\t}\n\t\tcache_update_hist( vi );\n\t}\n\n\t/* Add to our operation cache, if necessary.\n\t */\n\tif( !(vi->fn->flags & IM_FN_NOCACHE) ) {\n\t\tif( vi->in_cache ) \n\t\t\t/* Already in the history. Just touch the time.\n\t\t\t */\n\t\t\tcache_history_touch( vi );\n\t\telse if( (old_vi = cache_history_lookup( vi )) ) {\n\t\t\t/* We have an equal but older item there? This can \n\t\t\t * happen with nested calls. Touch the old one.\n\t\t\t */\n\t\t\tcache_history_touch( old_vi );\n\t\t\tvi = old_vi;\n\t\t}\n\t\telse\n\t\t\tcache_history_add( vi );\n\t}\n\n#ifdef DEBUG_HISTORY_SANITY\n\tcache_history_sanity();\n#endif /*DEBUG_HISTORY_SANITY*/\n\n\treturn( vi );\n}\n\n"
  },
  {
    "path": "src/cache.h",
    "content": "/* Call vips functions from the graph reducer.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\nextern int cache_history_size;\n\nvoid cache_tochar_trace( CallInfo *vi, int i, VipsBuf *buf );\nvoid cache_history_remove( CallInfo *vi );\nCallInfo *cache_dispatch( CallInfo *vi, PElement *out );\n"
  },
  {
    "path": "src/call.c",
    "content": "/* Call vips functions from the graph reducer.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with CALL - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/*\n#define DEBUG_TIME\n#define DEBUG\n */\n\n/* This is usually turned on from a -D in cflags.\n#define DEBUG_LEAK\n */\n\n/* Often want it off ... we get spurious complaints about leaks if an\n * operation has no images in or out (eg. im_version) because it'll never\n * get GCed.\n#undef DEBUG_LEAK\n */\n\n/* CALL argument types we support. Keep order in sync with CallArgumentType.\n */\nstatic im_arg_type call_supported[] = {\n\tIM_TYPE_DOUBLE,\t\t\n\tIM_TYPE_INT,\t\n\tIM_TYPE_COMPLEX,\n\tIM_TYPE_STRING,\n\tIM_TYPE_IMAGE,\n\tIM_TYPE_DOUBLEVEC,\n\tIM_TYPE_DMASK,\n\tIM_TYPE_IMASK,\n\tIM_TYPE_IMAGEVEC,\n\tIM_TYPE_INTVEC,\n\tIM_TYPE_GVALUE,\n\tIM_TYPE_INTERPOLATE\n};\n\nstatic iObjectClass *parent_class = NULL;\n\n/* All the CallInfo we make ... for leak and sanity testing. Build this file \n * with DEBUG_LEAK to enable add/remove to this list.\n */\nGSList *call_info_all = NULL;\n\nvoid\ncall_check_all_destroyed( void )\n{\n#ifdef DEBUG_LEAK\n\tint n_leaks;\n\tGSList *p;\n\n\tn_leaks = 0;\n\tfor( p = call_info_all; p; p = p->next ) {\n\t\tCallInfo *vi = (CallInfo *) p->data;\n\t\n\t\t/* Operations which don't take an image as either an input or \n\t\t * output will stay in the cache. Don't report them.\n\t\t */\n\t\tif( vi->ninii || vi->noutii ) {\n\t\t\tn_leaks += 1;\n\t\t\tprintf( \"\\t%s\\n\", vi->name );\n\t\t}\n\t}\n\n\tif( n_leaks ) \n\t\tprintf( \"** %d CallInfo leaked!\\n\", n_leaks ); \n#endif /*DEBUG_LEAK*/\n}\n\n/* Does a vips argument type require an argument from nip2?\n */\ngboolean\ncall_type_needs_input( im_type_desc *ty )\n{\n\t/* We supply these.\n\t */\n\tif( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 ) \n\t\treturn( FALSE );\n\n\tif( !(ty->flags & IM_TYPE_OUTPUT) )\n\t\treturn( TRUE );\n\n\tif( ty->flags & IM_TYPE_RW ) \n\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\n/* Will a vips argument type generate a result for nip2?\n */\ngboolean\ncall_type_makes_output( im_type_desc *ty )\n{\n\t/* We ignore these.\n\t */\n\tif( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 ) \n\t\treturn( FALSE );\n\n\tif( ty->flags & (IM_TYPE_OUTPUT | IM_TYPE_RW) ) \n\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\n/* Error early on .. we can't print args yet.\n */\nvoid\ncall_error( CallInfo *vi )\n{\n\terror_top( _( \"CALL library error.\" ) );\n\terror_sub( _( \"Error calling library function \\\"%s\\\" (%s).\" ), \n\t\tvi->name, vi->fn->desc );\n}\n\n/* Get the args from the heap.\n */\nstatic void\ncall_args_heap( CallInfo *vi, HeapNode **arg, VipsBuf *buf )\n{\n\tint i;\n\n\tvips_buf_appendf( buf, _( \"You passed:\" ) );\n\tvips_buf_appendf( buf, \"\\n\" );\n\tfor( i = 0; i < vi->nargs; i++ ) {\n\t\tim_arg_desc *varg = &vi->fn->argv[vi->inpos[i]];\n\t\tPElement rhs;\n\n\t\tPEPOINTRIGHT( arg[vi->nargs - i - 1], &rhs );\n\t\tvips_buf_appendf( buf, \"  %s - \", varg->name );\n\t\titext_value_ev( vi->rc, buf, &rhs );\n\t\tvips_buf_appendf( buf, \"\\n\" );\n\t}\n}\n\n/* Make a usage error for a CALL function.\n */\nvoid\ncall_usage( VipsBuf *buf, im_function *fn )\n{\n\tim_package *pack = im_package_of_function( fn->name );\n\tchar input[MAX_STRSIZE];\n\tchar output[MAX_STRSIZE];\n\tint nout, nin;\n\tint i;\n\n\tstrcpy( input, \"\" );\n\tstrcpy( output, \"\" );\n\tnin = 0;\n\tnout = 0;\n\tfor( i = 0; i < fn->argc; i++ ) {\n\t\tim_arg_desc *arg = &fn->argv[i];\n\t\tchar line[256];\n\n\t\t/* Format name, type message.\n\t\t */\n\t\tim_snprintf( line, 256, \n\t\t\t\"   %s  - %s\\n\", arg->name, arg->desc->type );\n\n\t\tif( call_type_makes_output( arg->desc ) ) {\n\t\t\tstrcat( output, line );\n\t\t\tnout++;\n\t\t}\n\n\t\tif( call_type_needs_input( arg->desc ) ) {\n\t\t\tstrcat( input, line );\n\t\t\tnin++;\n\t\t}\n\t}\n\n\tvips_buf_appendf( buf, _( \"Usage:\" ) );\n        vips_buf_appends( buf, \"\\n\" );\n        vips_buf_appendf( buf, _( \"CALL operator \\\"%s\\\"\" ), fn->name );\n        vips_buf_appends( buf, \"\\n\" );\n        vips_buf_appendf( buf, _( \"%s, from package \\\"%s\\\"\" ), \n\t\tfn->desc, pack->name );\n        vips_buf_appends( buf, \"\\n\" );\n\n\tvips_buf_appendf( buf, \n\t\tngettext( \"\\\"%s\\\" takes %d argument:\",\n\t\t\t\"\\\"%s\\\" takes %d arguments:\",\n\t\t\tnin ),\n\t\tfn->name, nin );\n        vips_buf_appendf( buf, \"\\n%s\", input );\n\n\tvips_buf_appendf( buf, \n\t\tngettext( \"And produces %d result:\",\n\t\t\t\"And produces %d results:\",\n\t\t\tnout ),\n\t\tnout );\n\tvips_buf_appendf( buf, \"\\n%s\", output );\n\n        /* Print any flags this function has.\n         */\n        vips_buf_appendf( buf, _( \"Flags:\" ) );\n        vips_buf_appends( buf, \"\\n\" );\n\tvips_buf_appendf( buf, \"   (\" );\n        if( fn->flags & IM_FN_PIO )\n                vips_buf_appendf( buf, _( \"PIO function\" ) );\n        else\n                vips_buf_appendf( buf, _( \"WIO function\" ) );\n\tvips_buf_appendf( buf, \") (\" );\n        if( fn->flags & IM_FN_TRANSFORM ) \n                vips_buf_appendf( buf, _( \"coordinate transformer\" ) );\n        else\n                vips_buf_appendf( buf, _( \"no coordinate transformation\" ) );\n\tvips_buf_appendf( buf, \") (\" );\n        if( fn->flags & IM_FN_PTOP )\n                vips_buf_appendf( buf, _( \"point-to-point operation\" ) );\n        else\n                vips_buf_appendf( buf, _( \"area operation\" ) );\n\tvips_buf_appendf( buf, \") (\" );\n        if( fn->flags & IM_FN_NOCACHE )\n                vips_buf_appendf( buf, _( \"uncacheable operation\" ) );\n        else\n                vips_buf_appendf( buf, _( \"operation can be cached\" ) );\n        vips_buf_appendf( buf, \")\\n\" );\n}\n\n/* We know there's a problem exporting a particular arg to CALL.\n */\nstatic void\ncall_error_arg( CallInfo *vi, HeapNode **arg, int argi )\n{\n\tchar txt[10000];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\terror_top( _( \"Bad argument.\" ) );\n\n\tvips_buf_appendf( &buf,\n\t\t_( \"Argument %d (%s) to \\\"%s\\\" is the wrong type.\" ),\n\t\targi + 1, vi->fn->argv[vi->inpos[argi]].name, vi->name );\n\tvips_buf_appendf( &buf, \"\\n\" );\n\tcall_args_heap( vi, arg, &buf );\n\tvips_buf_appendf( &buf, \"\\n\" );\n\tcall_usage( &buf, vi->fn );\n\terror_sub( \"%s\", vips_buf_all( &buf ) );\n}\n\n/* Too many args.\n */\nvoid\ncall_error_toomany( CallInfo *vi )\n{\n\tchar txt[1000];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\terror_top( _( \"Too many arguments.\" ) );\n\n\tvips_buf_appendf( &buf,\n\t\t_( \"Too many arguments to \\\"%s\\\".\" ),\n\t\tvi->name );\n\tvips_buf_appendf( &buf, \"\\n\" );\n\tcall_usage( &buf, vi->fn );\n\terror_sub( \"%s\", vips_buf_all( &buf ) );\n}\n\n/* Look up a CALL type. \n */\nCallArgumentType\ncall_lookup_type( im_arg_type type )\n{\n\tint i;\n\n\tfor( i = 0; i < IM_NUMBER( call_supported ); i++ )\n\t\tif( strcmp( type, call_supported[i] ) == 0 )\n\t\t\treturn( (CallArgumentType) i );\n\n\terror_top( _( \"Unknown type.\" ) );\n\terror_sub( _( \"CALL type \\\"%s\\\" not supported\" ), type );\n\n\treturn( CALL_NONE );\n}\n\n/* Is this the sort of CALL function we can call?\n */\ngboolean\ncall_is_callable( im_function *fn )\n{\n\tint i;\n\tint nout;\n\tint nin;\n\n\tif( fn->argc >= MAX_CALL_ARGS )\n\t\treturn( FALSE );\n\n        /* Check all argument types are supported. As well as the arg types\n         * spotted by call_lookup_type, we also allow IM_TYPE_DISPLAY.\n         */\n        for( i = 0; i < fn->argc; i++ ) {\n                im_arg_desc *arg = &fn->argv[i];\n                im_arg_type vt = arg->desc->type;\n\n                if( call_lookup_type( vt ) == CALL_NONE ) {\n                        /* Unknown type .. if DISPLAY it's OK.\n                         */\n                        if( strcmp( vt, IM_TYPE_DISPLAY ) != 0 )\n                                return( FALSE );\n                }\n        }\n\n        nin = nout = 0;\n        for( i = 0; i < fn->argc; i++ ) {\n\t\tim_type_desc *ty = fn->argv[i].desc;\n\n\t\tif( call_type_makes_output( ty ) ) \n\t\t\tnout += 1;\n\n\t\tif( call_type_needs_input( ty ) ) \n\t\t\tnin += 1;\n\t}\n\n        /* Must be at least one output argument.\n         */\n\n        /* Must be at least one output argument.\n         */\n        if( nout == 0 ) \n                return( FALSE );\n\n\t/* Need at least 1 input argument: we reply on having an application\n\t * node to overwrite with (I result).\n\t */\n        if( nin == 0 ) \n                return( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Count the number of args a CALL function needs.\n */\nint\ncall_n_args( im_function *fn )\n{\n\tint i;\n\tint nin;\n\n        for( nin = 0, i = 0; i < fn->argc; i++ ) {\n\t\tim_type_desc *ty = fn->argv[i].desc;\n\n\t\tif( call_type_needs_input( ty ) ) \n                        nin += 1;\n        }\n\n\treturn( nin );\n}\n\n/* Make an im_doublevec_object.\n */\nstatic int\ncall_make_doublevec( im_doublevec_object *dv, int n, double *vec )\n{\n\tint i;\n\n\tdv->n = n;\n\tdv->vec = NULL;\n\n\tif( n > 0 ) {\n\t\tif( !(dv->vec = IARRAY( NULL, n, double )) )\n\t\t\treturn( -1 );\n\t\tfor( i = 0; i < n; i++ )\n\t\t\tdv->vec[i] = vec[i];\n\t}\n\n\treturn( 0 );\n}\n\n/* Make an im_intvec_object. Make from a vec of doubles, because that's what\n * we get from nip.\n */\nstatic int\ncall_make_intvec( im_intvec_object *dv, int n, double *vec )\n{\n\tint i;\n\n\tdv->n = n;\n\tdv->vec = NULL;\n\n\tif( n > 0 ) {\n\t\tif( !(dv->vec = IARRAY( NULL, n, int )) )\n\t\t\treturn( -1 );\n\t\tfor( i = 0; i < n; i++ )\n\t\t\tdv->vec[i] = vec[i];\n\t}\n\n\treturn( 0 );\n}\n\n/* Make an im_imagevec_object.\n */\nstatic int\ncall_make_imagevec( im_imagevec_object *iv, int n )\n{\n\tint i;\n\n\tiv->n = n;\n\tiv->vec = NULL;\n\n\tif( n > 0 ) {\n\t\tif( !(iv->vec = IARRAY( NULL, n, IMAGE * )) )\n\t\t\treturn( -1 );\n\t\tfor( i = 0; i < n; i++ )\n\t\t\tiv->vec[i] = NULL;\n\t}\n\n\treturn( 0 );\n}\n\n/* Add another ii to inii.\n */\nstatic gboolean\ncall_add_input_ii( CallInfo *vi, Imageinfo *ii )\n{\n\tif( vi->ninii > MAX_CALL_ARGS ) {\n\t\tcall_error_toomany( vi );\n\t\treturn( FALSE );\n\t}\n\n\tvi->inii[vi->ninii] = ii;\n\tvi->ninii += 1;\n\n\t/* We hold a ref to the ii until the call is done and the result\n\t * written back to nip2. If we cache the result, we make a new\n\t * weakref.\n\t */\n\tmanaged_dup_nonheap( MANAGED( ii ) );\n\tvi->must_drop = TRUE;\n\n\treturn( TRUE );\n}\n\n/* ip types -> CALL types. Write to obj. FALSE for no conversion possible.\n */\nstatic gboolean\ncall_fromip( CallInfo *vi, int i, PElement *arg )\n{\n\tim_type_desc *ty = vi->fn->argv[i].desc;\n\tCallArgumentType vt = call_lookup_type( ty->type );\n\tim_object *obj = &vi->vargv[i];\n\n\t/* If call_lookup_type failed, is it the special DISPLAY type?\n\t */\n\tif( vt == CALL_NONE && strcmp( ty->type, IM_TYPE_DISPLAY ) != 0 ) \n\t\t/* Unknown type, and it's not DISPLAY. Flag an error.\n\t\t */\n\t\treturn( FALSE );\n\n\tswitch( vt ) {\n\tcase CALL_NONE:\t/* IM_TYPE_DISPLAY */\n\t\t/* Just use IM_TYPE_sRGB.\n\t\t */\n\t\t*obj = im_col_displays( 7 );\n\n\t\tbreak;\n\n\tcase CALL_DOUBLE:\n\t{\n\t\tdouble *a = *obj;\n\n\t\tif( !PEISREAL( arg ) )\n\t\t\treturn( FALSE );\n\t\t*a = PEGETREAL( arg );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_INT:\n\t{\n\t\tint *i = *obj;\n\n\t\tif( PEISREAL( arg ) ) {\n\t\t\tdouble t = PEGETREAL( arg );\n\n\t\t\t*i = (int) t;\n\t\t}\n\t\telse if( PEISBOOL( arg ) )\n\t\t\t*i = PEGETBOOL( arg );\n\t\telse\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_COMPLEX:\n\t{\n\t\tdouble *c = *obj;\n\n\t\tif( !PEISCOMPLEX( arg ) )\n\t\t\treturn( FALSE );\n\t\tc[0] = PEGETREALPART( arg );\n\t\tc[1] = PEGETIMAGPART( arg );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_STRING:\n\t{\n\t\tchar **c = (char **) obj;\n\t\tchar buf[MAX_STRSIZE];\n\n\t\tif( !heap_get_string( arg, buf, MAX_STRSIZE ) )\n\t\t\treturn( FALSE );\n\t\t*c = im_strdup( NULL, buf );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_IMAGE:\n\t\t/* Just note the Imageinfo for now ... a later pass sets vargv \n\t\t * once we've checked all the LUTs.\n\t\t */\n\t\tif( !PEISIMAGE( arg ) ||\n\t\t\t!call_add_input_ii( vi, IMAGEINFO( PEGETII( arg ) ) ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\n\tcase CALL_DOUBLEVEC:\n\t{\n\t\tdouble buf[MAX_VEC];\n\t\tint n;\n\n\t\tif( (n = heap_get_realvec( arg, buf, MAX_VEC )) < 0 ||\n\t\t\tcall_make_doublevec( *obj, n, buf ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_INTVEC:\n\t{\n\t\tdouble buf[MAX_VEC];\n\t\tint n;\n\n\t\tif( (n = heap_get_realvec( arg, buf, MAX_VEC )) < 0 ||\n\t\t\tcall_make_intvec( *obj, n, buf ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_IMAGEVEC:\n\t{\n\t\tImageinfo *buf[MAX_VEC];\n\t\tint n;\n\t\tint i;\n\n\t\t/* Put Imageinfo in for now ... a later pass changes this to\n\t\t * IMAGE* once we've checked all the LUTs.\n\t\t */\n\t\tif( (n = heap_get_imagevec( arg, buf, MAX_VEC )) < 0 ||\n\t\t\tcall_make_imagevec( *obj, n ) )\n\t\t\treturn( FALSE );\n\n\t\tfor( i = 0; i < n; i++ )\n\t\t\tif( !call_add_input_ii( vi, buf[i] ) )\n\t\t\t\treturn( FALSE );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_DMASK:\n\tcase CALL_IMASK:\n\t{\n\t\tim_mask_object **mo = (im_mask_object **) obj;\n\n\t\tif( vt == 6 ) {\n\t\t\tDOUBLEMASK *mask;\n\n\t\t\tif( !(mask = matrix_ip_to_dmask( arg )) )\n\t\t\t\treturn( FALSE );\n\t\t\t(*mo)->mask = mask;\n\t\t\t(*mo)->name = im_strdupn( mask->filename );\n\t\t}\n\t\telse {\n\t\t\tINTMASK *mask;\n\n\t\t\tif( !(mask = matrix_ip_to_imask( arg )) )\n\t\t\t\treturn( FALSE );\n\t\t\t(*mo)->mask = mask;\n\t\t\t(*mo)->name = im_strdupn( mask->filename );\n\t\t}\n\n\t\tbreak;\n\t}\n\n\tcase CALL_GVALUE:\n\t{\n\t\tGValue *value = *obj;\n\n\t\tmemset( value, 0, sizeof( GValue ) );\n\t\tif( !heap_ip_to_gvalue( arg, value ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_INTERPOLATE:\n\t\tif( !PEISMANAGEDGOBJECT( arg ) )\n\t\t\treturn( FALSE );\n\t\t*obj = PEGETMANAGEDGOBJECT( arg );\n\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* CALL types -> ip types. Write to arg. Use outiiindex to iterate through\n * outii[] as we find output imageinfo.\n */\nstatic gboolean\ncall_toip( CallInfo *vi, int i, int *outiiindex, PElement *arg )\n{\n\tim_object obj = vi->vargv[i];\n\tim_type_desc *ty = vi->fn->argv[i].desc;\n\n#ifdef DEBUG\n\tprintf( \"call_toip: arg[%d] (%s) = \", i, ty->type );\n#endif /*DEBUG*/\n\n\tswitch( call_lookup_type( ty->type ) ) {\n\tcase CALL_DOUBLE:\n\t\tif( !heap_real_new( vi->rc->heap, *((double*)obj), arg ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\n\tcase CALL_INT:\n\t\tif( !heap_real_new( vi->rc->heap, *((int*)obj), arg ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\n\tcase CALL_DOUBLEVEC:\n\t{\n\t\tim_doublevec_object *dv = obj;\n\n\t\tif( !heap_realvec_new( vi->rc->heap, dv->n, dv->vec, arg ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_INTVEC:\n\t{\n\t\tim_intvec_object *iv = obj;\n\n\t\tif( !heap_intvec_new( vi->rc->heap, iv->n, iv->vec, arg ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_COMPLEX:\n\t\tif( !heap_complex_new( vi->rc->heap, \n\t\t\t((double*)obj)[0], ((double*)obj)[1], arg ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\n\tcase CALL_STRING:\n\t\tif( !heap_managedstring_new( vi->rc->heap, (char *) obj, arg ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\n\tcase CALL_IMAGE:\n\t{\n\t\tImageinfo *outii;\n\n\t\toutii = vi->outii[*outiiindex];\n\t\t*outiiindex += 1;\n\n\t\tPEPUTP( arg, ELEMENT_MANAGED, outii );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_DMASK:\n\t{\n\t\tim_mask_object *mo = obj;\n\t\tDOUBLEMASK *mask = mo->mask;\n\n\t\tif( !matrix_dmask_to_heap( vi->rc->heap, mask, arg ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_IMASK:\n\t{\n\t\tim_mask_object *mo = obj;\n\t\tINTMASK *mask = mo->mask;\n\n\t\tif( !matrix_imask_to_heap( vi->rc->heap, mask, arg ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_GVALUE:\n\t\tif( !heap_gvalue_to_ip( (GValue *) obj, arg ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\n\tcase CALL_IMAGEVEC:\n\tcase CALL_INTERPOLATE:\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n#ifdef DEBUG\n\tpgraph( arg );\n#endif /*DEBUG*/\n\n\treturn( TRUE );\n}\n\nstatic void *\ncall_write_result_sub( Reduce *rc, PElement *safe, CallInfo *vi, PElement *out )\n{\n\tint outiiindex;\n\n\t/* call_toip() uses this to iterate through outii[].\n\t */\n\toutiiindex = 0;\n\n\t/* Write result.\n\t */\n\tif( vi->nres == 1 ) {\n\t\t/* Single result.\n\t\t */\n\t\tif( !call_toip( vi, vi->outpos[0], &outiiindex, safe ) )\n\t\t\treturn( out );\n\t}\n\telse {\n\t\t/* Have to build a list of results.\n\t\t */\n\t\tPElement list;\n\t\tPElement t;\n\t\tint i;\n\n\t\tlist = *safe;\n\t\theap_list_init( &list );\n\t\tfor( i = 0; i < vi->nres; i++ ) {\n\t\t\tif( !heap_list_add( vi->rc->heap, &list, &t ) ||\n\t\t\t\t!call_toip( vi, \n\t\t\t\t\tvi->outpos[i], &outiiindex, &t ) )\n\t\t\t\treturn( out );\n\n\t\t\t(void) heap_list_next( &list );\n\t\t}\n\t}\n\n\t/* Now overwrite out with safe.\n\t */\n\tPEPUTPE( out, safe );\n\n\treturn( NULL );\n}\n\n/* Write the results back to the heap. We have to so this in two stages:\n * build the output object linked off a new managed Element, then once it's\n * built, overwrite our output\n */\nstatic gboolean\ncall_write_result( CallInfo *vi, PElement *out )\n{\n\tif( reduce_safe_pointer( vi->rc, \n\t\t(reduce_safe_pointer_fn) call_write_result_sub, \n\t\tvi, out, NULL, NULL ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Junk all the refs we were holding during the call. See call_add_input_ii() \n * and call_add_output_ii().\n *\n * This gets called explicitly after we have handed the ii refs back to nip2\n * during normal processing, or from _dispose() if we bomb out early and\n * unref.\n */\nstatic void\ncall_drop_refs( CallInfo *vi )\n{\n\tif( vi->must_drop ) {\n\t\tint i;\n\n#ifdef DEBUG\n\t\tprintf( \"call_drop_refs: dropping %d in refs\\n\", vi->ninii );\n\t\tprintf( \"call_drop_refs: dropping %d out refs\\n\", vi->noutii );\n#endif /*DEBUG*/\n\n\t\tfor( i = 0; i < vi->ninii; i++ )\n\t\t\tmanaged_destroy_nonheap( MANAGED( vi->inii[i] ) );\n\t\tfor( i = 0; i < vi->noutii; i++ )\n\t\t\tmanaged_destroy_nonheap( MANAGED( vi->outii[i] ) );\n\n\t\tvi->must_drop = FALSE;\n\t}\n}\n\nstatic void\ncall_info_dispose( GObject *gobject )\n{\n\tCallInfo *vi;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_CALL_INFO( gobject ) );\n\n\tvi = CALL_INFO( gobject );\n\n#ifdef DEBUG\n\tprintf( \"call_info_dispose: (%p) %s \\\"%s\\\"\\n\",\n\t\tvi, G_OBJECT_TYPE_NAME( vi ), vi->name );\n#endif /*DEBUG*/\n\n\t/* Are we in the history? Remove us.\n\t */\n\tcache_history_remove( vi ); \n\n\t/* Drop any refs we may have left dangling.\n\t */\n\tcall_drop_refs( vi );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\n/* Junk stuff we may have attached to vargv.\n */\nstatic void\ncall_vargv_free( im_function *fn, im_object *vargv )\n{\n\tint i;\n\n\t/* Free any CALL args we built and haven't used.\n\t */\n\tfor( i = 0; i < fn->argc; i++ ) {\n\t\tim_type_desc *ty = fn->argv[i].desc;\n\t\tim_object *obj = vargv[i];\n\t\tCallArgumentType vt;\n\n\t\t/* Make sure we don't damage any error message we might\n\t\t * have.\n\t\t */\n\t\terror_block();\n\t\tvt = call_lookup_type( ty->type );\n\t\terror_unblock();\n\n\t\tswitch( vt ) {\n\t\tcase CALL_NONE:\t\t/* IM_TYPE_DISPLAY */\n\t\tcase CALL_DOUBLE:\n\t\tcase CALL_INT: \t\n\t\tcase CALL_COMPLEX: \n\t\tcase CALL_GVALUE:\n\t\tcase CALL_INTERPOLATE:\n\t\tcase CALL_IMAGE:\n\t\t\t/* Do nothing.\n\t\t\t */\n\t\t\tbreak;\n\n\t\tcase CALL_STRING:\n\t\t\tIM_FREE( obj );\n\t\t\tbreak;\n\n\t\tcase CALL_IMAGEVEC: \t\n\t\t\tIM_FREE( ((im_imagevec_object *) obj)->vec );\n\t\t\tbreak;\n\n\t\tcase CALL_DOUBLEVEC:\n\t\t\tIM_FREE( ((im_doublevec_object *) obj)->vec );\n\t\t\tbreak;\n\n\t\tcase CALL_INTVEC:\n\t\t\tIM_FREE( ((im_intvec_object *) obj)->vec );\n\t\t\tbreak;\n\n\t\tcase CALL_DMASK:\n\t\t\tIM_FREE( ((im_mask_object *) obj)->name );\n\t\t\tIM_FREEF( im_free_dmask, \n\t\t\t\t((im_mask_object *) obj)->mask );\n\t\t\tbreak;\n\n\t\tcase CALL_IMASK:\n\t\t\tIM_FREE( ((im_mask_object *) obj)->name );\n\t\t\tIM_FREEF( im_free_imask, \n\t\t\t\t((im_mask_object *) obj)->mask );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tg_assert( FALSE );\n\t\t}\n\t}\n}\n\nstatic void\ncall_info_finalize( GObject *gobject )\n{\n\tCallInfo *vi;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_CALL_INFO( gobject ) );\n\n\tvi = CALL_INFO( gobject );\n\n#ifdef DEBUG_LEAK\n\tcall_info_all = g_slist_remove( call_info_all, vi );\n#endif /*DEBUG_LEAK*/\n\n\tif( vi->vargv ) {\n\t\tcall_vargv_free( vi->fn, vi->vargv );\n\t\tim_free_vargv( vi->fn, vi->vargv );\n\t\tIM_FREE( vi->vargv );\n\t}\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\ncall_info_info( iObject *iobject, VipsBuf *buf )\n{\n\tCallInfo *vi = CALL_INFO( iobject );\n\n\tvips_buf_appendf( buf, \"call_info_info: (%p) %s \\\"%s\\\"\\n\",\n\t\tvi, G_OBJECT_TYPE_NAME( vi ), NN( IOBJECT( vi )->name ) );\n}\n\nstatic void\ncall_info_class_init( CallInfoClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tiObjectClass *iobject_class = IOBJECT_CLASS( class );\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = call_info_dispose;\n\tgobject_class->finalize = call_info_finalize;\n\n\tiobject_class->info = call_info_info;\n}\n\nstatic void\ncall_info_init( CallInfo *vi )\n{\n\tint i;\n\n\tvi->name = NULL;\n\tvi->fn = NULL;\n\tvi->rc = NULL;\n\tvi->vargv = NULL;\n\tvi->nargs = 0;\n\tvi->nres = 0;\n\tvi->nires = 0;\n\tvi->ninii = 0;\n\tvi->noutii = 0;\n\tvi->use_lut = FALSE;\t\t/* Set this properly later */\n\tvi->found_hash = FALSE;\n\tvi->in_cache = FALSE;\n\tvi->must_drop = FALSE;\n\n#ifdef DEBUG_LEAK\n\tcall_info_all = g_slist_prepend( call_info_all, vi );\n#endif /*DEBUG_LEAK*/\n\n\tfor( i = 0; i < MAX_CALL_ARGS; i++ ) {\n\t\tvi->outii_destroy_sid[i] = 0;\n\t\tvi->inii_destroy_sid[i] = 0;\n\t\tvi->inii_invalidate_sid[i] = 0;\n\t}\n}\n\nGType\ncall_info_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( CallInfoClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) call_info_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( CallInfo ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) call_info_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_IOBJECT, \n\t\t\t\"CallInfo\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic CallInfo *\ncall_new( Reduce *rc, im_function *fn )\n{\n\tCallInfo *vi;\n\tint i;\n\n\tg_assert( fn->argc < MAX_CALL_ARGS - 1 );\n\n\tif( !fn || \n\t\t!(vi = CALL_INFO( g_object_new( TYPE_CALL_INFO, NULL ) )) )\n\t\treturn( NULL );\n\tvi->name = fn->name;\n\tvi->fn = fn;\n\tvi->rc = rc;\n\n\t/* Look over the args ... count the number of inputs we need, and \n\t * the number of outputs we generate. Note the position of each.\n\t */\n\tfor( i = 0; i < vi->fn->argc; i++ ) {\n\t\tim_type_desc *ty = vi->fn->argv[i].desc;\n\n\t\tif( call_type_makes_output( ty ) ) {\n\t\t\tvi->outpos[vi->nres] = i;\n\t\t\tvi->nres += 1; \n\n\t\t\t/* Image output.\n\t\t\t */\n\t\t\tif( strcmp( ty->type, IM_TYPE_IMAGE ) == 0 ) \n\t\t\t\tvi->nires += 1;\n\t\t}\n\n\t\tif( call_type_needs_input( ty ) ) {\n\t\t\tvi->inpos[vi->nargs] = i;\n\t\t\tvi->nargs += 1; \n\t\t}\n\t}\n\n\t/* Make the call spine, alloc memory. \n\t */\n\tif( !(vi->vargv = IM_ARRAY( NULL, vi->fn->argc + 1, im_object )) ||\n\t\tim_allocate_vargv( vi->fn, vi->vargv ) ) {\n\t\tcall_error( vi );\n\t\tg_object_unref( vi );\n\t\treturn( NULL );\n\t}\n\n\treturn( vi );\n}\n\n/* Add another ii to outii.\n */\nstatic gboolean\ncall_add_output_ii( CallInfo *vi, Imageinfo *ii )\n{\n\tif( vi->noutii > MAX_CALL_ARGS ) {\n\t\tcall_error_toomany( vi );\n\t\treturn( FALSE );\n\t}\n\n\tvi->outii[vi->noutii] = ii;\n\tvi->noutii += 1;\n\n\t/* We hold a ref to the ii until the call is done and the result\n\t * written back to nip2. If we cache the result, we make a new\n\t * weakref.\n\t */\n\tmanaged_dup_nonheap( MANAGED( ii ) );\n\tvi->must_drop = TRUE;\n\n\treturn( TRUE );\n}\n\n/* Init an output slot in vargv.\n */\nstatic gboolean\ncall_build_output( CallInfo *vi, int i )\n{\n\tim_type_desc *ty = vi->fn->argv[i].desc;\n\n\t/* Provide output objects for the function to write to.\n\t */\n\tswitch( call_lookup_type( ty->type ) ) {\n\tcase CALL_DOUBLE:\n\tcase CALL_INT:\n\tcase CALL_COMPLEX:\n\tcase CALL_STRING:\n\t\tbreak;\n\n\tcase CALL_IMAGE:\n{\n\t\tImageinfo *ii;\n\n\t\tif( !(ii = imageinfo_new_temp( main_imageinfogroup, \n\t\t\tvi->rc->heap, NULL, \"p\" )) ||\n\t\t\t!call_add_output_ii( vi, ii ) ||\n\t\t\t!(vi->vargv[i] = imageinfo_get( FALSE, ii )) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n}\n\n\tcase CALL_DMASK:\n\tcase CALL_IMASK:\n\t{\n\t\tim_mask_object *mo = vi->vargv[i];\n\n\t\tmo->mask = NULL;\n\t\tmo->name = im_strdup( NULL, \"\" );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_GVALUE:\n\t{\n\t\tGValue *value = vi->vargv[i];\n\n\t\tmemset( value, 0, sizeof( GValue ) );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_DOUBLEVEC:\n\tcase CALL_INTVEC:\n\t{\n\t\t/* intvec is also int + pointer.\n\t\t */\n\t\tim_doublevec_object *dv = vi->vargv[i];\n\n\t\tdv->n = 0;\n\t\tdv->vec = NULL;\n\n\t\tbreak;\n\t}\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic gboolean\ncall_build_inputva( CallInfo *vi, int i, va_list *ap )\n{\n\tim_type_desc *ty = vi->fn->argv[i].desc;\n\n\tswitch( call_lookup_type( ty->type ) ) {\n\tcase CALL_DOUBLE:\n\t{\n\t\tdouble v = va_arg( *ap, double );\n\n#ifdef DEBUG\n\t\tprintf( \"%g\\n\", v );\n#endif /*DEBUG*/\n\n\t\t*((double*)vi->vargv[i]) = v;\n\n\t\tif( trace_flags & TRACE_VIPS ) \n\t\t\tvips_buf_appendf( trace_current(), \"%g \", v );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_INT:\n\t{\n\t\tint v = va_arg( *ap, int );\n\n#ifdef DEBUG\n\t\tprintf( \"%d\\n\", v );\n#endif /*DEBUG*/\n\n\t\t*((int*)vi->vargv[i]) = v;\n\n\t\tif( trace_flags & TRACE_VIPS ) \n\t\t\tvips_buf_appendf( trace_current(), \"%d \", v );\n\n\t\tbreak;\n\t}\n\n\tcase CALL_GVALUE:\n\t{\n\t\tGValue *value = va_arg( *ap, GValue * );\n\n#ifdef DEBUG\n\t\tprintf( \"gvalue %p\\n\", value );\n#endif /*DEBUG*/\n\n\t\tvi->vargv[i] = value;\n\n\t\tif( trace_flags & TRACE_VIPS ) {\n\t\t\tvips_buf_appendgv( trace_current(), value );\n\t\t\tvips_buf_appends( trace_current(), \" \" );\n\t\t}\n\n\t\tbreak;\n\t}\n\n\tcase CALL_INTERPOLATE:\n\t{\n\t\tVipsInterpolate *value = \n\t\t\tva_arg( *ap, VipsInterpolate * );\n\n#ifdef DEBUG\n\t\tprintf( \"interpolate %p\\n\", value );\n#endif /*DEBUG*/\n\n\t\tvi->vargv[i] = value;\n\n\t\tif( trace_flags & TRACE_VIPS ) {\n\t\t\tvips_object_to_string( VIPS_OBJECT( value ), \n\t\t\t\ttrace_current() );\n\t\t\tvips_buf_appends( trace_current(), \" \" );\n\t\t}\n\n\t\tbreak;\n\t}\n\n\tcase CALL_IMAGE:\n\t{\n\t\tImageinfo *ii = va_arg( *ap, Imageinfo * );\n\n#ifdef DEBUG\n\t\tprintf( \"imageinfo %p\\n\", ii );\n#endif /*DEBUG*/\n\n\t\tif( !call_add_input_ii( vi, ii ) )\n\t\t\treturn( FALSE );\n\n\t\t/* Filled in later.\n\t\t */\n\t\tvi->vargv[i] = NULL;\n\n\t\tif( trace_flags & TRACE_VIPS ) {\n\t\t\tVipsBuf *buf = trace_current();\n\n\t\t\tif( ii && ii->im ) {\n\t\t\t\tvips_buf_appends( buf, \"<\" );\n\t\t\t\tvips_buf_appendf( buf, \n\t\t\t\t\t_( \"image \\\"%s\\\"\" ),\n\t\t\t\t\tii->im->filename ); \n\t\t\t\tvips_buf_appends( buf, \"> \" );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tvips_buf_appends( buf, \"<\" );\n\t\t\t\tvips_buf_appends( buf, \n\t\t\t\t\t_( \"no image\" ) );\n\t\t\t\tvips_buf_appends( buf, \"> \" );\n\t\t\t}\n\t\t}\n\n\t\tbreak;\n\t}\n\n\tcase CALL_DOUBLEVEC:\n\t{\n\t\tint n = va_arg( *ap, int );\n\t\tdouble *vec = va_arg( *ap, double * );\n\n#ifdef DEBUG\n{\n\t\tint i;\n\n\t\tfor( i = 0; i < n; i++ )\n\t\t\tprintf( \"%g, \", vec[i] );\n\t\tprintf( \"\\n\" );\n}\n#endif /*DEBUG*/\n\n\t\tif( call_make_doublevec( vi->vargv[i], n, vec ) )\n\t\t\treturn( FALSE );\n\n\t\tif( trace_flags & TRACE_VIPS ) {\n\t\t\tVipsBuf *buf = trace_current();\n\t\t\tint i;\n\n\t\t\tvips_buf_appendf( buf, \"<\" );\n\t\t\tvips_buf_appendf( buf, _( \"doublevec\" ) );\n\t\t\tfor( i = 0; i < n; i++ )\n\t\t\t\tvips_buf_appendf( buf, \" %g\", vec[i] );\n\t\t\tvips_buf_appends( buf, \"> \" );\n\t\t}\n\n\t\tbreak;\n\t}\n\n\t/* \n\n\t\tFIXME ... add intvec perhaps\n\n\t */\n\n\tcase CALL_IMAGEVEC:\n\t{\n\t\tint n = va_arg( *ap, int );\n\t\tImageinfo **vec = va_arg( *ap, Imageinfo ** );\n\n#ifdef DEBUG\n{\n\t\tint i;\n\n\t\tfor( i = 0; i < n; i++ )\n\t\t\tprintf( \"%p, \", vec[i] );\n\t\tprintf( \"\\n\" );\n}\n#endif /*DEBUG*/\n\n\t\tif( call_make_imagevec( vi->vargv[i], n ) )\n\t\t\treturn( FALSE );\n\n\t\tfor( i = 0; i < n; i++ )\n\t\t\tif( !call_add_input_ii( vi, vec[i] ) )\n\t\t\t\treturn( FALSE );\n\n\t\tif( trace_flags & TRACE_VIPS ) {\n\t\t\tVipsBuf *buf = trace_current();\n\t\t\tint i;\n\n\t\t\tvips_buf_appendf( buf, \"<\" );\n\t\t\tvips_buf_appendf( buf, _( \"imagevec\" ) );\n\t\t\tfor( i = 0; i < n; i++ ) {\n\t\t\t\tvips_buf_appendf( buf, \" <\" );\n\t\t\t\tvips_buf_appendf( buf, \n\t\t\t\t\t_( \"image \\\"%s\\\"\" ),\n\t\t\t\t\tvec[i]->im->filename );\n\t\t\t\tvips_buf_appendf( buf, \">\" );\n\t\t\t}\n\t\t\tvips_buf_appends( buf, \"> \" );\n\t\t}\n\n\t\tbreak;\n\t}\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Fill an argument vector from the C stack.\n */\nstatic gboolean\ncall_fillva( CallInfo *vi, va_list *ap )\n{\n\tint i;\n\n\tg_assert( vi->ninii == 0 );\n\tg_assert( vi->noutii == 0 );\n\n\tfor( i = 0; i < vi->fn->argc; i++ ) {\n\t\tim_type_desc *ty = vi->fn->argv[i].desc;\n\n#ifdef DEBUG\n\t\tprintf( \"call_fillva: arg[%d] (%s) = \", i, ty->type );\n#endif /*DEBUG*/\n\n\t\tif( call_type_makes_output( ty ) ) {\n\t\t\tif( !call_build_output( vi, i ) )\n\t\t\t\treturn( FALSE );\n#ifdef DEBUG\n\t\t\tprintf( \" output\\n\" );\n#endif /*DEBUG*/\n\t\t}\n\n\t\tif( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 ) {\n\t\t\t/* DISPLAY argument ... just IM_TYPE_sRGB.\n\t\t\t */\n\t\t\tvi->vargv[i] = im_col_displays( 7 );\n\n#ifdef DEBUG\n\t\t\tprintf( \" display\\n\" );\n#endif /*DEBUG*/\n\t\t}\n\n\t\tif( call_type_needs_input( ty ) ) {\n\t\t\tif( !call_build_inputva( vi, i, ap ) )\n\t\t\t\treturn( FALSE );\n\t\t}\n\t}\n\n\t/* Every output ii depends upon all of the input ii.\n\t */\n\tfor( i = 0; i < vi->noutii; i++ ) \n\t\tmanaged_sub_add_all( MANAGED( vi->outii[i] ), \n\t\t\tvi->ninii, (Managed **) vi->inii );\n\n#ifdef DEBUG\n\tprintf( \"call_fill_spine: reffed %d in\\n\", vi->ninii );\n\tprintf( \"call_fill_spine: created %d out\\n\", vi->noutii );\n#endif /*DEBUG*/\n\n\treturn( TRUE );\n}\n\nstatic gboolean\ncallva_sub( Reduce *rc, const char *name, PElement *out, va_list *ap )\n{\n\tCallInfo *vi;\n\tgboolean result;\n\n\tif( trace_flags & TRACE_VIPS ) \n\t\ttrace_push();\n\n\tif( !(vi = call_new( rc, im_find_function( name ) )) )\n\t\treturn( FALSE );\n\n\tif( trace_flags & TRACE_VIPS ) \n\t\tvips_buf_appendf( trace_current(), \"\\\"%s\\\" \", vi->name );\n\n\tresult = TRUE;\n\n\tif( !call_fillva( vi, ap ) )\n\t\tresult = FALSE;\n\n\tif( trace_flags & TRACE_VIPS ) \n\t\tvips_buf_appends( trace_current(), \" ->\\n\" ); \n\n\tif( result && (\n\t\t!(vi = cache_dispatch( vi, out )) ||\n\t\t!call_write_result( vi, out ) ) )  \n\t\tresult = FALSE;\n\n\tif( trace_flags & TRACE_VIPS ) {\n\t\ttrace_result( TRACE_VIPS, out );\n\t\ttrace_pop();\n\t}\n\n\tif( vi ) {\n\t\t/* We must drop refs explicitly, since this unref might not\n\t\t * dispose the vi.\n\t\t */\n\t\tcall_drop_refs( vi );\n\n\t\tg_object_unref( vi );\n\t}\n\n\treturn( result );\n}\n\n/* Call a CALL function picking up args from the function call.\n */\nvoid\ncallva( Reduce *rc, PElement *out, const char *name, ... )\n{\n\tva_list ap;\n\tgboolean result;\n\n#ifdef DEBUG\n\tprintf( \"** callva: starting for %s\\n\", name );\n#endif /*DEBUG*/\n\n        va_start( ap, name );\n\tresult = callva_sub( rc, name, out, &ap );\n        va_end( ap );\n\n#ifdef DEBUG\n\tprintf( \"callva: done\\n\" );\n#endif /*DEBUG*/\n\n\tif( !result )\n\t\treduce_throw( rc );\n}\n\n/* Fill an argument vector from our stack frame. Number of args already\n * checked. \n */\nstatic gboolean\ncall_fill_spine( CallInfo *vi, HeapNode **arg )\n{\n\tint i, j;\n\n\tg_assert( vi->ninii == 0 );\n\tg_assert( vi->noutii == 0 );\n\n\t/* Fully reduce all arguments. Once we've done this, we can be sure\n\t * there will not be a GC while we gather, and therefore that no\n\t * pointers will become invalid during this call.\n\t */\n\tfor( i = 0; i < vi->nargs; i++ ) {\n\t\tPElement rhs;\n\n\t\tPEPOINTRIGHT( arg[i], &rhs );\n\t\tif( !heap_reduce_strict( &rhs ) )\n\t\t\treturn( FALSE );\n\t}\n\n\tfor( j = 0, i = 0; i < vi->fn->argc; i++ ) {\n\t\tim_type_desc *ty = vi->fn->argv[i].desc;\n\n\t\tif( call_type_makes_output( ty ) ) \n\t\t\tif( !call_build_output( vi, i ) )\n\t\t\t\treturn( FALSE );\n\n\t\tif( strcmp( ty->type, IM_TYPE_DISPLAY ) == 0 ) {\n\t\t\t/* Special DISPLAY argument - don't fetch another ip\n\t\t\t * argument for it.\n\t\t\t */\n\t\t\t(void) call_fromip( vi, i, NULL );\n\t\t}\n\n\t\tif( call_type_needs_input( ty ) ) {\n\t\t\tPElement rhs;\n\n\t\t\t/* Convert ip type to CALL type.\n\t\t\t */\n\t\t\tPEPOINTRIGHT( arg[vi->nargs - j - 1], &rhs );\n\t\t\tif( !call_fromip( vi, i, &rhs ) ) {\n\t\t\t\tcall_error_arg( vi, arg, j );\n\t\t\t\treturn( FALSE );\n\t\t\t}\n\n\t\t\tj += 1;\n\t\t}\n\t}\n\n\t/* Every output ii depends upon all of the input ii.\n\t */\n\tfor( i = 0; i < vi->noutii; i++ ) \n\t\tmanaged_sub_add_all( MANAGED( vi->outii[i] ), \n\t\t\tvi->ninii, (Managed **) vi->inii );\n\n#ifdef DEBUG\n\tprintf( \"call_fill_spine: reffed %d inii\\n\", vi->ninii );\n\tprintf( \"call_fill_spine: created %d outii\\n\", vi->noutii );\n#endif /*DEBUG*/\n\n\treturn( TRUE );\n}\n\nstatic gboolean\ncall_spine_sub( Reduce *rc, const char *name, im_function *fn,\n\tPElement *out, HeapNode **arg )\n{\n\tCallInfo *vi;\n\tgboolean result;\n\n#ifdef DEBUG\n\tprintf( \"** call_spine: starting for %s\\n\", name );\n#endif /*DEBUG*/\n\n\tif( !(vi = call_new( rc, fn )) )\n\t\treturn( FALSE );\n\n\tif( trace_flags & TRACE_VIPS ) {\n\t\tVipsBuf *buf = trace_push();\n\n\t\tvips_buf_appendf( buf, \"\\\"%s\\\" \", name );\n\t\ttrace_args( arg, vi->nargs );\n\t}\n\n\tresult = TRUE;\n\n\tif( !call_fill_spine( vi, arg ) ||\n\t\t!(vi = cache_dispatch( vi, out )) ||\n\t\t!call_write_result( vi, out ) )\n\t\tresult = FALSE;\n\n\tif( trace_flags & TRACE_VIPS ) {\n\t\ttrace_result( TRACE_VIPS, out );\n\t\ttrace_pop();\n\t}\n\n\tif( vi ) {\n\t\t/* We must drop refs explicitly, since this unref might not\n\t\t * dispose the vi.\n\t\t */\n\t\tcall_drop_refs( vi );\n\n\t\tg_object_unref( vi );\n\t}\n\n#ifdef DEBUG\n\tprintf( \"call_spine: done\\n\" );\n#endif /*DEBUG*/\n\n\treturn( result );\n}\n\n/* Call a CALL function, pick up args from the graph. \n */\nvoid\ncall_spine( Reduce *rc, const char *name, HeapNode **arg, PElement *out )\n{\n\tif( !call_spine_sub( rc, name, im_find_function( name ), out, arg ) )\n\t\treduce_throw( rc );\n}\n\n/* As an ActionFn.\n */\nvoid\ncall_run( Reduce *rc, Compile *compile,\n\tint op, const char *name, HeapNode **arg, PElement *out,\n\tim_function *function )\n{\n\tif( !call_spine_sub( rc, name, function, out, arg ) )\n\t\treduce_throw( rc );\n}\n"
  },
  {
    "path": "src/call.h",
    "content": "/* Call vips functions from the graph reducer.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with CALL - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n/* Maxiumum number of args to a CALL function.\n */\n#define MAX_CALL_ARGS (100)\n\n/* Maximum length of a vector we pass to INTVEC etc.\n */\n#define MAX_VEC (10000)\n\ntypedef enum _CallArgumentType {\n\tCALL_NONE = -1,\n\tCALL_DOUBLE = 0,\n\tCALL_INT,\n\tCALL_COMPLEX,\n\tCALL_STRING,\n\tCALL_IMAGE,\n\tCALL_DOUBLEVEC,\n\tCALL_DMASK,\n\tCALL_IMASK,\n\tCALL_IMAGEVEC,\n\tCALL_INTVEC,\n\tCALL_GVALUE,\n\tCALL_INTERPOLATE\n} CallArgumentType;\n\n#define TYPE_CALL_INFO (call_info_get_type())\n#define CALL_INFO( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_CALL_INFO, CallInfo ))\n#define CALL_INFO_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_CALL_INFO, CallInfoClass))\n#define IS_CALL_INFO( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_CALL_INFO ))\n#define IS_CALL_INFO_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_CALL_INFO ))\n#define CALL_INFO_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_CALL_INFO, CallInfoClass ))\n\n/* Stuff we hold about a call to a CALL function.\n */\ntypedef struct _CallInfo {\n\tiObject parent_object;\n\n\t/* Environment.\n\t */\n\tconst char *name;\n\tim_function *fn;\t\t/* Function we call */\n\tReduce *rc;\t\t\t/* RC we run inside */\n\n\t/* Args we build. Images in vargv are IMAGE* pointers.\n\t */\n\tim_object *vargv;\t\t/* vargv we build for CALL */\n\tint nargs;\t\t\t/* Number of args needed from ip */\n\tint nres;\t\t\t/* Number of objects we write back */\n\tint nires;\t\t\t/* Number of images we write back */\n\tint inpos[MAX_CALL_ARGS];\t/* Positions of inputs */\n\tint outpos[MAX_CALL_ARGS];\t/* Positions of outputs */\n\n\t/* Input images. Need to track \"destroy\" on each one (and kill us\n\t * in turn). \n\t *\n\t * RW images are a bit different. These are really output images (we\n\t * create the image that gets passed to the operation, just like\n\t * output images), but it's a \"t\" image and we im_copy() an input to\n\t * it to init it.\n\t *\n\t * So RW images appear in both inii and outii, but we don't look for\n\t * destroy for it.\n\t */\n\tint ninii;\t\t\t\n\tImageinfo *inii[MAX_CALL_ARGS];\t\n\tunsigned int inii_destroy_sid[MAX_CALL_ARGS];\n\tunsigned int inii_invalidate_sid[MAX_CALL_ARGS];\n\n\t/* Output images. \n\t */\n\tint noutii;\n\tImageinfo *outii[MAX_CALL_ARGS];\n\tunsigned int outii_destroy_sid[MAX_CALL_ARGS];\n\n\tgboolean use_lut;\t\t/* TRUE for using a lut */\n\n\t/* Cache hash code here.\n\t */\n\tunsigned int hash;\n\tgboolean found_hash;\n\n\t/* Set if we're in the history cache.\n\t */\n\tgboolean in_cache;\n\n\t/* Set if we hold refs in inii/outii that must be dropped.\n\t */\n\tgboolean must_drop;\n} CallInfo;\n\ntypedef struct _CallInfoClass {\n\tiObjectClass parent_class;\n\n} CallInfoClass;\n\nextern GSList *call_info_all;\n\nCallArgumentType call_lookup_type( im_arg_type type );\nvoid call_error( CallInfo *vi );\nvoid call_error_toomany( CallInfo *vi );\n\nGType call_info_get_type( void );\n\nvoid call_check_all_destroyed( void );\ngboolean call_type_needs_input( im_type_desc *ty );\ngboolean call_type_makes_output( im_type_desc *ty );\n\ngboolean call_is_callable( im_function *fn );\nint call_n_args( im_function *fn );\nvoid call_usage( VipsBuf *buf, im_function *fn );\nvoid call_spine( Reduce *rc, \n\tconst char *name, HeapNode **arg, PElement *out );\nvoid call_run( Reduce *rc, Compile *compile,\n\tint op, const char *name, HeapNode **arg, PElement *out,\n\tim_function *function );\nvoid callva( Reduce *rc, PElement *out, const char *name, ... );\n"
  },
  {
    "path": "src/class.c",
    "content": "/* Class functions ... really part of heap.c, but split out here to make it\n * more manageable.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/*\n#define DEBUG_MEMBER\n#define DEBUG_VERBOSE\n#define DEBUG\n#define DEBUG_BUILD\n */\n\nstatic gboolean\nclass_is_class( PElement *instance )\n{\n\tif( !PEISCLASS( instance ) ) {\n\t\tchar txt[50];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\tif( !itext_value( reduce_context, &buf, instance ) )\n\t\t\treturn( FALSE );\n\t\terror_top( _( \"Bad argument.\" ) );\n\t\terror_sub( _( \"Object %s is not a class.\" ), \n\t\t\tvips_buf_all( &buf ) );\n\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nCompile *\nclass_get_compile( PElement *instance )\n{\n\tif( !class_is_class( instance ) )\n\t\treturn( NULL );\n\n\treturn( PEGETCLASSCOMPILE( instance ) );\n}\n\n/* Look up \"super\" in a class ... try to do it quickly.\n */\ngboolean\nclass_get_super( PElement *instance, PElement *out )\n{\n\tCompile *compile;\n\n\tif( !(compile = class_get_compile( instance )) )\n\t\treturn( FALSE );\n\tg_assert( compile->super );\n\n\treturn( class_get_symbol( instance, compile->super, out ) );\n}\n\nvoid *\nclass_map( PElement *instance, class_map_fn fn, void *a, void *b )\n{\n\tPElement member;\n\tHeapNode *p;\n\n\tif( !PEISCLASS( instance ) ) \n\t\treturn( NULL );\n\n\t/* Loop over the instance member list.\n\t */\n\tPEGETCLASSMEMBER( &member, instance );\n\tif( !PEISELIST( &member ) )\n\t\tfor( p = PEGETVAL( &member ); p; p = GETRIGHT( p ) ) {\n\t\t\tHeapNode *hn;\n\t\t\tPElement s, v;\n\t\t\tSymbol *sym;\n\t\t\tvoid *result;\n\n\t\t\t/* Get the sym/value pair, get the sym.\n\t\t\t */\n\t\t\thn = GETLEFT( p );\n\t\t\tPEPOINTLEFT( hn, &s );\n\t\t\tPEPOINTRIGHT( hn, &v );\n\t\t\tsym = PEGETSYMREF( &s );\n\n\t\t\tif( (result = fn( sym, &v, a, b )) )\n\t\t\t\treturn( result );\n\n\t\t}\n\n\treturn( NULL );\n}\n\n/* Look up a member in a class instance by name. If lookup fails in this \n * instance, try the superclass. Don't search secrets. Point sym and value \n * at the symbol we found and its value. sym can be NULL for no result\n * required.\n */\ngboolean\nclass_get_member( PElement *instance, const char *name, \n\tSymbol **sym_out, PElement *out )\n{\n\tPElement member;\n\tPElement super;\n\tHeapNode *p;\n\n#ifdef DEBUG_MEMBER\n\tprintf( \"class_get_member: looking up \\\"%s\\\" in class \", name );\n\tpgraph( instance );\n#endif /*DEBUG_MEMBER*/\n\n\tif( !class_is_class( instance ) )\n\t\treturn( FALSE );\n\n\t/* Search this instance member list.\n\t */\n\tPEGETCLASSMEMBER( &member, instance );\n\tif( !PEISELIST( &member ) )\n\t\tfor( p = PEGETVAL( &member ); p; p = GETRIGHT( p ) ) {\n\t\t\tHeapNode *hn;\n\t\t\tPElement s;\n\t\t\tSymbol *sym;\n\n\t\t\t/* Get the sym/value pair, get the sym.\n\t\t\t */\n\t\t\thn = GETLEFT( p );\n\t\t\tPEPOINTLEFT( hn, &s );\n\n\t\t\t/* Match? \n\t\t\t */\n\t\t\tsym = PEGETSYMREF( &s );\n\t\t\tif( strcmp( IOBJECT( sym )->name, name ) == 0 ) {\n\t\t\t\t/* Found!\n\t\t\t\t */\n\t\t\t\tPEPOINTRIGHT( hn, out );\n\t\t\t\tif( sym_out )\n\t\t\t\t\t*sym_out = sym;\n\n#ifdef DEBUG_MEMBER\n\t\t\t\tprintf( \"class_get_member: found: \" );\n\t\t\t\tpgraph( out );\n#endif /*DEBUG_MEMBER*/\n\n\t\t\t\treturn( TRUE );\n\t\t\t}\n\t\t}\n\n\t/* Nope ... try the superclass.\n\t */\n\tif( !class_get_super( instance, &super ) || !PEISELIST( &super ) ) {\n\t\t/*\n\n\t\t\tFIXME ... gcc 2.95.2 gets this wrong, tries to\n\t\t\t\t  eliminate the tail recursion with -O2\n\t\t\t\t  and makes bad code\n\t\t\t      ... guess how long that took to find\n\t\t\t      ... put this back at some point\n\n\t\treturn( class_get_member( &super, name, sym_out, value ) ); \n\t\t */\n\t\tgboolean result = class_get_member( &super, name, \n\t\t\tsym_out, out ); \n\n\t\treturn( result );\n\t}\n\n\terror_top( _( \"Member not found.\" ) );\n\terror_sub( _( \"Member \\\"%s\\\" not found in class \\\"%s\\\".\" ),\n\t\tname, IOBJECT( PEGETCLASSCOMPILE( instance )->sym )->name );\n\n\treturn( FALSE );\n}\n\n/* Look up a symbol in a class. Write to out, or FALSE for not found. Look up \n * by symbol pointer. Search secrets as well. Try the superclass if lookup \n * fails.\n */\ngboolean\nclass_get_symbol( PElement *instance, Symbol *sym, PElement *out )\n{\n\tHeapNode *p;\n\tPElement secret;\n\tPElement super;\n\n#ifdef DEBUG_MEMBER\n\tprintf( \"class_get_symbol: looking up \" );\n\tsymbol_name_print( sym );\n\tprintf( \"in class \" );\n\tpgraph( instance );\n#endif /*DEBUG_MEMBER*/\n\n\tif( !class_is_class( instance ) )\n\t\treturn( FALSE );\n\n\tPEGETCLASSSECRET( &secret, instance );\n\tif( PEISNODE( &secret ) )\n\t\tfor( p = PEGETVAL( &secret ); p; p = GETRIGHT( p ) ) {\n\t\t\tPElement s;\n\t\t\tHeapNode *hn;\n\n\t\t\t/* Get the sym/value pair, get the sym.\n\t\t\t */\n\t\t\thn = GETLEFT( p );\n\t\t\tPEPOINTLEFT( hn, &s );\n\n\t\t\t/* Match?\n\t\t\t */\n\t\t\tif( PEGETSYMREF( &s ) == sym ) {\n\t\t\t\t/* Found!\n\t\t\t\t */\n\t\t\t\tPEPOINTRIGHT( hn, out );\n\n#ifdef DEBUG_MEMBER\n\t\t\t\tprintf( \"class_get_symbol: found: \" );\n\t\t\t\tpgraph( out );\n#endif /*DEBUG_MEMBER*/\n\n\t\t\t\treturn( TRUE );\n\t\t\t}\n\t\t}\n\n\t/* Nope ... try the superclass.\n\t */\n\tif( !class_get_super( instance, &super ) || !PEISELIST( &super ) ) {\n\t\t/*\n\n\t\t\tFIXME ... gcc 2.95.2 gets this wrong, tries to\n\t\t\t\t  eliminate the tail recursion with -O2\n\t\t\t\t  and makes bad code\n\t\t\t      ... guess how long that took to find\n\t\t\t      ... put this back at some point\n\n\t\treturn( class_get_member( &super, name, out ) ); \n\t\t */\n\t\tgboolean result = class_get_symbol( &super, sym, out ); \n\n\t\treturn( result );\n\t}\n\n\treturn( FALSE );\n}\n\n/* Search back up the inheritance tree for an exact instance of this\n * class.\n */\ngboolean\nclass_get_exact( PElement *instance, const char *name, PElement *out )\n{\n\tPElement pe;\n\n\tpe = *instance;\n\twhile( !reduce_is_instanceof_exact( reduce_context, name, &pe ) ) {\n\t\tif( !class_get_super( &pe, &pe ) || PEISELIST( &pe ) ) \n\t\t\treturn( FALSE );\n\t}\n\n\t*out = pe;\n\n\treturn( TRUE );\n}\n\n/* Stuff we need for class build.\n */\ntypedef struct {\n\tHeap *heap;\t\t/* Heap to build on */\n\tSymbol *sym;\t\t/* Sym we are local to */\n\tPElement *arg;\t\t/* Args to constructor */\n\tPElement *this;\t\t/* Base of instance we are building */\n\tint i;\t\t\t/* Index in arg list */\n\tCompile *compile;\t/* Compile for our class */\n} ClassBuildInfo;\n\n/* Member sym of class pbi->sym needs secret as an argument ... add it!\n */\nstatic gboolean\nclass_member_secret( ClassBuildInfo *pbi, \n\tSymbol *sym, GSList *secret, PElement *out )\n{\n\tSymbol *ssym;\n\tHeap *heap = pbi->heap;\n\tHeapNode *apl;\n\n\tif( !secret )\n\t\treturn( TRUE );\n\tssym = SYMBOL( secret->data );\n\n\t/* Make function application for this member.\n\t */\n\tif( NEWNODE( heap, apl ) )\n\t\treturn( FALSE );\n\tapl->type = TAG_APPL;\n\tPEPUTLEFT( apl, out );\n\n\t/* Is the secret \"this\"? Easy.\n\t */\n\tif( ssym == pbi->sym->expr->compile->this ) {\n\t\tPEPUTRIGHT( apl, pbi->this );\n\t}\n\telse {\n\t\t/* Look up ssym in pbi->sym's secrets ... should be there \n\t\t * somewhere. Use it's index to find the pbi->arg[] we need.\n\t\t */\n\t\tint pos = g_slist_index( \n\t\t\tpbi->sym->expr->compile->secret, ssym );\n\n\t\t/* FIXME ... may not be if we've regenerated one of these\n\t\t * stupid things :-( change this so we always go through \n\t\t * 'this'.\n\t\t */\n\t\tif( pos < 0 || pos >= pbi->sym->expr->compile->nsecret ) {\n\t\t\terror_top( _( \"No such secret.\" ) );\n\t\t\terror_sub( _( \"Editing local classes which reference \"\n\t\t\t\t\"non-local objects is a bit broken at the \"\n\t\t\t\t\"moment :-(\" ) );\n\t\t\treturn( FALSE );\n\t\t}\n\n\t\tPEPUTRIGHT( apl, \n\t\t\t&pbi->arg[pbi->sym->expr->compile->nsecret - pos - 1] );\n\t}\n\n\tPEPUTP( out, ELEMENT_NODE, apl );\n\n#ifdef DEBUG_VERBOSE\n{\n\tPElement p1;\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tPEPOINTRIGHT( apl, &p1 );\n\tgraph_pelement( pbi->heap, &buf, &p1, TRUE );\n\tprintf( \"class_member_secret: secret arg \" );\n\tsymbol_name_print( ssym );\n\tprintf( \"to member \" );\n\tsymbol_name_print( sym );\n\tprintf( \"= %s\\n\", vips_buf_all( &buf ) );\n}\n#endif /*DEBUG_VERBOSE*/\n\n\treturn( class_member_secret( pbi, sym, secret->next, out ) );\n}\n\n/* Add a member to a class.\n */\nstatic void *\nadd_class_member( Symbol *sym, ClassBuildInfo *pbi, PElement *out )\n{\n\tHeap *heap = pbi->heap;\n\tHeapNode *base, *sv;\n\tPElement v;\n\n\t/* Is this something that should be part of a class.\n\t */\n\tif( sym->type != SYM_VALUE )\n\t\treturn( NULL );\n\n\t/* Make new class-local-list element for this local.\n\t */\n\tif( NEWNODE( heap, base ) )\n\t\treturn( sym );\n\tbase->type = TAG_CONS;\n\tPPUTLEFT( base, ELEMENT_ELIST, NULL );\n\tPEPUTRIGHT( base, out );\n\tPEPUTP( out, ELEMENT_NODE, base );\n\n\t/* Make sym/value pair for this local.\n\t */\n\tif( NEWNODE( heap, sv ) )\n\t\treturn( sym );\n\tsv->type = TAG_CONS;\n\tPPUT( sv, ELEMENT_SYMREF, sym, ELEMENT_SYMBOL, sym ); \n\tPPUTLEFT( base, ELEMENT_NODE, sv );\n\n\t/* Build value ... apply args to the symbol.\n\t */\n\tPEPOINTRIGHT( sv, &v );\n\tif( !class_member_secret( pbi, sym, sym->expr->compile->secret, &v ) )\n\t\treturn( sym );\n\n#ifdef DEBUG_VERBOSE\n{\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_pelement( heap, &buf, &v, TRUE );\n\tprintf( \"add_class_member: member \\\"%s\\\" of class \\\"%s\\\" = %s\\n\",\n\t\tIOBJECT( sym )->name, IOBJECT( pbi->sym )->name, \n\t\tvips_buf_all( &buf ) );\n}\n#endif /*DEBUG_VERBOSE*/\n\n\treturn( NULL );\n}\n\n/* Add a symbol/value pair to a class.\n */\nstatic gboolean\nadd_class_svpair( ClassBuildInfo *pbi, \n\tSymbol *sym, PElement *val, PElement *out )\n{\n\tHeap *heap = pbi->heap;\n\tHeapNode *base, *sv;\n\n#ifdef DEBUG_VERBOSE\n{\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_pelement( heap, &buf, val, TRUE );\n\tprintf( \"add_class_svpair: adding parameter \\\"%s\\\" to class \"\n\t\t\"\\\"%s\\\" = %s\\n\", \n\t\tIOBJECT( sym )->name, IOBJECT( pbi->sym )->name,\n\t\tvips_buf_all( &buf ) );\n}\n#endif /*DEBUG_VERBOSE*/\n\n\t/* Make new class-local-list element for this parameter.\n\t */\n\tif( NEWNODE( heap, base ) )\n\t\treturn( FALSE );\n\tbase->type = TAG_CONS;\n\tPPUTLEFT( base, ELEMENT_ELIST, NULL );\n\tPEPUTRIGHT( base, out );\n\tPEPUTP( out, ELEMENT_NODE, base );\n\n\t/* Make sym/value pair for this parameter.\n\t */\n\tif( NEWNODE( heap, sv ) )\n\t\treturn( FALSE );\n\tsv->type = TAG_CONS;\n\tPPUTLEFT( sv, ELEMENT_SYMREF, sym )\n\tPEPUTRIGHT( sv, val );\n\tPPUTLEFT( base, ELEMENT_NODE, sv );\n\n\treturn( TRUE );\n}\n\n/* Add a parameter (secret or real) to a class.\n */\nstatic void *\nadd_class_parameter( Symbol *sym, ClassBuildInfo *pbi, PElement *out )\n{\n\t/* Add this symbol/value pair.\n\t */\n\tif( !add_class_svpair( pbi, sym, &pbi->arg[pbi->i], out ) )\n\t\treturn( sym );\n\n\t/* Move arg index on.\n\t */\n\tpbi->i += 1;\n\n\treturn( NULL );\n}\n\n/* Add the name member ... build the name string carefully.\n */\nstatic void *\nclass_new_single_name( Heap *heap, PElement *pe,\n\tClassBuildInfo *pbi, PElement *instance )\n{\n\tSymbol *snm = compile_lookup( pbi->compile, MEMBER_NAME );\n\tchar txt[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t/* Make class name string.\n\t */\n\tsymbol_qualified_name( pbi->sym, &buf );\n\tPEPUTP( pe, ELEMENT_ELIST, NULL );\n\tif( !heap_managedstring_new( heap, vips_buf_all( &buf ), pe ) ) \n\t\treturn( heap );\n\n\t/* Add as a member.\n\t */\n\tif( !add_class_svpair( pbi, snm, pe, instance ) ) \n\t\treturn( heap );\n\n\treturn( NULL );\n}\n\n/* Make a single level class instance ... fn below then loops over a class\n * hierarchy with this.\n */\nstatic gboolean\nclass_new_single( Heap *heap, \n\tCompile *compile, PElement *arg, PElement *this, PElement *out )\n{\n\tSymbol *sym = compile->sym;\n\tSymbol *sths = compile->this;\n\n\tHeapNode *base, *sm;\n\tPElement p1;\n\tClassBuildInfo pbi;\n\n#ifdef DEBUG\n{\n\tint i;\n\n\tprintf( \"class_new_single: starting for \" );\n\tsymbol_name_print( sym );\n\tprintf( \"%d secrets, %d params\\n\", \n\t\tcompile->nsecret, compile->nparam );\n\n\tfor( i = 0; i < compile->nsecret; i++ ) {\n\t\tchar txt[256];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\tgraph_pelement( heap, &buf, &arg[i], TRUE );\n\t\tprintf( \"\\tsecret %2d = %s\\n\", i, vips_buf_all( &buf ) );\n\t}\n\n\tfor( i = 0; i < compile->nparam; i++ ) {\n\t\tchar txt[256];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\tgraph_pelement( heap, &buf, &arg[i + compile->nsecret], TRUE );\n\t\tprintf( \"\\targ %2d = %s\\n\", i, vips_buf_all( &buf ) );\n\t}\n}\n#endif /*DEBUG*/\n\n\t/* Make class base.\n\t */\n\tif( NEWNODE( heap, base ) )\n\t\treturn( FALSE );\n\tbase->type = TAG_CLASS;\n\tPPUT( base, ELEMENT_COMPILEREF, compile, ELEMENT_ELIST, NULL ); \n\tPEPUTP( out, ELEMENT_NODE, base );\n\n\t/* Make node for holding secrets and members.\n\t */\n\tif( NEWNODE( heap, sm ) )\n\t\treturn( FALSE );\n\tsm->type = TAG_CONS;\n\tPPUT( sm, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL ); \n\tPPUTRIGHT( base, ELEMENT_NODE, sm );\n\n\t/* Build list of members.\n\t */\n\tpbi.heap = heap;\n\tpbi.sym = sym;\n\tpbi.arg = arg;\n\tpbi.this = this;\n\tpbi.compile = compile;\n\tPEPOINTRIGHT( sm, &p1 );\n\tif( icontainer_map_rev( ICONTAINER( compile ), \n\t\t(icontainer_map_fn) add_class_member, &pbi, &p1 ) ) \n\t\treturn( FALSE );\n\n\t/* Add name member.\n\t */\n\tif( heap_safe_pointer( heap,\n\t\t(heap_safe_pointer_fn) class_new_single_name, \n\t\t&pbi, &p1, NULL, NULL ) )\n\t\treturn( FALSE );\n\n\t/* Add this member.\n\t */\n\tif( !add_class_svpair( &pbi, sths, this, &p1 ) )\n\t\treturn( FALSE );\n\n\t/* Add class parameters to member list.\n\t */\n\tpbi.i = 0;\n\tif( slist_map2_rev( compile->param, \n\t\t(SListMap2Fn) add_class_parameter, &pbi, &p1 ) )\n\t\treturn( FALSE );\n\n\t/* Now ... secret list starts off pointing to head of member list.\n\t */\n\tPEPUTLEFT( sm, &p1 );\n\n\t/* Add all secret parameters to secret list.\n\t */\n\tPEPOINTLEFT( sm, &p1 );\n\tif( slist_map2_rev( compile->secret, \n\t\t(SListMap2Fn) add_class_parameter, &pbi, &p1 ) )\n\t\treturn( FALSE );\n\n#ifdef DEBUG\n{\n\tchar txt[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_pelement( heap, &buf, out, TRUE );\n\tprintf( \"class_new_single: built instance of \" );\n\tsymbol_name_print( sym );\n\tprintf( \":\\n%s\\n\", vips_buf_all( &buf ) );\n}\n#endif /*DEBUG*/\n\n\treturn( TRUE );\n}\n\n/* Look at a scrap of graph and try to find a constructor it might be using.\n * This will only work for really basic functions :-( but it's enough to allow\n * us to pass extra secrets through the superclass. Used by (eg.) Colour when\n * it overrides Value and adds the colourspace arg.\n */\nstatic Compile *\nclass_guess_constructor( PElement *fn )\n{\n\tif( PEISCONSTRUCTOR( fn ) ) \n\t\treturn( PEGETCOMPILE( fn ) );\n\telse if( PEISNODE( fn ) ) {\n\t\tHeapNode *hn = PEGETVAL( fn );\n\n\t\tif( hn->type == TAG_APPL ) {\n\t\t\tPElement left;\n\n\t\t\tPEPOINTLEFT( hn, &left );\n\n\t\t\treturn( class_guess_constructor( &left ) );\n\t\t}\n\t}\n\n\treturn( NULL );\n}\n\n/* Look at arg0 and try to extract the arguments (all the RHS of the @ nodes).\n * Return the number of args we found, or -1 if we find crazy stuff.\n */\nstatic int\nclass_guess_args( PElement arg[], PElement *fn )\n{\n\tif( PEISCONSTRUCTOR( fn ) )\n\t\treturn( 0 );\n\telse if( PEISNODE( fn ) ) {\n\t\tPElement left;\n\t\tint i;\n\n\t\tPEPOINTLEFT( PEGETVAL( fn ), &left );\n\t\tif( (i = class_guess_args( arg, &left )) == -1 )\n\t\t\treturn( -1 );\n\t\tif( i >= MAX_SYSTEM ) {\n\t\t\terror_top( _( \"Too many arguments.\" ) );\n\t\t\terror_sub( _( \"You can't have more than %d \"\n\t\t\t\t\"arguments to a superclass constructor.\" ),\n\t\t\t\tMAX_SYSTEM );\n\n\t\t\treturn( -1 );\n\t\t}\n\n\t\tPEPOINTRIGHT( PEGETVAL( fn ), &arg[i] );\n\n\t\treturn( i + 1 );\n\t}\n\telse\n\t\treturn( -1 );\n}\n\nstatic void *\nclass_new_super_sub( Heap *heap, PElement *p1,\n\tCompile *compile, PElement *arg, PElement *this, PElement *super )\n{\n\t/* Build the superclass ... we overwrite the super \n\t * list with the constructed class, so make a copy of \n\t * the pointer to stop it being GCed.\n\t */\n\tPEPUTPE( p1, super );\n\n\tif( !class_new_single( heap, compile, arg, this, super ) ) \n\t\treturn( heap );\n\n\treturn( NULL );\n}\n\n/* Clone a class instance. Copy pointers to the the args, secrets and super; \n * rebuild with the specified \"this\". Instance and out can be equal.\n */\nstatic gboolean\nclass_clone_super( Heap *heap, Compile *compile,\n\tPElement *instance, PElement *this, PElement *out )\n{\n\tPElement arg[MAX_SYSTEM];\n\tconst int nargs = compile->nsecret + compile->nparam;\n\tPElement secret;\n\tint i;\n\n\tg_assert( nargs <= MAX_SYSTEM );\n\n#ifdef DEBUG_VERBOSE\n{\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_pelement( heap, &buf, instance, TRUE );\n\tprintf( \"class_new_clone: about to clone \\\"%s\\\": %s\\n\", \n\t\tIOBJECT( compile->sym )->name, vips_buf_all( &buf ) );\n}\n#endif /*DEBUG_VERBOSE*/\n\n\t/* Pull out values of secrets and class args into arg[].\n\t */\n\tPEGETCLASSSECRET( &secret, instance );\n\tfor( i = 0; i < nargs; i++ ) {\n\t\tHeapNode *hn = PEGETVAL( &secret );\n\t\tHeapNode *sv = GETLEFT( hn );\n\t\tint index = nargs - i - 1;\n\n\t\tPEPOINTRIGHT( sv, &arg[index] );\n\t\tPEPOINTRIGHT( hn, &secret );\n\t}\n\n\t/* Build class again.\n\t */\n\treturn( class_new_single( heap, compile, arg, this, out ) );\n}\n\nstatic void *\nclass_clone_super_sub( Heap *heap, PElement *p1,\n\tCompile *compile, PElement *instance, PElement *this, PElement *out )\n{\n\t/* instance and out can point to the same node, so save a pointer to  \n\t * instance to stop it being GCed.\n\t */\n\tPEPUTPE( p1, instance );\n\n\tif( !class_clone_super( heap, compile, instance, this, out ) ) \n\t\treturn( heap );\n\n\treturn( NULL );\n}\n\n/* Does this class have a \"super\"? Build it and recurse.\n */\ngboolean\nclass_new_super( Heap *heap, \n\tCompile *compile, PElement *this, PElement *instance )\n{\n\tPElement super;\n\n\tif( compile->has_super && class_get_super( instance, &super ) ) {\n\t\tCompile *super_compile;\n\t\tint len, fn_len;\n\t\tPElement arg0;\n\n\t\t/* It must be a list whose first element is the superclass\n\t\t * constructor, or a partially parameterised constructor, or \n\t\t * the superclass itself (if it has already\n\t\t * been constructed, or has no args). Other elements in the\n\t\t * list are the remaining args.\n\t\t *\n\t\t * We keep the list form, since we want to not build the\n\t\t * superclass until now if we can help it ... otherwise we\n\t\t * have to construct once, then construct again when we clone.\n\t\t */\n\t\tif( (len = heap_list_length( &super )) < 1 ||\n\t\t\t!heap_list_index( &super, 0, &arg0 ) ||\n\t\t\t!heap_reduce_strict( &arg0 ) )\n\t\t\treturn( FALSE );\n\n\t\tif( (super_compile = class_guess_constructor( &arg0 )) ) {\n\t\t\tPElement fn_arg[MAX_SYSTEM];\n\t\t\tPElement arg[MAX_SYSTEM];\n\t\t\tint i;\n\n\t\t\t/* How many function args are there? \n\t\t\t */\n\t\t\tif( (fn_len = class_guess_args( fn_arg, &arg0 )) < 0 )\n\t\t\t\treturn( FALSE );\n\n\t\t\t/* Check total arg count.\n\t\t\t */\n\t\t\tif( super_compile->nsecret != 0 ) {\n\t\t\t\tchar txt[1024];\n\t\t\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\t\t\tslist_map2( super_compile->secret, \n\t\t\t\t\t(SListMap2Fn) symbol_name_error, \n\t\t\t\t\t&buf, NULL );\n\n\t\t\t\terror_top( _( \"Bad superclass.\" ) );\n\t\t\t\terror_sub( _( \"Superclass constructor \\\"%s\\\" \"\n\t\t\t\t\t\"refers to non-local symbols %s\" ),\n\t\t\t\t\tsymbol_name( super_compile->sym ),\n\t\t\t\t\tvips_buf_all( &buf ) );\n\n\t\t\t\treturn( FALSE );\n\t\t\t}\n\t\t\tif( len - 1 + fn_len != super_compile->nparam ) {\n\t\t\t\terror_top( _( \"Wrong number of arguments.\" ) );\n\t\t\t\terror_sub( _( \"Superclass constructor \\\"%s\\\" \"\n\t\t\t\t\t\"expects %d arguments, not %d.\" ),\n\t\t\t\t\tsymbol_name( super_compile->sym ),\n\t\t\t\t\tsuper_compile->nparam,\n\t\t\t\t\tlen - 1 + fn_len );\n\n\t\t\t\treturn( FALSE );\n\t\t\t}\n\n\t\t\t/* Grab the explicit args from the super list.\n\t\t\t */\n\t\t\tfor( i = 0; i < len - 1; i++ ) {\n\t\t\t\tif( !heap_list_index( &super, len - 1 - i, \n\t\t\t\t\t&arg[i] ) ) \n\t\t\t\t\treturn( FALSE );\n\t\t\t}\n\n\t\t\t/* Append the function args, but reverse them as we\n\t\t\t * go so we get most-nested arg last.\n\t\t\t */\n\t\t\tfor( i = 0; i < fn_len; i++ )\n\t\t\t\targ[i + len - 1] = fn_arg[fn_len - 1 - i];\n\n\t\t\t/* Build the superclass ... we overwrite the super \n\t\t\t * list with the constructed class, so make a copy of \n\t\t\t * the pointer to stop it being GCed.\n\t\t\t */\n\t\t\tif( heap_safe_pointer( heap, \n\t\t\t\t(heap_safe_pointer_fn) class_new_super_sub,\n\t\t\t\tsuper_compile, arg, this, &super ) )\n\t\t\t\treturn( FALSE );\n\n\t\t}\n\t\telse if( PEISCLASS( &arg0 ) ) {\n\t\t\t/* Super is a constructed class ... clone it, but with\n\t\t\t * our \"this\" in there. Slow, but useful.\n\t\t\t */\n\t\t\tsuper_compile = PEGETCLASSCOMPILE( &arg0 );\n\n\t\t\tif( heap_safe_pointer( heap, \n\t\t\t\t(heap_safe_pointer_fn) class_clone_super_sub,\n\t\t\t\tsuper_compile, &arg0, this, &super ) )\n\t\t\t\treturn( FALSE );\n\t\t}\n\t\telse {\n\t\t\tchar txt1[300];\n\t\t\tVipsBuf buf1 = VIPS_BUF_STATIC( txt1 );\n\t\t\tchar txt2[300];\n\t\t\tVipsBuf buf2 = VIPS_BUF_STATIC( txt2 );\n\n\t\t\terror_top( _( \"Bad superclass.\" ) );\n\n\t\t\titext_value( reduce_context, &buf1, &arg0 );\n\t\t\tvips_buf_appendf( &buf2,\n\t\t\t\t_( \"First element in superclass of \\\"%s\\\" \"\n\t\t\t\t\"must be class or constructor.\" ),\n\t\t\t\tsymbol_name( compile->sym ) );\n\t\t\tvips_buf_appendf( &buf2, \"\\n\" );\n\t\t\tvips_buf_appendf( &buf2, _( \"You passed:\" ) );\n\t\t\terror_sub( \"%s\\n  %s\", \n\t\t\t\tvips_buf_all( &buf2 ), vips_buf_all( &buf1 ) );\n\n\t\t\treturn( FALSE );\n\t\t}\n\n\t\t/* And recursively build any superclasses.\n\t\t */\n\t\tif( !class_new_super( heap, super_compile, this, &super ) )\n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Make a class instance. \n */\ngboolean\nclass_new( Heap *heap, Compile *compile, HeapNode **arg, PElement *out )\n{\n\tint i;\n\tPElement pe_arg[MAX_SYSTEM];\n\n\t/* Make a set of arg pointers.\n\t */\n\tif( compile->nparam + compile->nsecret >= MAX_SYSTEM ) {\n\t\terror_top( _( \"Too many arguments.\" ) );\n\t\terror_sub( _( \"Too many arguments to class constructor \\\"%s\\\". \"\n\t\t\t\"No more than %d arguments are supported.\" ),\n\t\t\tsymbol_name( compile->sym ), MAX_SYSTEM );\n\t\treturn( FALSE );\n\t}\n\tfor( i = 0; i < compile->nparam + compile->nsecret; i++ ) {\n\t\tPEPOINTRIGHT( arg[i], &pe_arg[i] );\n\t}\n\n\t/* Build the base instance.\n\t */\n\tif( !class_new_single( heap, compile, pe_arg, out, out ) )\n\t\treturn( FALSE );\n\n\t/* And recursively build any superclasses.\n\t */\n\tif( !class_new_super( heap, compile, out, out ) )\n\t\treturn( FALSE );\n\n#ifdef DEBUG_BUILD\n{\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_pelement( heap, &buf, out, TRUE );\n\tprintf( \"class_new: built instance of \\\"%s\\\": %s\\n\", \n\t\tIOBJECT( compile->sym )->name, vips_buf_all( &buf ) );\n}\n#endif /*DEBUG_BUILD*/\n\n\treturn( TRUE );\n}\n\n/* Clone a class instance. Copy pointers to the the args, secrets and super; \n * regenerate all the members. instance and out can be equal.\n */\ngboolean\nclass_clone_args( Heap *heap, PElement *instance, PElement *out )\n{\n\tHeapNode *arg[MAX_SYSTEM];\n\tCompile *compile = PEGETCLASSCOMPILE( instance );\n\tconst int nargs = compile->nsecret + compile->nparam;\n\tPElement secret;\n\tint i;\n\n\tg_assert( nargs <= MAX_SYSTEM );\n\n#ifdef DEBUG_VERBOSE\n{\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_pelement( heap, &buf, instance, TRUE );\n\tprintf( \"class_clone_args: about to clone \\\"%s\\\": %s\\n\", \n\t\tIOBJECT( compile->sym )->name, vips_buf_all( &buf ) );\n}\n#endif /*DEBUG_VERBOSE*/\n\n\t/* Pull out values of secrets and class args into RHS of arg[].\n\t */\n\tPEGETCLASSSECRET( &secret, instance );\n\tfor( i = 0; i < nargs; i++ ) {\n\t\tHeapNode *hn = PEGETVAL( &secret );\n\t\tHeapNode *sv = GETLEFT( hn );\n\t\tint index = nargs - i - 1;\n\n\t\targ[index] = sv;\n\t\tPEPOINTRIGHT( hn, &secret );\n\t}\n\n\t/* Build class again.\n\t */\n\treturn( class_new( heap, compile, &arg[0], out ) );\n}\n\n/* Build a class instance picking parameters from C args ... handy for\n * making a new toggle instance on a click, for example.\n */\ngboolean\nclass_newv( Heap *heap, const char *name, PElement *out, ... )\n{\n\tva_list ap;\n\tSymbol *sym;\n\tCompile *compile;\n\tHeapNode args[MAX_SYSTEM];\n\tHeapNode *pargs[MAX_SYSTEM];\n\tint i;\n\n\tif( !(sym = compile_lookup( symbol_root->expr->compile, name )) ||\n\t\t!is_value( sym ) || !is_class( sym->expr->compile ) ) {\n\t\terror_top( _( \"Class not found.\" ) );\n\t\terror_sub( _( \"Class \\\"%s\\\" not found.\" ), name );\n\t\treturn( FALSE );\n\t}\n\tcompile = sym->expr->compile;\n\tif( compile->nparam >= MAX_SYSTEM ) {\n\t\terror_top( _( \"Too many arguments.\" ) );\n\t\terror_sub( _( \"Too many arguments to class constructor \\\"%s\\\". \"\n\t\t\t\"No more than %d arguments are supported.\" ),\n\t\t\tsymbol_name( compile->sym ), MAX_SYSTEM );\n\t\treturn( FALSE );\n\t}\n\n        va_start( ap, out );\n\tfor( i = 0; i < compile->nparam; i++ ) {\n\t\tPElement *arg = va_arg( ap, PElement * );\n\t\tPElement rhs;\n\n\t\tpargs[i] = &args[i];\n\t\tPEPOINTRIGHT( pargs[i], &rhs );\n\t\tPEPUTPE( &rhs, arg );\n\t}\n        va_end( ap );\n\n\treturn( class_new( heap, compile, &pargs[0], out ) );\n}\n\nstatic void\nclass_typecheck_error( PElement *instance, const char *name, const char *type )\n{\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tPElement val;\n\n\tvips_buf_appendf( &buf, _( \"Member \\\"%s\\\" of class \\\"%s\\\" \"\n\t\t\"should be of type \\\"%s\\\", instead it's:\" ), \n\t\tname, \n\t\tIOBJECT( PEGETCLASSCOMPILE( instance )->sym )->name, \n\t\ttype );\n\tvips_buf_appends( &buf, \"\\n   \" );\n\tif( class_get_member( instance, name, NULL, &val ) &&\n\t\t!itext_value( reduce_context, &buf, &val ) )\n\t\treturn;\n\n\terror_top( _( \"Bad argument.\" ) );\n\terror_sub( \"%s\", vips_buf_all( &buf ) );\n}\n\n/* A function that gets a type from a class.\n */\ntypedef gboolean (*ClassGetFn)( PElement *, void * );\n\nstatic gboolean\nclass_get_member_check( PElement *instance, const char *name, const char *type,\n\tClassGetFn fn, void *a )\n{\n\tPElement val;\n\n\tif( !class_get_member( instance, name, NULL, &val ) )\n\t\treturn( FALSE );\n\n\tif( !fn( &val, a ) ) {\n\t\tclass_typecheck_error( instance, name, type );\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\ngboolean\nclass_get_member_bool( PElement *instance, const char *name, gboolean *out )\n{\n\treturn( class_get_member_check( instance, name, \"bool\",\n\t\t(ClassGetFn) heap_get_bool, out ) );\n}\n\ngboolean\nclass_get_member_real( PElement *instance, const char *name, double *out )\n{\n\treturn( class_get_member_check( instance, name, \"real\",\n\t\t(ClassGetFn) heap_get_real, out ) );\n}\n\ngboolean\nclass_get_member_int( PElement *instance, const char *name, int *out )\n{\n\tdouble d;\n\n\tif( !class_get_member_check( instance, name, \"real\",\n\t\t(ClassGetFn) heap_get_real, &d ) )\n\t\treturn( FALSE );\n\t*out = IM_RINT( d );\n\n\treturn( TRUE );\n}\n\ngboolean\nclass_get_member_class( PElement *instance, const char *name, \n\tconst char *type, PElement *out )\n{\n\tgboolean result;\n\n\tif( !class_get_member_check( instance, name, type,\n\t\t(ClassGetFn) heap_get_class, out ) )\n\t\treturn( FALSE );\n\n\tif( !heap_is_instanceof( type, out, &result ) ) \n\t\treturn( FALSE );\n\tif( !result ) {\n\t\tclass_typecheck_error( instance, name, type );\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\ngboolean\nclass_get_member_image( PElement *instance, const char *name, Imageinfo **out )\n{\n\treturn( class_get_member_check( instance, name, \"image\",\n\t\t(ClassGetFn) heap_get_image, out ) );\n}\n\ngboolean\nclass_get_member_lstring( PElement *instance, const char *name, \n\tGSList **labels )\n{\n\treturn( class_get_member_check( instance, name, \"finite [[char]]\",\n\t\t(ClassGetFn) heap_get_lstring, labels ) );\n}\n\ngboolean\nclass_get_member_string( PElement *instance, const char *name, \n\tchar *buf, int sz )\n{\n\tPElement val;\n\n\tif( !class_get_member( instance, name, NULL, &val ) )\n\t\treturn( FALSE );\n\n\tif( !heap_get_string( &val, buf, sz ) ) {\n\t\tclass_typecheck_error( instance, name, \"finite [char]\" );\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\ngboolean\nclass_get_member_instance( PElement *instance, \n\tconst char *name, const char *klass, PElement *out )\n{\n\tgboolean result;\n\n\treturn( class_get_member( instance, name, NULL, out ) &&\n\t\theap_is_instanceof( klass, out, &result ) &&\n\t\tresult );\n}\n\ngboolean\nclass_get_member_matrix_size( PElement *instance, const char *name, \n\tint *xsize, int *ysize )\n{\n\tPElement val;\n\n\tif( !class_get_member( instance, name, NULL, &val ) )\n\t\treturn( FALSE );\n\n\tif( !heap_get_matrix_size( &val, xsize, ysize ) ) {\n\t\tclass_typecheck_error( instance, name, \n\t\t\t\"finite rectangular [[real]]\" );\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\ngboolean\nclass_get_member_matrix( PElement *instance, const char *name, \n\tdouble *buf, int n, int *xsize, int *ysize )\n{\n\tPElement val;\n\n\tif( !class_get_member( instance, name, NULL, &val ) )\n\t\treturn( FALSE );\n\n\tif( !heap_get_matrix( &val, buf, n, xsize, ysize ) ) {\n\t\tclass_typecheck_error( instance, name, \n\t\t\t\"finite rectangular [[real]]\" );\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\ngboolean\nclass_get_member_realvec( PElement *instance, const char *name, \n\tdouble *buf, int n, int *length )\n{\n\tPElement val;\n\tint l;\n\n\tif( !class_get_member( instance, name, NULL, &val ) )\n\t\treturn( FALSE );\n\n\tif( (l = heap_get_realvec( &val, buf, n )) < 0 ) {\n\t\tclass_typecheck_error( instance, name, \"finite [real]\" );\n\t\treturn( FALSE );\n\t}\n\n\t*length = l;\n\n\treturn( TRUE );\n}\n"
  },
  {
    "path": "src/class.h",
    "content": "/* Decls for class.c\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* The builtin member names we know about.\n */\n#define MEMBER_BANDS \"bands\"\n#define MEMBER_CAPTION \"caption\"\n#define MEMBER_XCAPTION \"xcaption\"\n#define MEMBER_YCAPTION \"ycaption\"\n#define MEMBER_SERIES_CAPTIONS \"series_captions\"\n#define MEMBER_DISPLAY \"display\"\n#define MEMBER_CHECK \"check\"\n#define MEMBER_FILENAME \"filename\"\n#define MEMBER_FORMAT \"format\"\n#define MEMBER_FROM \"from\"\n#define MEMBER_HEIGHT \"height\"\n#define MEMBER_LABELS \"labels\"\n#define MEMBER_NAME \"name\"\n#define MEMBER_OFFSET \"offset\"\n#define MEMBER_SCALE \"scale\"\n#define MEMBER_SUPER \"super\"\n#define MEMBER_THIS \"this\"\n#define MEMBER_TO \"to\"\n#define MEMBER_VALUE \"value\"\n#define MEMBER_WIDTH \"width\"\n#define MEMBER_LEFT \"left\"\n#define MEMBER_TOP \"top\"\n#define MEMBER_IMAGE \"image\"\n#define MEMBER_OO_BINARY \"oo_binary\"\n#define MEMBER_OO_BINARY2 \"oo_binary'\"\n#define MEMBER_OO_UNARY \"oo_unary\"\n#define MEMBER_COLOUR_SPACE \"colour_space\"\n#define MEMBER_EXPR \"expr\"\n#define MEMBER_INTERVAL \"interval\"\n#define MEMBER_OPTIONS \"options\"\n\n#define MEMBER_VISLEVEL \"_vislevel\"\n#define MEMBER_ACTION \"action\"\n#define MEMBER_LABEL \"label\"\n#define MEMBER_ICON \"icon\"\n#define MEMBER_TOOLTIP \"tooltip\"\n\n/* The class names we know about.\n */\n#define CLASS_SLIDER \"Scale\"\n#define CLASS_TOGGLE \"Toggle\"\n#define CLASS_IMAGE \"Image\"\n#define CLASS_COLOUR \"Colour\"\n#define CLASS_NUMBER \"Number\"\n#define CLASS_STRING \"String\"\n#define CLASS_OPTION \"Option\"\n#define CLASS_MATRIX \"Matrix_vips\"\n#define CLASS_ARROW \"Arrow\"\n#define CLASS_REGION \"Region\"\n#define CLASS_AREA \"Area\"\n#define CLASS_HGUIDE \"HGuide\"\n#define CLASS_VGUIDE \"VGuide\"\n#define CLASS_MARK \"Mark\"\n#define CLASS_POINT \"Point\"\n#define CLASS_PATHNAME \"Pathname\"\n#define CLASS_FONTNAME \"Fontname\"\n#define CLASS_SEPARATOR \"Separator\"\n#define CLASS_GROUP \"Group\"\n#define CLASS_LIST \"List\"\n#define CLASS_MENU \"Menu\"\n#define CLASS_MENUITEM \"Menuitem\"\n#define CLASS_MENUACTION \"Menuaction\"\n#define CLASS_MENUPULLRIGHT \"Menupullright\"\n#define CLASS_MENUSEPARATOR \"Menuseparator\"\n#define CLASS_EXPRESSION \"Expression\"\n#define CLASS_CLOCK \"Clock\"\n#define CLASS_REAL \"Real\"\n#define CLASS_VECTOR \"Vector\"\n#define CLASS_PLOT \"Plot\"\n\n/* What we loop over a class instance with.\n */\ntypedef void *(*class_map_fn)( Symbol *, PElement *, void *, void * );\n\nCompile *class_get_compile( PElement *instance );\ngboolean class_get_super( PElement *instance, PElement *out );\nvoid *class_map( PElement *instance, class_map_fn fn, void *a, void *b );\ngboolean class_get_member( PElement *instance, const char *name, \n\tSymbol **sym_out, PElement *value );\ngboolean class_get_symbol( PElement *class, Symbol *sym, PElement *out );\ngboolean class_get_exact( PElement *instance, const char *name, PElement *out );\n\ngboolean class_new_super( Heap *heap, \n\tCompile *compile, PElement *this, PElement *instance );\ngboolean class_new( Heap *heap, \n\tCompile *compile, HeapNode **args, PElement *out );\ngboolean class_clone( Heap *heap, PElement *class, PElement *out );\ngboolean class_clone_args( Heap *heap, PElement *klass, PElement *out );\ngboolean class_newv( Heap *heap, const char *name, PElement *out, ... );\n\ngboolean class_get_member_real( PElement *klass, const char *name, \n\tdouble *out );\ngboolean class_get_member_int( PElement *instance, const char *name, \n\tint *out );\ngboolean class_get_member_bool( PElement *klass, const char *name, \n\tgboolean *out );\ngboolean class_get_member_image( PElement *instance, const char *name, \n\tImageinfo **out );\ngboolean class_get_member_class( PElement *instance, const char *name, \n\tconst char *type, PElement *out );\ngboolean class_get_member_lstring( PElement *instance, const char *name, \n\tGSList **labels );\ngboolean class_get_member_string( PElement *klass, const char *name, \n\tchar *buf, int sz );\ngboolean class_get_member_instance( PElement *instance, const char *name, \n\tconst char *klass, PElement *out );\ngboolean class_get_member_matrix_size( PElement *instance, const char *name, \n\tint *xsize, int *ysize );\ngboolean class_get_member_matrix( PElement *instance, const char *name, \n\tdouble *buf, int n, int *xsize, int *ysize );\ngboolean class_get_member_realvec( PElement *instance, const char *name, \n\tdouble *buf, int n, int *length );\n"
  },
  {
    "path": "src/classmodel.c",
    "content": "/* like a heapmodel, but we represent a class in the heap\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/*\n#define DEBUG\n */\n\nstatic HeapmodelClass *parent_class = NULL;\n\nvoid\nimage_value_init( ImageValue *image, Classmodel *classmodel )\n{\n\timage->ii = NULL;\n\timage->file_changed_sid = 0;\n\timage->classmodel = classmodel;\n}\n\nvoid\nimage_value_destroy( ImageValue *image )\n{\n\tFREESID( image->file_changed_sid, image->ii );\n\tMANAGED_UNREF( image->ii );\n}\n\nstatic void\nimage_value_file_changed_cb( Imageinfo *ii, ImageValue *image )\n{\n#ifdef DEBUG\n\tprintf( \"image_value_file_changed_cb: \" );\n\tiobject_print( IOBJECT( image->classmodel ) );\n#endif /*DEBUG*/\n\n\tif( CALC_RELOAD ) {\n\t\tRow *row = HEAPMODEL( image->classmodel )->row;\n\n\t\t(void) expr_dirty( row->expr, link_serial_new() );\n\t\tsymbol_recalculate_all();\n\t}\n}\n\nvoid\nimage_value_set( ImageValue *image, Imageinfo *ii )\n{\n\timage_value_destroy( image );\n\n\timage->ii = ii;\n\n\tif( ii ) {\n\t\tMANAGED_REF( image->ii );\n\t\timage->file_changed_sid = g_signal_connect( \n\t\t\tG_OBJECT( image->ii ), \"file_changed\", \n\t\t\tG_CALLBACK( image_value_file_changed_cb ), image );\n\t}\n\n#ifdef DEBUG\n\tprintf( \"iimage_instance_update: ii = %p\\n\", ii );\n#endif /*DEBUG*/\n}\n\n/* Generate a descriptive name for an imagevalue. Used by plot.c etc. as well.\n */\nvoid\nimage_value_caption( ImageValue *value, VipsBuf *buf )\n{\n\tImageinfo *ii = value->ii;\n\tClassmodel *classmodel = value->classmodel;\n\n\t/* Show the filename if this ii came from a file, otherwise show\n\t * the class.\n\t */\n\tif( ii && imageinfo_is_from_file( ii ) && classmodel->filename ) \n\t\tvips_buf_appends( buf, im_skip_dir( classmodel->filename ) );\n\telse if( !heapmodel_name( HEAPMODEL( classmodel ), buf ) )\n\t\t/* Only if there's no value, I think.\n\t\t */\n\t\tvips_buf_appends( buf, CLASS_IMAGE );\n}\n\nvoid *\nclassmodel_get_instance( Classmodel *classmodel )\n{\n\tClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel );\n\n\tif( class && class->get_instance )\n\t\treturn( class->get_instance( classmodel ) );\n\n\treturn( NULL );\n}\n\nstatic void\nclassmodel_graphic_save_cb( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( iwnd );\n\tClassmodel *classmodel = CLASSMODEL( client );\n\tClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel );\n\tchar *filename;\n\n\tif( (filename = filesel_get_filename( filesel )) ) {\n\t\tif( class->graphic_save( classmodel, \n\t\t\tGTK_WIDGET( iwnd ), filename ) ) {\n\t\t\tIM_SETSTR( classmodel->filename, filename );\n\t\t\tiobject_changed( IOBJECT( classmodel ) );\n\n\t\t\tnfn( sys, IWINDOW_YES );\n\t\t}\n\t\telse\n\t\t\tnfn( sys, IWINDOW_ERROR );\n\n\t\tg_free( filename );\n\t}\n\telse\n\t\tnfn( sys, IWINDOW_ERROR );\n}\n\nvoid\nclassmodel_graphic_save( Classmodel *classmodel, GtkWidget *parent )\n{\n\tClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel );\n\tGtkWidget *filesel;\n\tchar txt[100];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tif( !class->graphic_save ) {\n\t\terror_top( _( \"Not implemented.\" ) );\n\t\terror_sub( _( \"_%s() method not implemented for %s.\" ), \n\t\t\t\"graphic_save\", IOBJECT_GET_CLASS_NAME( classmodel ) );\n\t\tiwindow_alert( parent, GTK_MESSAGE_ERROR );\n\t\treturn;\n\t}\n\n\tfilesel = filesel_new();\n\trow_qualified_name( HEAPMODEL( classmodel )->row, &buf );\n\tiwindow_set_title( IWINDOW( filesel ), _( \"Save %s \\\"%s\\\"\" ), \n\t\tIOBJECT_GET_CLASS_NAME( classmodel ), vips_buf_all( &buf ) );\n\tfilesel_set_flags( FILESEL( filesel ), TRUE, TRUE );\n\tfilesel_set_filetype( FILESEL( filesel ), \n\t\tclass->filetype, \n\t\twatch_int_get( main_watchgroup, class->filetype_pref, 0 ) );\n\tfilesel_set_filetype_pref( FILESEL( filesel ), class->filetype_pref );\n\tiwindow_set_parent( IWINDOW( filesel ), parent );\n\tidialog_set_iobject( IDIALOG( filesel ), IOBJECT( classmodel ) );\n\tfilesel_set_done( FILESEL( filesel ), \n\t\tclassmodel_graphic_save_cb, classmodel );\n\tiwindow_build( IWINDOW( filesel ) );\n\n\tif( classmodel->filename )\n\t\tfilesel_set_filename( FILESEL( filesel ), \n\t\t\tclassmodel->filename );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\nstatic void\nclassmodel_graphic_replace_cb( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( iwnd );\n\tClassmodel *classmodel = CLASSMODEL( client );\n\tClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel );\n\tchar *filename;\n\n\tif( (filename = filesel_get_filename( filesel )) ) {\n\t\tif( class->graphic_replace( classmodel, \n\t\t\tGTK_WIDGET( iwnd ), filename ) ) {\n\t\t\t/* Make sure client stays alive through the\n\t\t\t * recalculate.\n\t\t\t */\n\t\t\tg_object_ref( G_OBJECT( classmodel ) );\n\n\t\t\tsymbol_recalculate_all();\n\t\t\tIM_SETSTR( classmodel->filename, filename );\n\t\t\tiobject_changed( IOBJECT( classmodel ) );\n\n\t\t\tg_object_unref( G_OBJECT( classmodel ) );\n\n\t\t\tnfn( sys, IWINDOW_YES );\n\t\t}\n\t\telse\n\t\t\tnfn( sys, IWINDOW_ERROR );\n\n\t\tg_free( filename );\n\t}\n\telse\n\t\tnfn( sys, IWINDOW_ERROR );\n}\n\nvoid\nclassmodel_graphic_replace( Classmodel *classmodel, GtkWidget *parent )\n{\n\tClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel );\n\tGtkWidget *filesel;\n\tchar txt[100];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tif( !class->graphic_replace ) {\n\t\terror_top( _( \"Not implemented.\" ) );\n\t\terror_sub( _( \"_%s() method not implemented for %s.\" ), \n\t\t\t\"graphic_replace\",\n\t\t\tIOBJECT_GET_CLASS_NAME( classmodel ) );\n\t\tiwindow_alert( parent, GTK_MESSAGE_ERROR );\n\t\treturn;\n\t}\n\n\trow_qualified_name( HEAPMODEL( classmodel )->row, &buf );\n\tfilesel = filesel_new();\n\tiwindow_set_title( IWINDOW( filesel ), _( \"Replace %s \\\"%s\\\"\" ), \n\t\tIOBJECT_GET_CLASS_NAME( classmodel ), vips_buf_all( &buf ) );\n\tfilesel_set_flags( FILESEL( filesel ), TRUE, FALSE );\n\tfilesel_set_filetype( FILESEL( filesel ), \n\t\tclass->filetype, \n\t\twatch_int_get( main_watchgroup, class->filetype_pref, 0 ) );\n\tfilesel_set_filetype_pref( FILESEL( filesel ), class->filetype_pref );\n\tiwindow_set_parent( IWINDOW( filesel ), parent );\n\tidialog_set_iobject( IDIALOG( filesel ), IOBJECT( classmodel ) );\n\tfilesel_set_done( FILESEL( filesel ), \n\t\tclassmodel_graphic_replace_cb, classmodel );\n\tiwindow_build( IWINDOW( filesel ) );\n\n\tif( classmodel->filename )\n\t\tfilesel_set_filename( FILESEL( filesel ), \n\t\t\tclassmodel->filename );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\n/* Make and break links between classmodels and the iimages displaying them.\n */\nstatic void \nclassmodel_iimage_link( Classmodel *classmodel, iImage *iimage )\n{\n\tif( !g_slist_find( classmodel->iimages, iimage ) ) {\n#ifdef DEBUG\n\t\tprintf( \"classmodel_iimage_link: linking \" );\n\t\trow_name_print( HEAPMODEL( classmodel )->row );\n\t\tprintf( \" to \" );\n\t\trow_name_print( HEAPMODEL( iimage )->row );\n\t\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t\tiimage->classmodels = \n\t\t\tg_slist_prepend( iimage->classmodels, classmodel );\n\t\tclassmodel->iimages = \n\t\t\tg_slist_prepend( classmodel->iimages, iimage );\n\t}\n}\n\nvoid *\nclassmodel_iimage_unlink( Classmodel *classmodel, iImage *iimage )\n{\n\tif( g_slist_find( classmodel->iimages, iimage ) ) {\n#ifdef DEBUG\n\t\tprintf( \"classmodel_iimage_unlink: unlinking \" );\n\t\trow_name_print( HEAPMODEL( classmodel )->row );\n\t\tprintf( \" from \" );\n\t\trow_name_print( HEAPMODEL( iimage )->row );\n\t\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t\tiimage->classmodels = \n\t\t\tg_slist_remove( iimage->classmodels, classmodel );\n\t\tclassmodel->iimages = \n\t\t\tg_slist_remove( classmodel->iimages, iimage );\n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\nclassmodel_iimage_unlink_rev( iImage *iimage, Classmodel *classmodel )\n{\n\treturn( classmodel_iimage_unlink( classmodel, iimage ) );\n}\n\ntypedef struct {\n\tClassmodel *classmodel;\n\tImageinfo *ii;\n} ClassmodelSearch;\n\nstatic void *\nclassmodel_iimage_expr_model( Model *model, ClassmodelSearch *parms )\n{\n\t/* Look for iimages which aren't super ... ie. if this is a class\n\t * derived from Image, display on the derived class, not on the\n\t * superclass.\n\t */\n\tif( IS_IIMAGE( model ) && \n\t\tHEAPMODEL( model )->row->sym &&\n\t\t!is_super( HEAPMODEL( model )->row->sym ) &&\n\t\t!is_this( HEAPMODEL( model )->row->sym ) ) {\n\t\tiImage *iimage = IIMAGE( model );\n\n\t\tif( iimage->value.ii == parms->ii ) \n\t\t\tclassmodel_iimage_link( parms->classmodel, iimage );\n\t}\n\n\treturn( NULL );\n}\n\n/* This classmodel is defined on an Imageinfo recorded as having been the value\n * of expr ... find an associated iImage, and link to that. \n */\nstatic void *\nclassmodel_iimage_expr( Expr *expr, ClassmodelSearch *parms )\n{\n\tif( expr->row ) {\n#ifdef DEBUG\n\t\tprintf( \"classmodel_iimage_expr: starting for \" );\n\t\trow_name_print( expr->row );\n\t\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t\t/* Search this part of the tally for an iImage with ii as its\n\t\t * derived value, and link to us. \n\t\t */\n\t\t(void) icontainer_map_all( ICONTAINER( expr->row->top_row ), \n\t\t\t(icontainer_map_fn) classmodel_iimage_expr_model, \n\t\t\tparms );\n\t}\n\n\treturn( NULL );\n}\n\n/* classmodel is defined on ii ... update all the classmodel->iimage links.\n */\nvoid\nclassmodel_iimage_update( Classmodel *classmodel, Imageinfo *ii )\n{\n\tClassmodelSearch parms;\n\n\tparms.classmodel = classmodel;\n\tparms.ii = ii;\n\tslist_map( classmodel->iimages, \n\t\t(SListMapFn) classmodel_iimage_unlink_rev, classmodel );\n\n\t/* Don't make links for supers/this.\n\t */\n\tif( HEAPMODEL( classmodel )->row->sym &&\n\t\t!is_super( HEAPMODEL( classmodel )->row->sym ) &&\n\t\t!is_this( HEAPMODEL( classmodel )->row->sym ) ) {\n#ifdef DEBUG\n\t\tprintf( \"classmodel_iimage_update: \" );\n\t\trow_name_print( HEAPMODEL( classmodel )->row );\n\t\tprintf( \" is defined on ii \\\"%s\\\" ... searching for client \"\n\t\t\t\"displays\\n\", ii->im->filename );\n#endif /*DEBUG*/\n\t\tslist_map( imageinfo_expr_which( ii ), \n\t\t\t(SListMapFn) classmodel_iimage_expr, &parms );\n\t}\n}\n\nstatic gboolean\nclassmodel_class_member_new( Classmodel *classmodel,\n\tClassmodelMember *m, Heap *heap, PElement *out );\n\nstatic gboolean\nclassmodel_dict_new( Classmodel *classmodel, \n\tClassmodelMember *options, int noptions, Heap *heap, PElement *out )\n{\n\tPElement list = *out;\n\tint i;\n\n\t/* Make first RHS ... the end of the list. \n\t */\n\theap_list_init( &list ); \n\n\tfor( i = 0; i < noptions; i++ ) {\n\t\tPElement pair, key, value;\n\n\t\tif( !heap_list_add( heap, &list, &pair ) ||\n\t\t\t!heap_list_add( heap, &pair, &key ) ||\n\t\t\t!heap_list_add( heap, &pair, &value ) ||\n\t\t\t!heap_managedstring_new( heap, \n\t\t\t\toptions[i].member_name, &key ) ||\n\t\t\t!classmodel_class_member_new( classmodel,\n\t\t\t\t&options[i], heap, &value ) )\n\t\t\treturn( FALSE );\n\n\t\t(void) heap_list_next( &list );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic gboolean\nclassmodel_class_member_new( Classmodel *classmodel,\n\tClassmodelMember *m, Heap *heap, PElement *out )\n{\n\tswitch( m->type ) {\n\tcase CLASSMODEL_MEMBER_INT:\n\tcase CLASSMODEL_MEMBER_ENUM:\n\t\tif( !heap_real_new( heap, \n\t\t\tG_STRUCT_MEMBER( int, classmodel, m->offset ),\n\t\t\tout ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_BOOLEAN:\n\t\tif( !heap_bool_new( heap, \n\t\t\tG_STRUCT_MEMBER( gboolean, classmodel, m->offset ),\n\t\t\tout ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_DOUBLE:\n\t\tif( !heap_real_new( heap, \n\t\t\tG_STRUCT_MEMBER( double, classmodel, m->offset ),\n\t\t\tout ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_STRING:\n\t\tif( !heap_managedstring_new( heap, \n\t\t\tG_STRUCT_MEMBER( char *, classmodel, m->offset ),\n\t\t\tout ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_STRING_LIST:\n\t\tif( !heap_lstring_new( heap, \n\t\t\tG_STRUCT_MEMBER( GSList *, classmodel, m->offset ),\n\t\t\tout ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_REALVEC_FIXED:\n\t\tif( !heap_realvec_new( heap, m->extent, \n\t\t\t&G_STRUCT_MEMBER( double, classmodel, m->offset ),\n\t\t\tout ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_MATRIX:\n\t{\n\t\tMatrixValue *value = \n\t\t\t&G_STRUCT_MEMBER( MatrixValue, classmodel, m->offset );\n\n\t\tif( !heap_matrix_new( heap, \n\t\t\tvalue->width, value->height, value->coeff, out ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\t}\n\n\tcase CLASSMODEL_MEMBER_OPTIONS:\n\t\tif( !classmodel_dict_new( classmodel, \n\t\t\t(ClassmodelMember *) m->details, m->extent, \n\t\t\theap, out ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_IMAGE:\n\t{\n\t\tImageValue *value = \n\t\t\t&G_STRUCT_MEMBER( ImageValue, classmodel, m->offset );\n\n\t\tPEPUTP( out, ELEMENT_MANAGED, value->ii );\n\t\tbreak;\n\t}\n\n\tdefault:\n\t\tg_assert( 0 );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Trigger the class_new method for a classmodel ... look for a constructor:\n * try CLASS_edit, then if that's not defined, try CLASS. Eg.  \n *\tA1.Scale_edit from to value\n * if Scale_edit is not defined, try\n *\tA1.Scale from to value\n */\nstatic gboolean\nclassmodel_class_instance_new( Classmodel *classmodel )\n{\n\tClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel );\n\tRow *row = HEAPMODEL( classmodel )->row;\n\tPElement *root = &row->expr->root;\n\tconst char *cname = IOBJECT( classmodel )->name;\n\tReduce *rc = reduce_context;\n\tHeap *heap = rc->heap;\n\n\tchar cname_new[256];\n\tPElement fn;\n\n#ifdef DEBUG\n\tprintf( \"classmodel_class_instance_new: \" );\n\trow_name_print( HEAPMODEL( classmodel )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Find and build.\n\t */\n\tim_snprintf( cname_new, 256, \"%s_edit\", cname );\n\tif( !class_get_member( root, cname_new, NULL, &fn ) ) {\n\t\tif( !class_get_member( root, cname, NULL, &fn ) ) \n\t\t\treturn( FALSE );\n\t}\n\n\tif( class->class_new ) {\n\t\tif( !class->class_new( classmodel, &fn, root ) )\n\t\t\treturn( FALSE );\n\t}\n\telse {\n\t\tint i;\n\t\tPElement rhs;\n\n\t\theap_appl_init( root, &fn );\n\n\t\tfor( i = 0; i < class->n_members; i++ ) {\n\t\t\tif( !heap_appl_add( heap, root, &rhs ) )\n\t\t\t\treturn( FALSE );\n\n\t\t\tif( !classmodel_class_member_new( classmodel,\n\t\t\t\t&class->members[i], heap, &rhs ) )\n\t\t\t\treturn( FALSE );\n\t\t}\n\t}\n\n\t/* Reduce to base type.\n\t */\n\tif( !reduce_pelement( rc, reduce_spine, root ) ) \n\t\treturn( FALSE );\n\n\t/* We have a new heap struct ... tell everyone to get new pointers.\n\t */\n\tif( heapmodel_new_heap( HEAPMODEL( row ), root ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic void\nclassmodel_dispose( GObject *gobject )\n{\n\tClassmodel *classmodel;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_CLASSMODEL( gobject ) );\n\n\tclassmodel = CLASSMODEL( gobject );\n\n\t/* My instance destroy stuff.\n\t */\n\tslist_map( classmodel->iimages, \n\t\t(SListMapFn) classmodel_iimage_unlink_rev, classmodel );\n\tIM_FREE( classmodel->filename );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\n/* We don't want subclases like Group to have an _info() method, since it\n * will appear in tooltips and the Container _info() is rather annoying.\n *\n * Things like iImage define an _info() with useful stuff in.\n */\nstatic void\nclassmodel_info( iObject *iobject, VipsBuf *buf )\n{\n}\n\nstatic void\nclassmodel_parent_add( iContainer *child )\n{\n\tg_assert( IS_CLASSMODEL( child ) );\n\n\tICONTAINER_CLASS( parent_class )->parent_add( child );\n}\n\n/* How many widgets we allow for member automation edit.\n */\n#define MAX_WIDGETS (10)\n\n/* Widgets for classmodel edit.\n */\ntypedef struct _ClassmodelEdit {\n\tiDialog *idlg;\n\n\tClassmodel *classmodel;\n\n\tGtkWidget *widgets[MAX_WIDGETS];\n} ClassmodelEdit;\n\nstatic gboolean\nclassmodel_done_member( Classmodel *classmodel,\n\tClassmodelMember *m, GtkWidget *widget )\n{\n\tchar txt[256];\n\n\tswitch( m->type ) {\n\tcase CLASSMODEL_MEMBER_INT:\n\tcase CLASSMODEL_MEMBER_ENUM:\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_BOOLEAN:\n\t\tG_STRUCT_MEMBER( gboolean, classmodel, m->offset ) =\n\t\t\tGTK_TOGGLE_BUTTON( widget )->active;\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_DOUBLE:\n\t\tif( !get_geditable_double( widget, \n\t\t\t&G_STRUCT_MEMBER( double, classmodel, m->offset ) ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_STRING:\n\t\tget_geditable_string( widget, txt, 256 );\n\t\tIM_SETSTR( G_STRUCT_MEMBER( char *, classmodel, m->offset ), \n\t\t\ttxt );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_STRING_LIST:\n\tcase CLASSMODEL_MEMBER_REALVEC_FIXED:\n\tcase CLASSMODEL_MEMBER_MATRIX:\n\tcase CLASSMODEL_MEMBER_OPTIONS:\n\tcase CLASSMODEL_MEMBER_IMAGE:\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( 0 );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Done button hit.\n */\nstatic void\nclassmodel_done_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tClassmodelEdit *eds = (ClassmodelEdit *) client;\n\tClassmodel *classmodel = eds->classmodel;\n\tClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel );\n\tint i;\n\n\tfor( i = 0; i < class->n_members; i++ ) \n\t\tif( !classmodel_done_member( classmodel, \n\t\t\t&class->members[i], eds->widgets[i] ) ) {\n\t\t\tnfn( sys, IWINDOW_ERROR );\n\t\t\treturn;\n\t\t}\n\n\t/* Rebuild object.\n\t */\n\tclassmodel_update( classmodel );\n\tsymbol_recalculate_all();\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic GtkWidget *\nclassmodel_buildedit_member( Classmodel *classmodel, \n\tClassmodelMember *m, iDialog *idlg, GtkWidget *vb, GtkSizeGroup *group )\n{\n\tGtkWidget *widget;\n\n\twidget = NULL; \n\n\tswitch( m->type ) {\n\tcase CLASSMODEL_MEMBER_INT:\n\tcase CLASSMODEL_MEMBER_ENUM:\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_BOOLEAN:\n\t\twidget = build_gtoggle( vb, _( m->user_name ) );\n\t\tgtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( widget ), \n\t\t\tG_STRUCT_MEMBER( gboolean, classmodel, m->offset ) );\n\t\tset_tooltip( widget, _( \"Set boolean value here\" ) );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_DOUBLE:\n\t\twidget = build_glabeltext4( vb, group, _( m->user_name ) );\n\t\tidialog_init_entry( idlg, widget, \n\t\t\t_( \"Enter a floating point number here\" ), \n\t\t\t\"%g\", \n\t\t\tG_STRUCT_MEMBER( double, classmodel, m->offset ) );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_STRING:\n\t\twidget = build_glabeltext4( vb, group, _( m->user_name ) );\n\t\tidialog_init_entry( idlg, widget, _( \"Enter a string here\" ), \n\t\t\t\"%s\", \n\t\t\tG_STRUCT_MEMBER( char *, classmodel, m->offset ) );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_STRING_LIST:\n\tcase CLASSMODEL_MEMBER_REALVEC_FIXED:\n\tcase CLASSMODEL_MEMBER_MATRIX:\n\tcase CLASSMODEL_MEMBER_OPTIONS:\n\tcase CLASSMODEL_MEMBER_IMAGE:\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( 0 );\n\t}\n\n\treturn( widget );\n}\n\n/* Build the insides of edit.\n */\nstatic void\nclassmodel_buildedit( iDialog *idlg, GtkWidget *vb, ClassmodelEdit *eds )\n{\n\tClassmodel *classmodel = eds->classmodel;\n\tClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel );\n\tGtkSizeGroup *group = gtk_size_group_new( GTK_SIZE_GROUP_HORIZONTAL );\n\tint i;\n\n\tfor( i = 0; i < class->n_members; i++ ) \n\t\teds->widgets[i] = classmodel_buildedit_member( classmodel, \n\t\t\t&class->members[i], idlg, vb, group );\n\n        gtk_widget_show_all( vb );\n\n\tg_object_unref( group );\n}\n\nstatic void \nclassmodel_edit( GtkWidget *parent, Model *model )\n{\n\tClassmodel *classmodel = CLASSMODEL( model );\n\tClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel );\n\n\tif( class->n_members ) {\n\t\tGtkWidget *idlg;\n\t\tClassmodelEdit *eds = INEW( NULL, ClassmodelEdit );\n\n\t\teds->classmodel = classmodel;\n\n\t\tidlg = idialog_new();\n\t\t/* Expands to eg. \"Edit Toggle A1\".\n\t\t */\n\t\tiwindow_set_title( IWINDOW( idlg ), _( \"Edit %s %s\" ),\n\t\t\tIOBJECT_GET_CLASS_NAME( model ),\n\t\t\tIOBJECT( HEAPMODEL( model )->row )->name );\n\t\tidialog_set_build( IDIALOG( idlg ), \n\t\t\t(iWindowBuildFn) classmodel_buildedit, eds, \n\t\t\tNULL, NULL );\n\t\tidialog_set_callbacks( IDIALOG( idlg ), \n\t\t\tiwindow_true_cb, NULL, idialog_free_client, eds );\n\t\t/* Expands to eg. \"Set Toggle\".\n\t\t */\n\t\tidialog_add_ok( IDIALOG( idlg ), \n\t\t\tclassmodel_done_cb, _( \"Set %s\" ), \n\t\t\tIOBJECT_GET_CLASS_NAME( classmodel ) );\n\t\tiwindow_set_parent( IWINDOW( idlg ), parent );\n\t\tidialog_set_iobject( IDIALOG( idlg ), IOBJECT( classmodel ) );\n\t\tiwindow_build( IWINDOW( idlg ) );\n\n\t\tgtk_widget_show( GTK_WIDGET( idlg ) );\n\t}\n}\n\nstatic gboolean\nclassmodel_save_member( Classmodel *classmodel, \n\tClassmodelMember *m, xmlNode *xthis )\n{\n\tint i;\n\n\tswitch( m->type ) {\n\tcase CLASSMODEL_MEMBER_INT:\n\tcase CLASSMODEL_MEMBER_ENUM:\n\t\tif( !set_iprop( xthis, m->save_name, \n\t\t\tG_STRUCT_MEMBER( int, classmodel, m->offset ) ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_BOOLEAN:\n\t\tif( !set_sprop( xthis, m->save_name, bool_to_char( \n\t\t\tG_STRUCT_MEMBER( gboolean, classmodel, m->offset ) ) ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_DOUBLE:\n\t\tif( !set_dprop( xthis, m->save_name, \n\t\t\tG_STRUCT_MEMBER( double, classmodel, m->offset ) ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_STRING:\n\t\tif( !set_sprop( xthis, m->save_name, \n\t\t\tG_STRUCT_MEMBER( char *, classmodel, m->offset ) ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_STRING_LIST:\n\t\tif( !set_slprop( xthis, m->save_name, \n\t\t\tG_STRUCT_MEMBER( GSList *, classmodel, m->offset ) ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_REALVEC_FIXED:\n\t\tfor( i = 0; i < m->extent; i++ ) {\n\t\t\tchar buf[256];\n\n\t\t\tim_snprintf( buf, 256, \"%s%d\", m->save_name, i );\n\t\t\tif( !set_dprop( xthis, buf, (&G_STRUCT_MEMBER( double, \n\t\t\t\tclassmodel, m->offset ))[i] ) )\n\t\t\t\treturn( FALSE );\n\t\t}\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_MATRIX:\n\t{\n\t\tMatrixValue *value = \n\t\t\t&G_STRUCT_MEMBER( MatrixValue, classmodel, m->offset );\n\t\tconst int n = value->width * value->height;\n\n\t\tif( !set_dlprop( xthis, \"value\", value->coeff, n ) ||\n\t\t\t!set_iprop( xthis, \"width\", value->width ) ||\n\t\t\t!set_iprop( xthis, \"height\", value->height ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\t}\n\n\tcase CLASSMODEL_MEMBER_OPTIONS:\n\t\tfor( i = 0; i < m->extent; i++ ) {\n\t\t\tClassmodelMember *options = \n\t\t\t\t(ClassmodelMember *) m->details;\n\n\t\t\tif( !classmodel_save_member( classmodel, \n\t\t\t\t&options[i], xthis ) )\n\t\t\t\treturn( FALSE );\n\t\t}\n\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_IMAGE:\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( 0 );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic xmlNode *\nclassmodel_save( Model *model, xmlNode *xnode )\n{\n\tClassmodel *classmodel = CLASSMODEL( model );\n\tClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel );\n\txmlNode *xthis;\n\tint i;\n\n#ifdef DEBUG\n\tprintf( \"classmodel_save: \" );\n\trow_name_print( HEAPMODEL( classmodel )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )\n\t\treturn( NULL );\n\n\tif( classmodel->edited ) \n\t\tfor( i = 0; i < class->n_members; i++ ) \n\t\t\tif( !classmodel_save_member( classmodel, \n\t\t\t\t&class->members[i], xthis ) )\n\t\t\t\treturn( NULL );\n\n\treturn( xthis );\n}\n\nstatic gboolean\nclassmodel_load_member( Classmodel *classmodel, \n\tClassmodelMember *m, xmlNode *xthis )\n{\n\tchar buf[MAX_STRSIZE];\n\tgboolean found;\n\tint i;\n\n\tfound = FALSE;\n\n\tswitch( m->type ) {\n\tcase CLASSMODEL_MEMBER_INT:\n\t\tif( get_iprop( xthis, m->save_name, \n\t\t\t&G_STRUCT_MEMBER( int, classmodel, m->offset ) ) )\n\t\t\tfound = TRUE;\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_ENUM:\n\t{\n\t\tint v;\n\n\t\tif( get_iprop( xthis, m->save_name, &v ) ) {\n\t\t\tv = IM_CLIP( 0, v, m->extent );\n\t\t\tG_STRUCT_MEMBER( int, classmodel, m->offset ) = v;\n\t\t\tfound = TRUE;\n\t\t}\n\t\tbreak;\n\t}\n\n\tcase CLASSMODEL_MEMBER_BOOLEAN:\n\t\tif( get_bprop( xthis, m->save_name, \n\t\t\t&G_STRUCT_MEMBER( gboolean, classmodel, m->offset ) ) )\n\t\t\tfound = TRUE;\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_DOUBLE:\n\t\tif( get_dprop( xthis, m->save_name, \n\t\t\t&G_STRUCT_MEMBER( double, classmodel, m->offset ) ) )\n\t\t\tfound = TRUE;\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_STRING:\n\t\tif( get_sprop( xthis, m->save_name, buf, MAX_STRSIZE ) ) {\n\t\t\tIM_SETSTR( G_STRUCT_MEMBER( char *, \n\t\t\t\tclassmodel, m->offset ), buf );\n\t\t\tfound = TRUE;\n\t\t}\n\n\t\t/* Nasty: before member automation, we used to always\n\t\t * save/load caption, as a member of model. Now caption is\n\t\t * only present if the class has it as a automated member.\n\t\t * Plus some classes used to not support captions (eg. Scale).\n\t\t * So: caption can be missing, even if it should be there. Set\n\t\t * a fall-back value.\n\t\t */\n\t\tif( !found && strcmp( m->save_name, \"caption\" ) == 0 ) {\n\t\t\tIM_SETSTR( G_STRUCT_MEMBER( char *, \n\t\t\t\tclassmodel, m->offset ), \"\" );\n\t\t\tfound = TRUE;\n\t\t}\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_STRING_LIST:\n\t{\n\t\tGSList *slist;\n\t\tGSList **member = \n\t\t\t&G_STRUCT_MEMBER( GSList *, classmodel, m->offset );\n\n\t\tif( get_slprop( xthis, m->member_name, &slist ) ) {\n\t\t\tIM_FREEF( slist_free_all, *member ); \n\t\t\t*member = slist; \n\t\t\tfound = TRUE;\n\t\t}\n\n\t\tbreak;\n\t}\n\n\tcase CLASSMODEL_MEMBER_REALVEC_FIXED:\n\t\tfor( i = 0; i < m->extent; i++ ) {\n\t\t\tim_snprintf( buf, MAX_STRSIZE, \n\t\t\t\t\"%s%d\", m->save_name, i );\n\t\t\tif( get_dprop( xthis, buf, \n\t\t\t\t&((&G_STRUCT_MEMBER( double, \n\t\t\t\t\tclassmodel, m->offset ))[i]) ) )\n\t\t\t\tfound = TRUE;\n\t\t}\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_MATRIX:\n\t{\n\t\tMatrixValue *value = \n\t\t\t&G_STRUCT_MEMBER( MatrixValue, classmodel, m->offset );\n\n\t\tif( get_dlprop( xthis, \"value\", &value->coeff ) &&\n\t\t\tget_iprop( xthis, \"width\", &value->width ) &&\n\t\t\tget_iprop( xthis, \"height\", &value->height ) )\n\t\t\tfound = TRUE;\n\n\t\tbreak;\n\t}\n\n\tcase CLASSMODEL_MEMBER_OPTIONS:\n\t\tfor( i = 0; i < m->extent; i++ ) {\n\t\t\tClassmodelMember *options = \n\t\t\t\t(ClassmodelMember *) m->details;\n\n\t\t\tif( !classmodel_load_member( classmodel, \n\t\t\t\t&options[i], xthis ) )\n\t\t\t\treturn( FALSE );\n\t\t}\n\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_IMAGE:\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( 0 );\n\t}\n\n\treturn( found );\n}\n\nstatic gboolean\nclassmodel_load( Model *model, \n\tModelLoadState *state, Model *parent, xmlNode *xthis )\n{\n\tClassmodel *classmodel = CLASSMODEL( model );\n\tClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel );\n\n#ifdef DEBUG\n\tprintf( \"classmodel_load: \" );\n\trow_name_print( HEAPMODEL( classmodel )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Only for classes with member automation.\n\t */\n\tif( class->n_members ) {\n\t\tgboolean all_found;\n\t\tint i;\n\n\t\t/* Before we mark the graphic as edited, insist all \n\t\t * members have values set. This can be important in\n\t\t * compatibility mode, where the old nip might not have\n\t\t * supported all the members we have.\n\t\t */\n\t\tall_found = TRUE;\n\t\tfor( i = 0; i < class->n_members; i++ ) \n\t\t\tall_found &= classmodel_load_member( classmodel, \n\t\t\t\t&class->members[i], xthis );\n\t\tif( all_found ) \n\t\t\tclassmodel_set_edited( CLASSMODEL( model ), TRUE );\n\t}\n\n\treturn( MODEL_CLASS( parent_class )->load( model, \n\t\tstate, parent, xthis ) );\n}\n\nstatic gboolean\nclassmodel_get_item( Classmodel *classmodel, \n\tClassmodelMember *m, PElement *value );\n\nstatic void *\nclassmodel_parse_option( const char *key, PElement *value, \n\tClassmodel *classmodel, ClassmodelMember *m )\n{\n\tClassmodelMember *options = (ClassmodelMember *) m->details;\n\tint noptions = m->extent;\n\tint i;\n\n\tfor( i = 0; i < noptions; i++ )\n\t\tif( strcmp( key, options[i].member_name ) == 0 ) \n\t\t\tbreak;\n\tif( i == noptions ) {\n\t\terror_top( _( \"Unknown option.\" ) );\n\t\terror_sub( _( \"Option \\\"%s\\\" not known.\" ), key );\n\n\t\treturn( value );\n\t}\n\n\tif( !classmodel_get_item( classmodel, &options[i], value ) )\n\t\treturn( value );\n\n\treturn( NULL );\n}\n\nstatic gboolean\nclassmodel_get_item( Classmodel *classmodel, \n\tClassmodelMember *m, PElement *value )\n{\n\tchar buf[MAX_STRSIZE];\n\tdouble vec[3];\n\tint l;\n\tint i;\n\tdouble d;\n\n\tswitch( m->type ) {\n\tcase CLASSMODEL_MEMBER_INT:\n\t\tif( !heap_get_real( value, &d ) )\n\t\t\treturn( FALSE );\n\t\tG_STRUCT_MEMBER( int, classmodel, m->offset ) = d;\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_ENUM:\n\t\tif( !heap_get_real( value, &d ) )\n\t\t\treturn( FALSE );\n\t\td = IM_CLIP( 0, d, m->extent );\n\t\tG_STRUCT_MEMBER( int, classmodel, m->offset ) = d;\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_BOOLEAN:\n\t\tif( !heap_get_bool( value, \n\t\t\t&G_STRUCT_MEMBER( gboolean, classmodel, m->offset ) ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_DOUBLE:\n\t\tif( !heap_get_real( value, \n\t\t\t&G_STRUCT_MEMBER( double, classmodel, m->offset ) ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_STRING:\n\t\tif( !heap_get_string( value, buf, MAX_STRSIZE ) )\n\t\t\treturn( FALSE );\n\t\tIM_SETSTR( G_STRUCT_MEMBER( char *, classmodel, m->offset ), \n\t\t\tbuf );\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_STRING_LIST:\n\t{\n\t\tGSList *slist;\n\t\tGSList **member = \n\t\t\t&G_STRUCT_MEMBER( GSList *, classmodel, m->offset );\n\n\t\tif( !heap_get_lstring( value, &slist ) )\n\t\t\treturn( FALSE );\n\n\t\tIM_FREEF( slist_free_all, *member ); \n\t\t*member = slist; \n\n\t\tbreak;\n\t}\n\n\tcase CLASSMODEL_MEMBER_REALVEC_FIXED:\n\t\tg_assert( m->extent < 4 );\n\n\t\tif( (l = heap_get_realvec( value, vec, m->extent )) < 0 )\n\t\t\treturn( FALSE );\n\t\tif( l != m->extent ) {\n\t\t\terror_top( _( \"Bad value.\" ) );\n\t\t\terror_sub( _( \"%d band value only\" ), m->extent );\n\t\t\treturn( FALSE );\n\t\t}\n\t\tfor( i = 0; i < m->extent; i++ )\n\t\t\t(&G_STRUCT_MEMBER( double, classmodel, m->offset ))[i] =\n\t\t\t\tvec[i];\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_MATRIX:\n\t{\n\t\tMatrixValue *matrix = \n\t\t\t&G_STRUCT_MEMBER( MatrixValue, classmodel, m->offset );\n\t\tint w, h;\n\n\t\tif( !heap_get_matrix_size( value, &w, &h ) ||\n\t\t\t!matrix_value_resize( matrix, w, h ) ||\n\t\t\t!heap_get_matrix( value, \n\t\t\t\tmatrix->coeff, matrix->width * matrix->height, \n\t\t\t\t&w, &h ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\t}\n\n\tcase CLASSMODEL_MEMBER_OPTIONS:\n\t\t/* If there are optional fields, we have to have a reset\n\t\t * method for clearing the ones we don't use.\n\t\t */\n\t\tg_assert( CLASSMODEL_GET_CLASS( classmodel )->reset );\n\n\t\tif( heap_map_dict( value, \n\t\t\t(heap_map_dict_fn) classmodel_parse_option, \n\t\t\tclassmodel, m ) ) \n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\n\tcase CLASSMODEL_MEMBER_IMAGE:\n\t{\n\t\tImageValue *image = \n\t\t\t&G_STRUCT_MEMBER( ImageValue, classmodel, m->offset );\n\t\tImageinfo *ii;\n\n\t\tg_assert( image->classmodel == classmodel );\n\n\t\tif( !heap_get_image( value, &ii ) )\n\t\t\treturn( FALSE );\n\t\timage_value_set( image, ii );\n\n\t\tbreak;\n\t}\n\n\tdefault:\n\t\tg_assert( 0 );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic gboolean\nclassmodel_update_model_member( Classmodel *classmodel, \n\tClassmodelMember *m, PElement *root )\n{\n\tPElement value;\n\n\tif( !class_get_member( root, m->member_name, NULL, &value ) )\n\t\treturn( FALSE );\n\n#ifdef DEBUG\n\tprintf( \"classmodel_update_model_member: setting %s = \",\n\t\tm->member_name );\n\tpgraph( &value );\n#endif /*DEBUG*/\n\n\tif( !classmodel_get_item( classmodel, m, &value ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Update all members from the heap. Also used from graph_export_image.\n */\ngboolean \nclassmodel_update_members( Classmodel *classmodel, PElement *root )\n{\n\tClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel );\n\n\tint i;\n\n\tfor( i = 0; i < class->n_members; i++ ) \n\t\tif( !classmodel_update_model_member( classmodel,\n\t\t\t&class->members[i], root ) )\n\t\t\treturn( FALSE );\n\n\tif( class->class_get &&\n\t\t!class->class_get( classmodel, root ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic void *\nclassmodel_update_model( Heapmodel *heapmodel )\n{\n\tClassmodel *classmodel = CLASSMODEL( heapmodel );\n\tClassmodelClass *class = CLASSMODEL_GET_CLASS( classmodel );\n\n#ifdef DEBUG\n\tprintf( \"classmodel_update_model: \" );\n\trow_name_print( heapmodel->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* If necessary, reset model to default.\n\t */\n\tif( class->reset )\n\t\tclass->reset( classmodel );\n\n\tif( heapmodel->row && \n\t\theapmodel->row->expr ) {\n\t\tExpr *expr = heapmodel->row->expr;\n\n\t\tif( !heapmodel->modified ) \n\t\t\tif( !classmodel_update_members( classmodel,\n\t\t\t\t&expr->root ) )\n\t\t\t\treturn( classmodel );\n\t}\n\n\treturn( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) );\n}\n\nstatic void *\nclassmodel_update_heap( Heapmodel *heapmodel )\n{\n\tClassmodel *classmodel = CLASSMODEL( heapmodel );\n\n#ifdef DEBUG\n\tprintf( \"classmodel_update_heap: \" );\n\trow_name_print( HEAPMODEL( classmodel )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Nasty: classmodel_class_instance_new() can (indirectly) destroy us.\n\t * Wrap a _ref()/_unref() pair around it to make sure we stay alive.\n\t */\n\tg_object_ref( G_OBJECT( heapmodel ) );\n\n\t/* Build a new instance from the model.\n\t */\n\tif( !classmodel_class_instance_new( classmodel ) ) {\n\t\tg_object_unref( G_OBJECT( heapmodel ) );\n\t\treturn( heapmodel );\n\t}\n\n\tif( HEAPMODEL_CLASS( parent_class )->update_heap( heapmodel ) ) {\n\t\tg_object_unref( G_OBJECT( heapmodel ) );\n\t\treturn( heapmodel );\n\t}\n\n\tg_object_unref( G_OBJECT( heapmodel ) );\n\n\treturn( NULL );\n}\n\nstatic void *\nclassmodel_clear_edited( Heapmodel *heapmodel )\n{\n\tClassmodel *classmodel = CLASSMODEL( heapmodel );\n\n\tclassmodel_set_edited( classmodel, FALSE );\n\n\treturn( HEAPMODEL_CLASS( parent_class )->clear_edited( heapmodel ) );\n}\n\nstatic gboolean\nclassmodel_real_class_get( Classmodel *classmodel, PElement *root )\n{\n\treturn( TRUE );\n}\n\nstatic void\nclassmodel_class_init( ClassmodelClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tiContainerClass *icontainer_class = (iContainerClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tHeapmodelClass *heapmodel_class = (HeapmodelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Init methods.\n\t */\n\tgobject_class->dispose = classmodel_dispose;\n\n\tiobject_class->info = classmodel_info;\n\n\ticontainer_class->parent_add = classmodel_parent_add;\n\n\tmodel_class->edit = classmodel_edit;\n\tmodel_class->save = classmodel_save;\n\tmodel_class->load = classmodel_load;\n\n\theapmodel_class->update_model = classmodel_update_model;\n\theapmodel_class->update_heap = classmodel_update_heap;\n\theapmodel_class->clear_edited = classmodel_clear_edited;\n\n\tclassmodel_class->get_instance = NULL;\n\n\tclassmodel_class->class_get = classmodel_real_class_get;\n\tclassmodel_class->class_new = NULL;\n\n\tclassmodel_class->graphic_save = NULL;\n\tclassmodel_class->graphic_replace = NULL;\n\n\tclassmodel_class->filetype = filesel_type_any;\n\tclassmodel_class->filetype_pref = NULL;\n\n\tclassmodel_class->members = NULL;\n\tclassmodel_class->n_members = 0;\n}\n\nstatic void\nclassmodel_init( Classmodel *classmodel )\n{\n\tModel *model = MODEL( classmodel );\n\n\tmodel->display = FALSE;\n\n        classmodel->edited = FALSE;\n\n        classmodel->iimages = NULL;\n        classmodel->views = NULL;\n\n        classmodel->filename = NULL;\n}\n\nGType\nclassmodel_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ClassmodelClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) classmodel_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Classmodel ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) classmodel_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_HEAPMODEL, \n\t\t\t\"Classmodel\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nvoid\nclassmodel_set_edited( Classmodel *classmodel, gboolean edited )\n{\n\tif( classmodel->edited != edited ) {\n#ifdef DEBUG\n\t\tprintf( \"classmodel_set_edited: \" );\n\t\trow_name_print( HEAPMODEL( classmodel )->row );\n\t\tprintf( \" %s\\n\", bool_to_char( edited ) );\n#endif /*DEBUG*/\n\n\t\tclassmodel->edited = edited;\n\t\tiobject_changed( IOBJECT( classmodel ) );\n\n\t\tif( HEAPMODEL( classmodel )->row && \n\t\t\tHEAPMODEL( classmodel )->row->expr )\n\t\t\texpr_dirty( HEAPMODEL( classmodel )->row->expr, \n\t\t\t\tlink_serial_new() );\n\t}\n\n\t/* Mark eds for application.\n\t */\n\tif( edited )\n\t\theapmodel_set_modified( HEAPMODEL( classmodel ), TRUE );\n}\n\n/* The model has changed: mark for recomp.\n */\nvoid\nclassmodel_update( Classmodel *classmodel )\n{\n\tRow *row = HEAPMODEL( classmodel )->row;\n\n\t/* Eg. for no symol on load.\n\t */\n\tif( !row->expr )\n\t\treturn;\n\n#ifdef DEBUG\n\tprintf( \"classmodel_update: \" );\n\trow_name_print( HEAPMODEL( classmodel )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* classmodel_update_heap() will rebuild us on recomp.\n\t */\n\tclassmodel_set_edited( classmodel, TRUE );\n\texpr_dirty( row->expr, link_serial_new() );\n\tworkspace_set_modified( row->ws, TRUE );\n}\n\n/* Make a new classmodel subtype (eg. TYPE_PATHNAME) and link it on.\n */\nClassmodel *\nclassmodel_new_classmodel( GType type, Rhs *rhs )\n{\n\tClassmodel *classmodel;\n\n\tclassmodel = g_object_new( type, NULL );\n\ticontainer_child_add( ICONTAINER( rhs ), ICONTAINER( classmodel ), -1 );\n\n\treturn( classmodel );\n}\n"
  },
  {
    "path": "src/classmodel.h",
    "content": "/* like a heapmodel, but we represent a class in the heap\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* Member types we automate.\n */\ntypedef enum {\n\tCLASSMODEL_MEMBER_INT,\n\tCLASSMODEL_MEMBER_ENUM,\t\t/* Like int, but extent has max value */\n\tCLASSMODEL_MEMBER_BOOLEAN,\n\tCLASSMODEL_MEMBER_DOUBLE,\n\tCLASSMODEL_MEMBER_STRING,\n\tCLASSMODEL_MEMBER_STRING_LIST,\n\tCLASSMODEL_MEMBER_REALVEC_FIXED,/* Eg. Colour's triplet */\n\tCLASSMODEL_MEMBER_MATRIX,\n\tCLASSMODEL_MEMBER_OPTIONS,\n\tCLASSMODEL_MEMBER_IMAGE\n} ClassmodelMemberType;\n\n/* A matrix value.\n */\ntypedef struct _MatrixValue {\n\tdouble *coeff;\t\t\t/* Base coeffs */\n\tint width;\t\t\t/* Size of matrix */\n\tint height;\n} MatrixValue;\n\n/* An image value.\n */\ntypedef struct {\n\tImageinfo *ii;\n\n\t/* Can get \"changed\" for reload if the file changes behind our backs.\n\t * Recalc the classmodel if this happens.\n\t */\n\tguint file_changed_sid;\n\tClassmodel *classmodel;\n} ImageValue;\n\n/* A member needing automation.\n */\ntypedef struct {\n\tClassmodelMemberType type;\n\tvoid *details;\t\t\t/* eg. the set of allowed options */\n\tint extent;\t\t\t/* Vector length, enum max, etc. */\n\n\tconst char *member_name;\t/* Name as known in nip class defs */\n\tconst char *save_name;\t\t/* As known in save files */\n\tconst char *user_name;\t\t/* i18n'd name for dialogs */\n\n\tguint offset;\t\t\t/* Struct offset */\n} ClassmodelMember;\n\n#define TYPE_CLASSMODEL (classmodel_get_type())\n#define CLASSMODEL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_CLASSMODEL, Classmodel ))\n#define CLASSMODEL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_CLASSMODEL, ClassmodelClass))\n#define IS_CLASSMODEL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_CLASSMODEL ))\n#define IS_CLASSMODEL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_CLASSMODEL ))\n#define CLASSMODEL_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_CLASSMODEL, ClassmodelClass ))\n\nstruct _Classmodel {\n\tHeapmodel parent_class;\n\n\t/* Set if we have graphic mods applied which should be saved.\n\t */\n\tgboolean edited;\n\n\t/* xtras for Region/Arrow/etc.\n\t */\n\tGSList *iimages;\t/* All the iimage we are defined on */\n\tGSList *views;\t\t/* All the regionview we have made */\n\n\t/* For things which have been loaded or saved from files (eg. image\n\t * and matrix). Used to set the filename for the \"save\" dialog.\n\t */\n\tchar *filename;\n};\n\ntypedef struct _ClassmodelClass {\n\tHeapmodelClass parent_class;\n\n\t/* Get a pointer to the class instance vars ... just used by\n\t * iarrow/iregion for code sharing.\n\t */\n\tvoid *(*get_instance)( Classmodel * );\n\n\t/* Read from heap into model, and create new heap class from model.\n\t */\n\tgboolean (*class_get)( Classmodel *, PElement *root );\n\tgboolean (*class_new)( Classmodel *, PElement *fn, PElement *out );\n\n\t/* Save and replace graphic displays ... eg. image/matrix.\n\t */\n\tgboolean (*graphic_save)( Classmodel *, GtkWidget *, const char * );\n\tgboolean (*graphic_replace)( Classmodel *, GtkWidget *, const char * );\n\n\tFileselFileType **filetype;\n\tconst char *filetype_pref;\n\n\tClassmodelMember *members;\n\tint n_members;\n\tvoid (*reset)( Classmodel * );\n} ClassmodelClass;\n\nvoid image_value_init( ImageValue *image, Classmodel *classmodel );\nvoid image_value_destroy( ImageValue *image );\nvoid image_value_set( ImageValue *image, Imageinfo *ii );\nvoid image_value_caption( ImageValue *value, VipsBuf *buf );\n\nvoid *classmodel_get_instance( Classmodel *classmodel );\nvoid classmodel_graphic_save( Classmodel *classmodel, GtkWidget *parent );\nvoid classmodel_graphic_replace( Classmodel *classmodel, GtkWidget *parent );\n\nvoid *classmodel_iimage_unlink( Classmodel *classmodel, iImage *iimage );\nvoid classmodel_iimage_update( Classmodel *classmodel, Imageinfo *ii );\n\ngboolean classmodel_update_members( Classmodel *classmodel, PElement *root );\n\nGType classmodel_get_type( void );\n\nvoid classmodel_update( Classmodel *classmodel );\nvoid classmodel_set_edited( Classmodel *classmodel, gboolean edited );\n\nClassmodel *classmodel_new_classmodel( GType type, Rhs *rhs );\n"
  },
  {
    "path": "src/clock.c",
    "content": "/* a clock ... triggers a recomp every whenever\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ValueClass *parent_class = NULL;\n\nstatic void\nclock_dispose( GObject *gobject )\n{\n\tClock *clock = CLOCK( gobject );\n\n#ifdef DEBUG\n\tprintf( \"clock_dispose\\n\" );\n#endif /*DEBUG*/\n\n\tIM_FREEF( g_source_remove, clock->recalc_timeout );\n\tIM_FREEF( g_timer_destroy, clock->elapsed_timer );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\nclock_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys )\n{\n\tClock *clock = CLOCK( client );\n\tStringset *ss = STRINGSET( iwnd );\n\n\tStringsetChild *interval = stringset_child_get( ss, _( \"Interval\" ) );\n\tStringsetChild *value = stringset_child_get( ss, _( \"Elapsed time\" ) );\n\n\tif( !get_geditable_double( interval->entry, &clock->interval ) ||\n\t\t!get_geditable_double( value->entry, &clock->value ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tif( clock->interval < 0.1 )\n\t\tclock->interval = 0.1;\n\tif( clock->value < 0.0 )\n\t\tclock->value = 0.0;\n\n\t/* Magic: ask for the clock timer to be reset.\n\t */\n\tclock->time_offset = -1;\n\n\tclassmodel_update( CLASSMODEL( clock ) );\n\tsymbol_recalculate_all();\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void \nclock_edit( GtkWidget *parent, Model *model )\n{\n\tClock *clock = CLOCK( model );\n\tGtkWidget *ss = stringset_new();\n\tchar txt[256];\n\n\tim_snprintf( txt, 256, \"%g\", clock->interval );\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Interval\" ), txt, _( \"Interval between ticks (seconds)\" ) );\n\tim_snprintf( txt, 256, \"%g\", clock->value );\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Elapsed time\" ), txt, _( \"Elapsed time (seconds)\" ) );\n\n\t/* Expands to eg. \"Edit Toggle A1\".\n\t */\n\tiwindow_set_title( IWINDOW( ss ), _( \"Edit %s %s\" ),\n\t\tIOBJECT_GET_CLASS_NAME( model ),\n\t\tIOBJECT( HEAPMODEL( model )->row )->name );\n\tidialog_set_callbacks( IDIALOG( ss ), \n\t\tiwindow_true_cb, NULL, NULL, clock );\n\tidialog_add_ok( IDIALOG( ss ), \n\t\tclock_done_cb, _( \"Set %s\" ), IOBJECT_GET_CLASS_NAME( model ) );\n\tiwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( parent ) );\n\tidialog_set_iobject( IDIALOG( ss ), IOBJECT( model ) );\n\tiwindow_build( IWINDOW( ss ) );\n\n\tgtk_widget_show( ss );\n}\n\nstatic gboolean\nclock_timeout_cb( Clock *clock )\n{\n#ifdef DEBUG\n\tprintf( \"clock_timeout_cb: \" );\n\trow_name_print( HEAPMODEL( clock )->row );\n\tprintf( \" interval=%g, value=%g\\n\", clock->interval, clock->value );\n#endif /*DEBUG*/\n\n\t/* Test autocalc ... if it's off, make sure we don't update the\n\t * interface.\n\t */\n\tif( mainw_auto_recalc ) {\n\t\tclock->value = g_timer_elapsed( clock->elapsed_timer, NULL ) + \n\t\t\tclock->time_offset;\n\n\t\tclassmodel_update( CLASSMODEL( clock ) );\n\n\t\tsymbol_recalculate_all();\n\t}\n\n\treturn( TRUE );\n}\n\nstatic void *\nclock_update_model( Heapmodel *heapmodel )\n{\n\tClock *clock = CLOCK( heapmodel );\n\n#ifdef DEBUG\n\tprintf( \"clock_update_model: \" );\n\trow_name_print( HEAPMODEL( clock )->row );\n\tprintf( \" interval=%g, value=%g\\n\", clock->interval, clock->value );\n#endif /*DEBUG*/\n\n\tif( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) )\n\t\treturn( heapmodel );\n\n\t/* Milliseconds for the update timeout ... don't let it go under 100,\n\t * there's a danger the interface will lock up.\n\t */\n\tint ms = IM_MAX( 100, clock->interval * 1000 );\n\tIM_FREEF( g_source_remove, clock->recalc_timeout );\n\tclock->recalc_timeout = g_timeout_add( ms, \n\t\t(GSourceFunc) clock_timeout_cb, clock );\n\n\t/* Should we reset the timer from the value?\n\t */\n\tif( clock->time_offset == -1 ) {\n\t\tg_timer_start( clock->elapsed_timer );\n\t\tclock->time_offset = clock->value;\n\t}\n\n\treturn( NULL );\n}\n\n/* Override value_generate_caption(): pick from the model.\n */\nstatic const char *\nclock_generate_caption( iObject *iobject )\n{\n\tValue *value = VALUE( iobject );\n\tValueClass *value_class = VALUE_GET_CLASS( value );\n\tClock *clock = CLOCK( iobject );\n\tVipsBuf *buf = &value->caption_buffer;\n\n\tvips_buf_rewind( buf );\n\tif( !heapmodel_name( HEAPMODEL( value ), buf ) ) \n\t\tvips_buf_appends( buf, G_OBJECT_CLASS_NAME( value_class ) );\n\tvips_buf_appendf( buf, \" %g %g\", clock->interval, clock->value );\n\n\treturn( vips_buf_all( buf ) );\n}\n\n/* Members of clock we automate.\n */\nstatic ClassmodelMember clock_members[] = {\n\t{ CLASSMODEL_MEMBER_DOUBLE, NULL, 0,\n\t\tMEMBER_INTERVAL, \"interval\", N_( \"Interval\" ),\n\t\tG_STRUCT_OFFSET( Clock, interval ) },\n\t{ CLASSMODEL_MEMBER_DOUBLE, NULL, 0,\n\t\tMEMBER_VALUE, \"value\", N_( \"Value\" ),\n\t\tG_STRUCT_OFFSET( Clock, value ) }\n};\n\nstatic void\nclock_class_init( ClockClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tHeapmodelClass *heapmodel_class = (HeapmodelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->dispose = clock_dispose;\n\n\tiobject_class->user_name = _( \"Clock\" );\n\tiobject_class->generate_caption = clock_generate_caption;\n\n\tmodel_class->edit = clock_edit;\n\n\theapmodel_class->update_model = clock_update_model;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n\n\tclassmodel_class->members = clock_members;\n\tclassmodel_class->n_members = IM_NUMBER( clock_members );\n}\n\nstatic void\nclock_init( Clock *clock )\n{\n#ifdef DEBUG\n\tprintf( \"clock_init\\n\" );\n#endif /*DEBUG*/\n\n\t/* Overridden later. Just something sensible.\n\t */\n        clock->interval = 1;\n        clock->value = 0;\n\n\t/* time_offset: set to -1 means we should set the offset from value on\n\t * the next rebuild.\n\t */\n\tclock->elapsed_timer = g_timer_new();\n\tclock->time_offset = -1;\t\n        clock->recalc_timeout = 0;\n\n\tiobject_set( IOBJECT( clock ), CLASS_CLOCK, NULL );\n}\n\nGType\nclock_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ClockClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) clock_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Clock ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) clock_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_VALUE, \n\t\t\t\"Clock\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/clock.h",
    "content": "/* a clock in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_CLOCK (clock_get_type())\n#define CLOCK( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_CLOCK, Clock ))\n#define CLOCK_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_CLOCK, ClockClass))\n#define IS_CLOCK( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_CLOCK ))\n#define IS_CLOCK_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_CLOCK ))\n#define CLOCK_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_CLOCK, ClockClass ))\n\ntypedef struct _Clock {\n\tValue parent_object;\n\n\tdouble interval;\n\tdouble value;\n\n\tGTimer *elapsed_timer;\n\tdouble time_offset;\t/* Offset timer by this to get new value */\n\tguint recalc_timeout;\t/* Timeout for next recalc */\n} Clock;\n\ntypedef struct _ClockClass {\n\tValueClass parent_class;\n\n\t/* My methods.\n\t */\n} ClockClass;\n\nGType clock_get_type( void );\n"
  },
  {
    "path": "src/colour.c",
    "content": "/* an image class object in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* Set of allowed colour_space strings. Do a case-insensitive match.\n */\nstatic const char *colour_colour_space[] = {\n\t\"xyz\", \t\t/* index 0 */\n\t\"yxy\", \t\t/* index 1 */\n\t\"lab\", \t\t/* index 2 */\n\t\"lch\", \t\t/* index 3 */\n\t\"ucs\", \t\t/* index 4 */\n\t\"rgb\", \t\t/* index 5 */\n\t\"srgb\",\t\t/* index 6 */\n\t\"rgb16\",\t/* index 7 */\n\t\"grey16\"\t/* index 8 */\n};\n\n/* For each allowed colourspace, the corresponding VIPS Type value.\n */\nstatic const int colour_type[] = {\n\tIM_TYPE_XYZ,\n\tIM_TYPE_YXY,\n\tIM_TYPE_LAB,\n\tIM_TYPE_LCH,\n\tIM_TYPE_UCS,\n\tIM_TYPE_RGB,\n\tIM_TYPE_sRGB,\n\tIM_TYPE_RGB16,\n\tIM_TYPE_GREY16\n};\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic void\ncolour_finalize( GObject *gobject )\n{\n\tColour *colour = COLOUR( gobject );\n\n\tIM_FREE( colour->colour_space );\n\tvips_buf_destroy( &colour->caption );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\n/* Widgets for colour edit.\n */\ntypedef struct _ColourEdit {\n\tiDialog *idlg;\n\n\tColour *colour;\n\tGtkWidget *colour_widget;\n} ColourEdit;\n\n/* Find the VIPS type for a colour space string.\n */\nstatic int\ncolour_get_vips_type( Colour *colour )\n{\n\tint type;\n\tint i;\n\n\t/* Default to something harmless.\n\t */\n\ttype = IM_TYPE_MULTIBAND;\n\n\tif( colour->colour_space ) \n\t\tfor( i = 0; i < IM_NUMBER( colour_colour_space ); i++ )\n\t\t\tif( strcasecmp( colour->colour_space, \n\t\t\t\tcolour_colour_space[i] ) == 0 ) {\n\t\t\t\ttype = colour_type[i];\n\t\t\t\tbreak;\n\t\t\t}\n\n\treturn( type );\n}\n\n/* Are two doubles more or less equal. We need this when we check \n * for update to stop loops. The 0.0001 is a bit of a fudge :-(\n */\n#define DEQ( A, B ) (ABS((A) - (B)) < 0.0001)\n\n/* Update non-model stuff in object from the model params.\n */\nstatic void\ncolour_refresh( Colour *colour )\n{\n\tvips_buf_rewind( &colour->caption );\n\tvips_buf_appendf( &colour->caption, CLASS_COLOUR \" %s [%g, %g, %g]\",\n\t\tNN( colour->colour_space ),\n\t\tcolour->value[0], colour->value[1], colour->value[2] );\n}\n\nvoid\ncolour_set_colour( Colour *colour, \n\tconst char *colour_space, double value[3] )\n{\n\tint i;\n\n\t/* No change?\n\t */\n\tfor( i = 0; i < 3; i++ )\n\t\tif( !DEQ( value[i], colour->value[i] ) )\n\t\t\tbreak;\n\tif( i == 3 && \n\t\tcolour_space &&\n\t\tstrcmp( colour_space, colour->colour_space ) == 0 )\n\t\treturn;\n\n\tfor( i = 0; i < 3; i++ )\n\t\tcolour->value[i] = value[i];\n\tIM_SETSTR( colour->colour_space, colour_space );\n\n\tcolour_refresh( colour );\n        classmodel_update( CLASSMODEL( colour ) );\n        symbol_recalculate_all();\n}\n\n/* Code up a colour as an ii. Refcount zero! Will go on next GC.\n */\nImageinfo *\ncolour_ii_new( Colour *colour )\n{\n\tImageinfo *imageinfo;\n\tint i;\n\n\tif( !(imageinfo = imageinfo_new_temp( main_imageinfogroup, \n\t\treduce_context->heap, NULL, \"t\" )) ) \n\t\treturn( NULL );\n\n\t/* Make a 3 band 32-bit FLOAT memory image.\n\t */\n\tim_initdesc( imageinfo->im, 1, 1, 3, \n\t\tIM_BBITS_FLOAT, IM_BANDFMT_FLOAT, \n\t\tIM_CODING_NONE, colour_get_vips_type( colour ),\n\t\t1.0, 1.0, 0, 0 );\n\tif( im_setupout( imageinfo->im ) ) \n\t\treturn( NULL );\n\tfor( i = 0; i < 3; i++ )\n\t\t((float *) imageinfo->im->data)[i] = colour->value[i];\n\n\treturn( imageinfo );\n}\n\n/* Convert our colour to rgb. Slow!\n */\nstatic void\ncolour_get_rgb( Colour *colour, double rgb[4] )\n{\n\tint i;\n\tImageinfo *imageinfo;\n\n\tfor( i = 0; i < 4; i++ ) \n\t\trgb[i] = 0.0;\n\tif( (imageinfo = colour_ii_new( colour )) )\n\t\timageinfo_to_rgb( imageinfo, rgb );\n}\n\nvoid\ncolour_set_rgb( Colour *colour, double rgb[4] )\n{\n\tImageinfo *imageinfo;\n\n\tif( (imageinfo = colour_ii_new( colour )) ) {\n\t\tdouble old_rgb[4];\n\t\tdouble value[3];\n\t\tint i;\n\n\t\t/* Setting as RGB can't express small differences since we're\n\t\t * going via 8 bit RGB. So only accept the new value if it's \n\t\t * sufficiently different from\n\t\t * what we have now.\n\t\t */\n\t\tcolour_get_rgb( colour, old_rgb );\n\t\tif( fabs( rgb[0] - old_rgb[0] ) > (0.5 / 255) ||\n\t\t\tfabs( rgb[1] - old_rgb[1] ) > (0.5 / 255) ||\n\t\t\tfabs( rgb[2] - old_rgb[2] ) > (0.5 / 255) ) {\n\t\t\timageinfo_from_rgb( imageinfo, rgb );\n\t\t\tfor( i = 0; i < 3; i++ )\n\t\t\t\tvalue[i] = ((float *) imageinfo->im->data)[i];\n\t\t\tcolour_set_colour( colour, \n\t\t\t\tcolour->colour_space, value );\n\t\t}\n\t}\n}\n\n/* Done button hit.\n */\nstatic void\ncolour_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys )\n{\n\tColourEdit *eds = (ColourEdit *) client;\n\tColour *colour = eds->colour;\n\tdouble rgb[4];\n\n\tgtk_color_selection_get_color( \n\t\tGTK_COLOR_SELECTION( eds->colour_widget ), rgb );\n\n\tcolour_set_rgb( colour, rgb );\n\n\tnfn( sys, IWINDOW_YES );\n}\n\n/* Build the insides of colour edit.\n */\nstatic void\ncolour_buildedit( iDialog *idlg, GtkWidget *work, ColourEdit *eds )\n{\n\tColour *colour = eds->colour;\n\tdouble rgb[4];\n\n\teds->colour_widget = gtk_color_selection_new();\n\tgtk_color_selection_set_has_opacity_control( \n\t\tGTK_COLOR_SELECTION( eds->colour_widget ), FALSE );\n\tcolour_get_rgb( colour, rgb );\n\tgtk_color_selection_set_color( \n\t\tGTK_COLOR_SELECTION( eds->colour_widget ), rgb );\n        gtk_box_pack_start( GTK_BOX( work ), \n\t\teds->colour_widget, TRUE, TRUE, 2 );\n\n        gtk_widget_show_all( work );\n}\n\nstatic void\ncolour_edit( GtkWidget *parent, Model *model )\n{\n\tColour *colour = COLOUR( model );\n\tColourEdit *eds = INEW( NULL, ColourEdit );\n\tGtkWidget *idlg;\n\n\teds->colour = colour;\n\n\tidlg = idialog_new();\n\tiwindow_set_title( IWINDOW( idlg ), _( \"Edit %s %s\" ),\n\t\tIOBJECT_GET_CLASS_NAME( model ),\n\t\tIOBJECT( HEAPMODEL( model )->row )->name );\n\tidialog_set_build( IDIALOG( idlg ), \n\t\t(iWindowBuildFn) colour_buildedit, eds, NULL, NULL );\n\tidialog_set_callbacks( IDIALOG( idlg ), \n\t\tiwindow_true_cb, NULL, idialog_free_client, eds );\n\tidialog_add_ok( IDIALOG( idlg ), \n\t\tcolour_done_cb, _( \"Set %s\" ), \n\t\tIOBJECT_GET_CLASS_NAME( model ) );\n\tiwindow_set_parent( IWINDOW( idlg ), parent );\n\tidialog_set_iobject( IDIALOG( idlg ), IOBJECT( model ) );\n\tidialog_set_pinup( IDIALOG( idlg ), TRUE );\n\tiwindow_build( IWINDOW( idlg ) );\n\n\tgtk_widget_show( GTK_WIDGET( idlg ) );\n}\n\nstatic View *\ncolour_view_new( Model *model, View *parent )\n{\n\treturn( colourview_new() );\n}\n\nstatic void *\ncolour_update_model( Heapmodel *heapmodel )\n{\n\tColour *colour = COLOUR( heapmodel );\n\n\tif( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) )\n\t\treturn( heapmodel );\n\n\tcolour_refresh( colour );\n\n\treturn( NULL );\n}\n\n/* Members of colour we automate.\n */\nstatic ClassmodelMember colour_members[] = {\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0, \n\t\tMEMBER_COLOUR_SPACE, \"colour_space\", N_( \"Color Space\" ),\n\t\tG_STRUCT_OFFSET( Colour, colour_space ) },\n\t{ CLASSMODEL_MEMBER_REALVEC_FIXED, NULL, 3,\n\t\tMEMBER_VALUE, \"value\", N_( \"Value\" ),\n\t\tG_STRUCT_OFFSET( Colour, value ) }\n};\n\nstatic void\ncolour_class_init( ColourClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tHeapmodelClass *heapmodel_class = (HeapmodelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->finalize = colour_finalize;\n\n\tmodel_class->view_new = colour_view_new;\n\tmodel_class->edit = colour_edit;\n\n\theapmodel_class->update_model = colour_update_model;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n\n\tclassmodel_class->members = colour_members;\n\tclassmodel_class->n_members = IM_NUMBER( colour_members );\n}\n\nstatic void\ncolour_init( Colour *colour )\n{\n\tcolour->value[0] = 0.0;\n\tcolour->value[1] = 0.0;\n\tcolour->value[2] = 0.0;\n\tcolour->colour_space = NULL;\n\tvips_buf_init_dynamic( &colour->caption, MAX_LINELENGTH );\n\n\tiobject_set( IOBJECT( colour ), CLASS_COLOUR, NULL );\n}\n\nGType\ncolour_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ColourClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) colour_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Colour ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) colour_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"Colour\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/colour.h",
    "content": "/* a colour colour in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_COLOUR (colour_get_type())\n#define COLOUR( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_COLOUR, Colour ))\n#define COLOUR_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_COLOUR, ColourClass))\n#define IS_COLOUR( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_COLOUR ))\n#define IS_COLOUR_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_COLOUR ))\n#define COLOUR_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_COLOUR, ColourClass ))\n\nstruct _Colour {\n\tClassmodel parent_class;\n\n\t/* Class fields.\n\t */\n\tdouble value[3];\n\tchar *colour_space;\n\n\t/* Build view caption here.\n\t */\n\tVipsBuf caption;\n};\n\ntypedef struct _ColourClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} ColourClass;\n\nImageinfo *colour_ii_new( Colour *colour );\nvoid colour_set_rgb( Colour *colour, double rgb[3] );\n\nGType colour_get_type( void );\n"
  },
  {
    "path": "src/colourdisplay.c",
    "content": "/* run the display for an image in a workspace \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* Tag our drag-n-drops with these.\n */\nenum {\n\tTARGET_COLOUR,\n\tTARGET_TEXT\n};\n\nstatic ImagedisplayClass *parent_class = NULL;\n\n/* Prefer x-color drags for 3 band non-complex imageinfos, and for LABQ\n */\nstatic void\ncolourdisplay_set_drag_type( Colourdisplay *colourdisplay )\n{\n\tstatic const GtkTargetEntry text_targets[] = {\n\t\t{ \"text/plain\", 0, TARGET_TEXT },\n\t\t{ \"application/x-color\", 0, TARGET_COLOUR }\n\t};\n\n\tstatic const GtkTargetEntry colour_targets[] = {\n\t\t{ \"application/x-color\", 0, TARGET_COLOUR },\n\t\t{ \"text/plain\", 0, TARGET_TEXT }\n\t};\n\n\tImageinfo *imageinfo = IMAGEDISPLAY( colourdisplay )->conv->ii;\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo );\n\tconst GtkTargetEntry *targets;\n\n\tif( !GTK_WIDGET_REALIZED( GTK_WIDGET( colourdisplay ) ) || !im ) \n\t\treturn;\n\n\tif( im->Bands == 3 && !vips_bandfmt_iscomplex( im->BandFmt ) )\n\t\ttargets = colour_targets;\n\telse if( im->Coding == IM_CODING_LABQ )\n\t\ttargets = colour_targets;\n\telse\n\t\ttargets = text_targets;\n\n\tgtk_drag_dest_unset( GTK_WIDGET( colourdisplay ) );\n\tgtk_drag_dest_set( GTK_WIDGET( colourdisplay ),\n\t\tGTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_MOTION | \n\t\t\tGTK_DEST_DEFAULT_DROP,\n\t\ttargets, IM_NUMBER( text_targets ),\n\t\tGDK_ACTION_COPY );\n\tgtk_drag_source_unset( GTK_WIDGET( colourdisplay ) );\n\tgtk_drag_source_set( GTK_WIDGET( colourdisplay ),\n\t\tGDK_BUTTON1_MASK | GDK_BUTTON3_MASK,\n\t\ttargets, IM_NUMBER( text_targets ),\n\t\tGDK_ACTION_COPY | GDK_ACTION_MOVE );\n}\n\nstatic void\ncolourdisplay_realize( GtkWidget *widget )\n{\n\tColourdisplay *colourdisplay = COLOURDISPLAY( widget );\n\n\tGTK_WIDGET_CLASS( parent_class )->realize( widget );\n\n\tcolourdisplay_set_drag_type( colourdisplay );\n}\n\nstatic void\ncolourdisplay_drag_begin( GtkWidget *widget, GdkDragContext *context )\n{\n\tColourdisplay *colourdisplay = COLOURDISPLAY( widget );\n\tGtkWidget *window;\n\tdouble colours[4];\n\tGdkColor bg;\n\n\twindow = iimageview_drag_window_new( 48, 32 ); \n\tgtk_object_set_data_full( GTK_OBJECT( widget ),\n\t\t\"nip2-drag-window\", window,\n\t\t(GtkDestroyNotify) gtk_widget_destroy );\n#ifdef DEBUG\n\tprintf( \"colourdisplay_drag_begin: generating drag swatch colour\\n\" );\n#endif /*DEBUG*/\n\timageinfo_to_rgb( IMAGEDISPLAY( colourdisplay )->conv->ii, colours );\n\tbg.red = 0xffff * colours[0];\n\tbg.green = 0xffff * colours[1];\n\tbg.blue = 0xffff * colours[2];\n\tgtk_widget_modify_bg( window, GTK_STATE_NORMAL, &bg );\n\n\tgtk_drag_set_icon_widget( context, window, -2, -2 );\n}\n\nstatic void\ncolourdisplay_drag_end( GtkWidget *widget, GdkDragContext *context )\n{\n\tgtk_object_set_data( GTK_OBJECT( widget ), \n\t\t\"nip2-drag-window\", NULL );\n}\n\nstatic void\ncolourdisplay_drag_data_get( GtkWidget *widget, GdkDragContext *context,\n\tGtkSelectionData *selection_data, guint info, guint time ) \n{\n\tColourdisplay *colourdisplay = COLOURDISPLAY( widget );\n\tImageinfo *imageinfo = IMAGEDISPLAY( colourdisplay )->conv->ii;\n\tdouble colours[3];\n\tguint16 vals[4];\n\tchar vips_buf_text[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( vips_buf_text );\n\n\tswitch( info ) {\n\tcase TARGET_COLOUR:\n\t\timageinfo_to_rgb( imageinfo, colours );\n\n\t\tvals[0] = IM_RINT( colours[0] * 0xffff );\n\t\tvals[1] = IM_RINT( colours[1] * 0xffff );\n\t\tvals[2] = IM_RINT( colours[2] * 0xffff );\n\t\tvals[3] = 0xffff;\n\n\t\tgtk_selection_data_set( selection_data,\n\t\t\tgdk_atom_intern( \"application/x-color\", FALSE ),\n\t\t\t16, (guchar *) vals, 8 );\n\n#ifdef DEBUG\n\t\tprintf( \"colourdisplay_drag_data_get: sending x-color\\n\" );\n#endif /*DEBUG*/\n\n\t\tbreak;\n\n\tcase TARGET_TEXT:\n\t\timageinfo_to_text( imageinfo, &buf );\n\t\tgtk_selection_data_set( selection_data,\n\t\t\tgdk_atom_intern( \"text/plain\", FALSE ), 8, \n\t\t\t(guchar *) vips_buf_all( &buf ), \n\t\t\tstrlen( vips_buf_all( &buf ) ) );\n\n#ifdef DEBUG\n\t\tprintf( \"colourdisplay_drag_data_get: sending text/plain\\n\" );\n#endif /*DEBUG*/\n\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t\tbreak;\n\t}\n}\n\nstatic void\ncolourdisplay_drag_data_received( GtkWidget *widget, GdkDragContext *context,\n\tgint x, gint y, GtkSelectionData *selection_data,\n\tguint info, guint time ) \n{\n\tColourdisplay *colourdisplay = COLOURDISPLAY( widget );\n\tImageinfo *imageinfo = IMAGEDISPLAY( colourdisplay )->conv->ii;\n\n\tguint16 *vals;\n\tgdouble old_rgb[4];\n\tgdouble rgb[4];\n\n\tif( selection_data->length < 0 ) \n\t\treturn;\n\n\tswitch( info ) {\n\tcase TARGET_COLOUR: \n\t\tif( selection_data->format != 16 || \n\t\t\tselection_data->length != 8 )\n\t\t\treturn;\n\n#ifdef DEBUG\n\t\tprintf( \"colourdisplay_drag_data_received: seen x-color\\n\" );\n#endif /*DEBUG*/\n\n\t\tvals = (guint16 *)selection_data->data;\n\t\trgb[0] = (double) vals[0] / 0xffff;\n\t\trgb[1] = (double) vals[1] / 0xffff;\n\t\trgb[2] = (double) vals[2] / 0xffff;\n\n\t\t/* Dragging as RGB can't express small differences. So only\n\t\t * accept the new value if it's sufficiently different from\n\t\t * what we have now.\n\t\t */\n\t\timageinfo_to_rgb( imageinfo, old_rgb );\n\t\tif( fabs( rgb[0] - old_rgb[0] ) > (0.5 / 255) ||\n\t\t\tfabs( rgb[1] - old_rgb[1] ) > (0.5 / 255) ||\n\t\t\tfabs( rgb[2] - old_rgb[2] ) > (0.5 / 255) )\n\t\t\timageinfo_from_rgb( imageinfo, rgb );\n\n\t\tbreak;\n\n\tcase TARGET_TEXT:\n\t\tif( selection_data->format != 8 )\n\t\t\treturn;\n\n#ifdef DEBUG\n\t\tprintf( \"colourdisplay_drag_data_received: seen text/plain\\n\" );\n#endif /*DEBUG*/\n\n\t\tif( !imageinfo_from_text( imageinfo, \n\t\t\t(char *) selection_data->data ) )\n\t\t\tiwindow_alert( widget, GTK_MESSAGE_ERROR );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t\tbreak;\n\t}\n}\n\nstatic void\ncolourdisplay_generate_tooltip( Colourdisplay *colourdisplay, VipsBuf *buf )\n{\n\tImagedisplay *id = IMAGEDISPLAY( colourdisplay );\n\n\tif( id->conv && id->conv->ii ) {\n\t\timageinfo_to_text( id->conv->ii, buf );\n\t\tvips_buf_appends( buf, \"\\n\" );\n\t\tvips_buf_appends( buf, _( \"Double-click to edit this color, or \"\n\t\t\t\"drag-and-drop between colors\" ) );\n\t}\n}\n\nstatic void\ncolourdisplay_conversion_changed( Imagedisplay *id )\n{\n\tColourdisplay *colourdisplay = COLOURDISPLAY( id );\n\n\tIMAGEDISPLAY_CLASS( parent_class )->conversion_changed( id );\n\n\tif( id->conv )\n\t\tconversion_set_mag( id->conv, 5000 );\n\n\tcolourdisplay_set_drag_type( colourdisplay );\n}\n\nstatic void\ncolourdisplay_class_init( ColourdisplayClass *class )\n{\n\tGtkWidgetClass *widget_class = (GtkWidgetClass *) class;\n\tImagedisplayClass *imagedisplay_class = (ImagedisplayClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\twidget_class->realize = colourdisplay_realize;\n\twidget_class->drag_begin = colourdisplay_drag_begin;\n\twidget_class->drag_end = colourdisplay_drag_end;\n\twidget_class->drag_data_get = colourdisplay_drag_data_get;\n\twidget_class->drag_data_received = colourdisplay_drag_data_received;\n\n\timagedisplay_class->conversion_changed =\n\t\tcolourdisplay_conversion_changed;\n}\n\nstatic void\ncolourdisplay_init( Colourdisplay *colourdisplay )\n{\n#ifdef DEBUG\n\tprintf( \"colourdisplay_init\\n\" );\n#endif /*DEBUG*/\n\n\t/* Who wants to focus one of these :/\n\t */\n\tGTK_WIDGET_UNSET_FLAGS( GTK_WIDGET( colourdisplay ), GTK_CAN_FOCUS );\n\n\tset_tooltip_generate( GTK_WIDGET( colourdisplay ), \n\t\t(TooltipGenerateFn) colourdisplay_generate_tooltip, \n\t\t\tNULL, NULL );\n}\n\nGtkType\ncolourdisplay_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Colourdisplay\",\n\t\t\tsizeof( Colourdisplay ),\n\t\t\tsizeof( ColourdisplayClass ),\n\t\t\t(GtkClassInitFunc) colourdisplay_class_init,\n\t\t\t(GtkObjectInitFunc) colourdisplay_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_IMAGEDISPLAY, &info );\n\t}\n\n\treturn( type );\n}\n\nColourdisplay *\ncolourdisplay_new( Conversion *conv )\n{\n\tColourdisplay *colourdisplay = gtk_type_new( TYPE_COLOURDISPLAY );\n\n\tif( !conv ) \n\t\tconv = conversion_new( NULL );\n\tconversion_set_synchronous( conv, TRUE );\n\timagedisplay_set_conversion( IMAGEDISPLAY( colourdisplay ), conv );\n\n\treturn( colourdisplay );\n}\n"
  },
  {
    "path": "src/colourdisplay.h",
    "content": "/* subclass imagedisplay ... show a patch of plain colour from a 1x1 pixel\n * imageinfo\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_COLOURDISPLAY (colourdisplay_get_type())\n#define COLOURDISPLAY( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_COLOURDISPLAY, Colourdisplay ))\n#define COLOURDISPLAY_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_COLOURDISPLAY, ColourdisplayClass ))\n#define IS_COLOURDISPLAY( obj ) (GTK_CHECK_TYPE( (obj), TYPE_COLOURDISPLAY ))\n#define IS_COLOURDISPLAY_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_COLOURDISPLAY ))\n\ntypedef struct _Colourdisplay {\n\tImagedisplay parent_class;\n\n\t/* Set this to indicate that we prefer to drag as text rather than \n\t * colour.\n\t */\n\tgboolean drag_as_text;\n} Colourdisplay;\n\ntypedef struct _ColourdisplayClass {\n\tImagedisplayClass parent_class;\n\n\t/* My methods.\n\t */\n} ColourdisplayClass;\n\nGtkType colourdisplay_get_type( void );\nColourdisplay *colourdisplay_new( Conversion *conv );\n"
  },
  {
    "path": "src/colourview.c",
    "content": "/* run the display for an image in a workspace \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GraphicviewClass *parent_class = NULL;\n\nstatic void\ncolourview_link( View *view, Model *model, View *parent )\n{\n\tColourview *colourview = COLOURVIEW( view );\n\tRowview *rview = ROWVIEW( parent->parent );\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\trowview_menu_attach( rview, GTK_WIDGET( colourview->colourdisplay ) );\n}\n\nstatic void \ncolourview_refresh( vObject *vobject )\n{\n\tColourview *colourview = COLOURVIEW( vobject );\n\tColour *colour = COLOUR( vobject->iobject );\n\n#ifdef DEBUG\n\tprintf( \"colourview_refresh\\n\" );\n#endif /*DEBUG*/\n\n\tconversion_set_image( colourview->conv, colour_ii_new( colour ) );\n\tset_gcaption( colourview->label, \"%s\", vips_buf_all( &colour->caption ) );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\ncolourview_class_init( ColourviewClass *class )\n{\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = colourview_refresh;\n\n\tview_class->link = colourview_link;\n}\n\nstatic void\ncolourview_area_changed_cb( Imagedisplay *id, Rect *area, \n\tColourview *colourview )\n{\n\tdouble rgb[4];\n\n\timageinfo_to_rgb( id->conv->ii, rgb );\n\tcolour_set_rgb( COLOUR( VOBJECT( colourview )->iobject ), rgb );\n}\n\nstatic void \ncolourview_doubleclick_one_cb( GtkWidget *widget, GdkEvent *event, \n\tColourview *colourview )\n{\n\tHeapmodel *heapmodel = HEAPMODEL( VOBJECT( colourview )->iobject );\n\tRow *row = heapmodel->row;\n\n\trow_select_modifier( row, event->button.state );\n}\n\nstatic void \ncolourview_doubleclick_two_cb( GtkWidget *widget, GdkEvent *event, \n\tColourview *colourview )\n{\n\tmodel_edit( widget, MODEL( VOBJECT( colourview )->iobject ) );\n}\n\nstatic void\ncolourview_init( Colourview *colourview )\n{\n\tGtkWidget *eb;\n\tGtkWidget *vbox;\n\n#ifdef DEBUG\n\tprintf( \"colourview_init\\n\" );\n#endif /*DEBUG*/\n\n        eb = gtk_event_box_new();\n\tgtk_widget_add_events( GTK_WIDGET( eb ), \n\t\tGDK_POINTER_MOTION_HINT_MASK ); \n        gtk_box_pack_start( GTK_BOX( colourview ), eb, FALSE, FALSE, 0 );\n\tvbox = gtk_vbox_new( FALSE, 0 );\n        gtk_container_add( GTK_CONTAINER( eb ), vbox );\n        gtk_widget_show( vbox );\n\n        colourview->colourdisplay = colourdisplay_new( NULL );\n\tcolourview->conv = IMAGEDISPLAY( colourview->colourdisplay )->conv;\n\tgtk_widget_set_size_request( GTK_WIDGET( colourview->colourdisplay ), \n\t\tDISPLAY_THUMBNAIL, DISPLAY_THUMBNAIL );\n        gtk_box_pack_start( GTK_BOX( vbox ), \n\t\tGTK_WIDGET( colourview->colourdisplay ), FALSE, FALSE, 0 );\n\tg_signal_connect( colourview->colourdisplay, \"area_changed\",\n\t\tG_CALLBACK( colourview_area_changed_cb ), colourview );\n        gtk_widget_show( GTK_WIDGET( colourview->colourdisplay ) );\n\n\tcolourview->label = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( colourview->label ), 0, 0.5 );\n        gtk_misc_set_padding( GTK_MISC( colourview->label ), 2, 0 );\n        gtk_box_pack_start( GTK_BOX( vbox ), \n\t\tGTK_WIDGET( colourview->label ), FALSE, FALSE, 0 );\n        gtk_widget_show( GTK_WIDGET( colourview->label ) );\n\n\tdoubleclick_add( GTK_WIDGET( colourview ), FALSE,\n\t\tDOUBLECLICK_FUNC( colourview_doubleclick_one_cb ), colourview,\n\t\tDOUBLECLICK_FUNC( colourview_doubleclick_two_cb ), colourview );\n\n\tgtk_widget_set_name( eb, \"caption_widget\" );\n        gtk_widget_show( eb );\n}\n\nGtkType\ncolourview_get_type( void )\n{\n\tstatic GtkType colourview_type = 0;\n\n\tif( !colourview_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Colourview\",\n\t\t\tsizeof( Colourview ),\n\t\t\tsizeof( ColourviewClass ),\n\t\t\t(GtkClassInitFunc) colourview_class_init,\n\t\t\t(GtkObjectInitFunc) colourview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tcolourview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info );\n\t}\n\n\treturn( colourview_type );\n}\n\nView *\ncolourview_new( void )\n{\n\tColourview *colourview = gtk_type_new( TYPE_COLOURVIEW );\n\n\treturn( VIEW( colourview ) );\n}\n"
  },
  {
    "path": "src/colourview.h",
    "content": "/* a colourview in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_COLOURVIEW (colourview_get_type())\n#define COLOURVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_COLOURVIEW, Colourview ))\n#define COLOURVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_COLOURVIEW, ColourviewClass ))\n#define IS_COLOURVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_COLOURVIEW ))\n#define IS_COLOURVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_COLOURVIEW ))\n\ntypedef struct _Colourview {\n\tGraphicview parent_object;\n\n\tColourdisplay *colourdisplay;\n\tConversion *conv;\n\tGtkWidget *label;\n} Colourview;\n\ntypedef struct _ColourviewClass {\n\tGraphicviewClass parent_class;\n\n\t/* My methods.\n\t */\n} ColourviewClass;\n\nGtkType colourview_get_type( void );\nView *colourview_new( void );\n"
  },
  {
    "path": "src/column.c",
    "content": "/* a column button in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic FilemodelClass *parent_class = NULL;\n\n/* Offset for this column load/save.\n */\nstatic int column_left_offset = 0;\nstatic int column_top_offset = 0;\n\n/* When we merge workspaces we need to scroll to position the last new column\n * in view.\n */\nstatic Column *column_last_new = NULL;\n\n/* Map down a column.\n */\nvoid *\ncolumn_map( Column *col, row_map_fn fn, void *a, void *b )\n{\n\tSubcolumn *scol = col->scol;\n\n\treturn( subcolumn_map( scol, fn, a, b ) );\n}\n\nvoid *\ncolumn_map_symbol_sub( Row *row, symbol_map_fn fn, void *a )\n{\n\treturn( fn( row->sym, a, NULL, NULL ) );\n}\n\n/* Map down a column, applying to the symbol of the row.\n */\nvoid *\ncolumn_map_symbol( Column *col, symbol_map_fn fn, void *a )\n{\n\treturn( column_map( col, \n\t\t(row_map_fn) column_map_symbol_sub, (void *) fn, a ) );\n}\n\nstatic void\ncolumn_finalize( GObject *gobject )\n{\n\tColumn *col;\n\n#ifdef DEBUG\n\tprintf( \"column_finalize\\n\" );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_COLUMN( gobject ) );\n\n\tcol = COLUMN( gobject ); \n\n\tif( col == column_last_new ) \n\t\tcolumn_last_new = NULL;\n\tIM_FREEF( g_source_remove, col->scrollto_timeout );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\n/* Select all things in a column.\n */\nvoid *\ncolumn_select_symbols( Column *col )\n{\n\treturn( column_map( col, (row_map_fn) row_select_extend, NULL, NULL ) );\n}\n\nstatic Subcolumn *\ncolumn_get_subcolumn( Column *col )\n{\n\tg_assert( g_slist_length( ICONTAINER( col )->children ) == 1 );\n\n\treturn( SUBCOLUMN( ICONTAINER( col )->children->data ) );\n}\n\nstatic void\ncolumn_child_add( iContainer *parent, iContainer *child, int pos )\n{\n\tColumn *col = COLUMN( parent );\n\n\tICONTAINER_CLASS( parent_class )->child_add( parent, child, pos );\n\n\t/* Update our context.\n\t */\n\tcol->scol = column_get_subcolumn( col );\n}\n\nstatic void\ncolumn_child_remove( iContainer *parent, iContainer *child )\n{\n\tColumn *col = COLUMN( parent );\n\n\tworkspace_set_modified( col->ws, TRUE );\n\n\tICONTAINER_CLASS( parent_class )->child_remove( parent, child );\n}\n\nstatic Workspace *\ncolumn_get_workspace( Column *col )\n{\n\treturn( WORKSPACE( ICONTAINER( col )->parent ) );\n}\n\nstatic void\ncolumn_parent_add( iContainer *child )\n{\n\tColumn *col = COLUMN( child );\n\n\tg_assert( IS_WORKSPACE( child->parent ) );\n\n\tICONTAINER_CLASS( parent_class )->parent_add( child );\n\n\tg_assert( IS_WORKSPACE( child->parent ) );\n\n\t/* Update our context.\n\t */\n\tcol->ws = column_get_workspace( col );\n\tg_assert( IS_WORKSPACE( child->parent ) );\n}\n\nstatic View *\ncolumn_view_new( Model *model, View *parent )\n{\n\tif( IS_PREFWORKSPACEVIEW( parent ) )\n\t\treturn( prefcolumnview_new() );\n\telse\n\t\treturn( columnview_new() );\n}\n\nstatic xmlNode *\ncolumn_save( Model *model, xmlNode *xnode )\n{\n\tColumn *col = COLUMN( model );\n\tint x = IM_MAX( 0, col->x - column_left_offset );\n\tint y = IM_MAX( 0, col->y - column_top_offset );\n\n\txmlNode *xthis;\n\n\tif( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )\n\t\treturn( NULL );\n\n\t/* Save sform for backwards compat with nip 7.8 ... now a workspace\n\t * property.\n\t */\n\tif( !set_iprop( xthis, \"x\", x ) ||\n\t\t!set_iprop( xthis, \"y\", y ) ||\n\t\t!set_sprop( xthis, \"open\", bool_to_char( col->open ) ) ||\n\t\t!set_sprop( xthis, \"selected\",\n\t\t\tbool_to_char( col->selected ) ) ||\n\t\t!set_sprop( xthis, \"sform\", bool_to_char( FALSE ) ) ||\n\t\t!set_iprop( xthis, \"next\", col->next ) || \n\t\t!set_sprop( xthis, \"name\", IOBJECT( col )->name ) )\n\t\treturn( NULL );\n\n\t/* Caption can be NULL for untitled columns.\n\t */\n\tif( IOBJECT( col )->caption )\n\t\tif( !set_sprop( xthis, \"caption\", IOBJECT( col )->caption ) ) \n\t\t\treturn( NULL );\n\n\treturn( xthis );\n}\n\nstatic gboolean\ncolumn_save_test( Model *model )\n{\n\tColumn *col = COLUMN( model );\n\tWorkspace *ws = col->ws;\n\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\n\tif( wsg->save_type == WORKSPACEGROUP_SAVE_SELECTED ) \n\t\t/* Only save columns containing selected rows.\n\t\t */\n\t\treturn( column_map( col, \n\t\t\t(row_map_fn) row_is_selected, NULL, NULL ) != NULL );\n\n\treturn( TRUE );\n}\n\nstatic void\ncolumn_set_last_new( Column *col )\n{\n\tif( !column_last_new ) \n\t\tcolumn_last_new = col;\n}\n\nstatic gboolean\ncolumn_load( Model *model, \n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\tColumn *col = COLUMN( model );\n\tint x = col->x;\n\tint y = col->y;\n\n\tchar buf[256];\n\n\tg_assert( IS_WORKSPACE( parent ) );\n\n\tif( !get_iprop( xnode, \"x\", &x ) ||\n\t\t!get_iprop( xnode, \"y\", &y ) ||\n\t\t!get_bprop( xnode, \"open\", &col->open ) ||\n\t\t!get_bprop( xnode, \"selected\", &col->selected ) ||\n\t\t!get_iprop( xnode, \"next\", &col->next ) )\n\t\treturn( FALSE );\n\n\tcol->x = x + column_left_offset;\n\tcol->y = y + column_top_offset;\n\n\t/* Don't use iobject_set(): we don't want to trigger _changed during\n\t * load.\n\t */\n\tif( get_sprop( xnode, \"caption\", buf, 256 ) ) {\n\t\tIM_SETSTR( IOBJECT( col )->caption, buf );\n\t}\n\tif( get_sprop( xnode, \"name\", buf, 256 ) ) {\n\t\tIM_SETSTR( IOBJECT( col )->name, buf );\n\t}\n\n\tcolumn_set_last_new( col );\n\n\treturn( MODEL_CLASS( parent_class )->load( model, \n\t\tstate, parent, xnode ) );\n}\n\nstatic void\ncolumn_class_init( ColumnClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tiContainerClass *icontainer_class = (iContainerClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tFilemodelClass *filemodel_class = (FilemodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = column_finalize;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tiobject_class->user_name = _( \"Column\" );\n\n\ticontainer_class->child_add = column_child_add;\n\ticontainer_class->child_remove = column_child_remove;\n\ticontainer_class->parent_add = column_parent_add;\n\n\tmodel_class->view_new = column_view_new;\n\tmodel_class->save = column_save;\n\tmodel_class->save_test = column_save_test;\n\tmodel_class->load = column_load;\n\n\tfilemodel_class->filetype = filesel_type_workspace;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\ncolumn_init( Column *col )\n{\n#ifdef DEBUG\n\tprintf( \"column_init\\n\" );\n#endif /*DEBUG*/\n\n\tcol->scol = NULL;\n\tcol->ws = NULL;\n\n        col->x = 0;\n        col->y = 0;\n        col->open = TRUE;\n        col->selected = FALSE;\n\n        col->next = 1;\n        col->last_select = NULL;\n}\n\nGType\ncolumn_get_type( void )\n{\n\tstatic GType column_type = 0;\n\n\tif( !column_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ColumnClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) column_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Column ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) column_init,\n\t\t};\n\n\t\tcolumn_type = g_type_register_static( TYPE_FILEMODEL, \n\t\t\t\"Column\", &info, 0 );\n\t}\n\n\treturn( column_type );\n}\n\nColumn *\ncolumn_new( Workspace *ws, const char *name )\n{\n\tColumn *col;\n\n\tif( workspace_column_find( ws, name ) ) {\n\t\terror_top( _( \"Name clash.\" ) );\n\t\terror_sub( _( \"Can't create column \\\"%s\\\". A column with that \"\n\t\t\t\"name already exists.\" ), name );\n\t\treturn( NULL );\n\t}\n\n\tcol = COLUMN( g_object_new( TYPE_COLUMN, NULL ) );\n\tiobject_set( IOBJECT( col ), name, NULL );\n\ticontainer_child_add( ICONTAINER( ws ), ICONTAINER( col ), -1 );\n\n        subcolumn_new( NULL, col );\n\n\tcol->x = ws->vp.left + 50;\n\tcol->y = ws->vp.top;\n\n\tcolumn_set_last_new( col );\n\n\treturn( col );\n}\n\nColumn *\ncolumn_get_last_new( void )\n{\n\treturn( column_last_new ); \n}\n\nvoid\ncolumn_clear_last_new( void )\n{\n\tcolumn_last_new = NULL; \n}\n\n/* Find the bottom of the column.\n */\nRow *\ncolumn_get_bottom( Column *col )\n{\n\tSubcolumn *scol = col->scol;\n\tGSList *children = ICONTAINER( scol )->children;\n\n\tif( children ) {\n\t\tRow *row = ROW( g_slist_last( children )->data );\n\n\t\treturn( row );\n\t}\n\n\treturn( NULL );\n}\n\n/* Add the last n names from a column to a buffer. Error if there are too few \n * there.\n */\ngboolean\ncolumn_add_n_names( Column *col, const char *name, VipsBuf *buf, int nparam )\n{\n\tSubcolumn *scol = col->scol;\n\tGSList *children = ICONTAINER( scol )->children;\n\tint len = g_slist_length( children );\n\tGSList *i;\n\n\tg_assert( nparam >= 0 );\n\n\tif( nparam > 0 && nparam > len ) {\n\t\terror_top( _( \"Too few items.\" ) );\n\t\terror_sub( _( \"This column only has %d items, \"\n\t\t\t\"but %s needs %d items.\" ), len, name, nparam );\n\t\treturn( FALSE );\n\t}\n\n\tfor( i = g_slist_nth( children, len - nparam ); i; i = i->next ) {\n\t\tRow *row = ROW( i->data );\n\n\t\tif( row->sym ) { \n\t\t\tvips_buf_appends( buf, \" \" );\n\t\t\tvips_buf_appends( buf, IOBJECT( row->sym )->name );\n\t\t}\n\t}\n\n\treturn( TRUE );\n}\n\n/* Is a column empty?\n */\ngboolean\ncolumn_is_empty( Column *col )\n{\n\tSubcolumn *scol = col->scol;\n\tGSList *children = ICONTAINER( scol )->children;\n\n\treturn( children == NULL );\n}\n\n/* Set the load/save offsets.\n */\nvoid\ncolumn_set_offset( int x_off, int y_off )\n{\n#ifdef DEBUG\n\tprintf( \"column_set_offset: load offset %d x %d\\n\", x_off, y_off );\n#endif /*DEBUG*/\n\n\tcolumn_left_offset = x_off;\n\tcolumn_top_offset = y_off;\n}\n\nchar *\ncolumn_name_new( Column *col )\n{\n\tchar buf[256];\n\n\tdo {\n\t\tim_snprintf( buf, 256, \"%s%d\", \n\t\t\tIOBJECT( col )->name, col->next++ );\n\t} while( compile_lookup( col->ws->sym->expr->compile, buf ) );\n\n\treturn( im_strdup( NULL, buf ) );\n}\n\nvoid \ncolumn_set_open( Column *col, gboolean open )\n{\n        if( col->open != open ) {\n\t\tWorkspace *ws = col->ws;\n\n\t\tcol->open = open;\n\t\tworkspace_set_modified( ws, TRUE );\n\t\tiobject_changed( IOBJECT( col ) );\n\t}\n}\n\nstatic gboolean\ncolumn_scrollto_timeout_cb( Column *col )\n{\n#ifdef DEBUG\n\tprintf( \"column_scrollto_timeout_cb: %p\\n\", col ); \n#endif /*DEBUG*/\n\n\tcol->scrollto_timeout = 0;\n\tmodel_scrollto( MODEL( col ), col->pending_position ); \n\n\treturn( FALSE );\n}\n\nvoid\ncolumn_scrollto( Column *col, ModelScrollPosition position )\n{\n#ifdef DEBUG\n\tprintf( \"column_scrollto: %p %s\\n\", col, IOBJECT( col )->name );\n#endif /*DEBUG*/\n\n\tIM_FREEF( g_source_remove, col->scrollto_timeout );\n\tcol->pending_position = position; \n\n\t/* We need a longer timeout here than the one in mainw_layout().\n\t */\n\tcol->scrollto_timeout = g_timeout_add( 400, \n\t\t(GSourceFunc) column_scrollto_timeout_cb, col );\n}\n"
  },
  {
    "path": "src/column.h",
    "content": "/* a column in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_COLUMN (column_get_type())\n#define COLUMN( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_COLUMN, Column ))\n#define COLUMN_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_COLUMN, ColumnClass))\n#define IS_COLUMN( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_COLUMN ))\n#define IS_COLUMN_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_COLUMN ))\n#define COLUMN_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_COLUMN, ColumnClass ))\n\nstruct _Column {\n\tFilemodel parent_object;\n\n\t/* Our context.\n\t */\n\tSubcolumn *scol;\t/* Subcolumn we enclose */\n\tWorkspace *ws;\t\t/* Enclosing workspace */\n\n        /* Appearance state info.\n         */\n        int x, y;\t\t/* Position */\n        gboolean open;\t\t/* Currently popped down */\n        gboolean selected;\n\n\t/* Other state.\n\t */\n        int next;\t\t/* Index of next symbol we make */\n        Row *last_select;\t/* Last row clicked ... for x sel */\n\n\t/* A pending scrollto.\n\t */\n\tguint scrollto_timeout;\n\tModelScrollPosition pending_position;\n};\n\ntypedef struct _ColumnClass {\n\tFilemodelClass parent_class;\n\n\t/* My methods.\n\t */\n} ColumnClass;\n\nvoid *column_map( Column *col, row_map_fn fn, void *a, void *b );\nvoid *column_map_symbol( Column *col, symbol_map_fn fn, void *a );\n\nvoid *column_select_symbols( Column *col );\n\nGtkType column_get_type( void );\n\nColumn *column_new( Workspace *ws, const char *name );\n\nColumn *column_get_last_new( void );\nvoid column_clear_last_new( void );\n\nRow *column_get_bottom( Column *col );\ngboolean column_add_n_names( Column *col, \n\tconst char *name, VipsBuf *buf, int nparam );\ngboolean column_is_empty( Column *col );\n\nvoid column_set_offset( int x_off, int y_off );\n\nchar *column_name_new( Column *col );\n\nvoid column_set_open( Column *col, gboolean open );\n\nvoid column_scrollto( Column *col, ModelScrollPosition position );\n"
  },
  {
    "path": "src/columnview.c",
    "content": "/* a view of a column\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\n/* The columnview popup menu.\n */\nstatic GtkWidget *columnview_menu = NULL;\n\n/* Edit caption ... right button menu on title bar.\n */\nstatic void\ncolumnview_caption_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview )\n{\n        /* Edit caption!\n         */\n        if( cview->state == COL_EDIT )\n                return;\n\n        cview->state = COL_EDIT;\n        vobject_refresh_queue( VOBJECT( cview ) );\n}\n\n/* Select all objects in menu's column.\n */\nstatic void\ncolumnview_select_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview )\n{\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\tWorkspace *ws = col->ws;\n\n\tworkspace_deselect_all( ws );\n        column_select_symbols( col );\n}\n\n/* Clone a column.\n */\nstatic void\ncolumnview_clone_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview )\n{\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\tWorkspace *ws = col->ws;\n\n\tchar new_name[MAX_STRSIZE];\n        Column *newcol;\n\n\tworkspace_column_name_new( ws, new_name );\n        newcol = workspace_column_get( ws, new_name );\n        iobject_set( IOBJECT( newcol ), NULL, IOBJECT( col )->caption );\n        newcol->x = col->x + 100;\n        newcol->y = col->y;\n\n\tworkspace_deselect_all( ws );\n        column_select_symbols( col );\n\tworkspace_column_select( ws, newcol );\n        if( !workspace_selected_duplicate( ws ) )\n\t\tiwindow_alert( GTK_WIDGET( cview ), GTK_MESSAGE_ERROR );\n\tworkspace_deselect_all( ws );\n\n        symbol_recalculate_all();\n}\n\nstatic void\ncolumnview_merge_sub( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( iwnd );\n\tColumn *col = COLUMN( client );\n\tWorkspace *ws = col->ws;\n\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\n\tchar *filename;\n\tiWindowResult result;\n\n\tresult = IWINDOW_YES;\n\tprogress_begin();\n\n\tif( (filename = filesel_get_filename( filesel )) ) {\n\t\tif( !workspacegroup_merge_rows( wsg, filename ) ) \n\t\t\tresult = IWINDOW_ERROR;\n\n\t\tg_free( filename );\n\t}\n\n\tsymbol_recalculate_all();\n\tprogress_end();\n\n\tnfn( sys, result );\n}\n\nstatic void\ncolumnview_merge_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview )\n{\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\tiWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( cview ) ) );\n\tGtkWidget *filesel = filesel_new();\n\n\tiwindow_set_title( IWINDOW( filesel ), \n\t\t_( \"Merge Into Column \\\"%s\\\"\" ), IOBJECT( col )->name );\n\tfilesel_set_flags( FILESEL( filesel ), FALSE, FALSE );\n\tfilesel_set_filetype( FILESEL( filesel ), filesel_type_workspace, 0 ); \n\tiwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( iwnd ) );\n\tidialog_set_iobject( IDIALOG( filesel ), IOBJECT( col ) );\n\tfilesel_set_done( FILESEL( filesel ), columnview_merge_sub, col );\n\tiwindow_build( IWINDOW( filesel ) );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\n/* Callback from save browser.\n */\nstatic void\ncolumnview_save_as_sub( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( iwnd );\n\tColumn *col = COLUMN( client );\n\tWorkspace *ws = col->ws;\n\tchar *filename;\n\n\tworkspace_deselect_all( ws );\n        column_select_symbols( col );\n\n\tif( (filename = filesel_get_filename( filesel )) ) {\n\t\tif( workspace_selected_save( ws, filename ) ) {\n\t\t\tworkspace_deselect_all( ws );\n\t\t\tnfn( sys, IWINDOW_YES );\n\t\t}\n\t\telse\n\t\t\tnfn( sys, IWINDOW_ERROR );\n\n\t\tg_free( filename );\n\t}\n\telse\n\t\tnfn( sys, IWINDOW_ERROR );\n}\n\n/* Save a column ... can't just do view_save_as_cb(), since we need to save\n * the enclosing workspace too. Hence we have to save_selected on the ws, but\n * only after we have the filename.\n */\nstatic void\ncolumnview_save_as_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview )\n{\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\tiWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( cview ) ) );\n\tGtkWidget *filesel = filesel_new();\n\n\tiwindow_set_title( IWINDOW( filesel ), \n\t\t_( \"Save Column \\\"%s\\\"\" ), IOBJECT( col )->name );\n\tfilesel_set_flags( FILESEL( filesel ), FALSE, TRUE );\n\tfilesel_set_filetype( FILESEL( filesel ), filesel_type_workspace, 0 ); \n\tiwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( iwnd ) );\n\tidialog_set_iobject( IDIALOG( filesel ), IOBJECT( col ) );\n\tfilesel_set_done( FILESEL( filesel ), columnview_save_as_sub, col );\n\tiwindow_build( IWINDOW( filesel ) );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\n/* Make a name for a column menu file, based on what we're going to call the\n * menu item.\n */\nstatic void\ncolumnview_filename( char *file, const char *caption )\n{\n\tint i;\n\tchar name[FILENAME_MAX];\n\n\tim_strncpy( name, caption, 10 );\n\tfor( i = 0; i < strlen( name ); i++ )\n\t\tif( name[i] == ' ' )\n\t\t\tname[i] = '_';\n\n\tfor( i = 0; ; i++ ) {\n\t\tim_snprintf( file, FILENAME_MAX, \n\t\t\t\"$SAVEDIR\" G_DIR_SEPARATOR_S \"data\" G_DIR_SEPARATOR_S \n\t\t\t\"%s-%d.ws\", name, i );\n\t\tif( !existsf( \"%s\", file ) )\n\t\t\tbreak;\n\t}\n}\n\n/* Remember the name of the last toolkit the user asked to add to.\n */\nstatic char *columnview_to_menu_last_toolkit = NULL;\n\n/* Done button hit.\n */\nstatic void\ncolumnview_to_menu_done_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tColumn *col = COLUMN( client );\n\tWorkspace *ws = col->ws;\n\tStringset *ss = STRINGSET( iwnd );\n\tStringsetChild *name = stringset_child_get( ss, _( \"Name\" ) );\n\tStringsetChild *toolkit = stringset_child_get( ss, _( \"Toolkit\" ) );\n\tStringsetChild *file = stringset_child_get( ss, _( \"Filename\" ) );\n\n\tchar name_text[1024];\n\tchar toolkit_text[1024];\n\tchar file_text[1024];\n\n\tif( !get_geditable_string( name->entry, name_text, 1024 ) ||\n\t\t!get_geditable_name( toolkit->entry, toolkit_text, 1024 ) ||\n\t\t!get_geditable_filename( file->entry, file_text, 1024 ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\t/* Save column to file.\n\t */\n\tworkspace_deselect_all( ws );\n        column_select_symbols( col );\n\n\tif( !workspace_selected_save( ws, file_text ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tworkspace_deselect_all( ws );\n\n\tif( !tool_new_dia( toolkit_by_name( ws->kitg, toolkit_text ), \n\t\t-1, name_text, file_text ) ) {\n\t\tunlinkf( \"%s\", file_text );\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tIM_SETSTR( columnview_to_menu_last_toolkit, toolkit_text );\n\n\tnfn( sys, IWINDOW_YES );\n}\n\n/* Make a column into a menu item. \n */\nstatic void\ncolumnview_to_menu_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview )\n{\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\tiWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( cview ) ) );\n\tGtkWidget *ss = stringset_new();\n\tchar *name;\n\tchar *kit_name;\n\tchar filename[FILENAME_MAX];\n\n\tif( !(name = IOBJECT( col )->caption) )\n\t\tname = \"untitled\";\n\tcolumnview_filename( filename, name );\n\n\tif( columnview_to_menu_last_toolkit )\n\t\tkit_name = columnview_to_menu_last_toolkit;\n\telse\n\t\tkit_name = \"untitled\";\n\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Name\" ), name, _( \"Set menu item text here\" ) );\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Toolkit\" ), kit_name, _( \"Add to this toolkit\" ) );\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Filename\" ), filename, _( \"Store column in this file\" ) );\n\n\tiwindow_set_title( IWINDOW( ss ), \n\t\t_( \"New Menu Item from Column \\\"%s\\\"\" ), IOBJECT( col )->name );\n\tidialog_set_callbacks( IDIALOG( ss ), \n\t\tiwindow_true_cb, NULL, NULL, col );\n\tidialog_set_help_tag( IDIALOG( ss ), \"sec:diaref\" );\n\tidialog_add_ok( IDIALOG( ss ), columnview_to_menu_done_cb, \n\t\t_( \"Menuize\" ) );\n\tiwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( iwnd ) );\n\tiwindow_build( IWINDOW( ss ) );\n\n\tgtk_widget_show( ss );\n}\n\n/* Find the position and size of a columnview.\n */\nvoid\ncolumnview_get_position( Columnview *cview, int *x, int *y, int *w, int *h )\n{\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\n        if( GTK_WIDGET( cview )->allocation.x < 2 || \n\t\tGTK_WIDGET( cview )->allocation.y < 2 ) {\n                /* Nothing there yet, guess.\n                 */\n\t\t*x = col->x; \n\t\t*y = col->y;\n                *w = 200;\n                *h = 50;\n        }\n        else {\n                *x = GTK_WIDGET( cview )->allocation.x;\n                *y = GTK_WIDGET( cview )->allocation.y;\n                *w = GTK_WIDGET( cview )->allocation.width;\n                *h = GTK_WIDGET( cview )->allocation.height;\n\n#ifdef DEBUG\n\t\tprintf( \"columnview_get_position: %s, \"\n\t\t\t\"x = %d, y = %d, w = %d, h = %d\\n\",\n\t\t\tIOBJECT( col )->name, *x, *y, *w, *h );\n#endif /*DEBUG*/\n        }\n}\n\n/* Transition functions for mouse stuff on columnviews.\n */\nstatic void\ncolumnview_left_press( Columnview *cview, GdkEvent *ev )\n{\n\tWorkspaceview *wview = cview->wview;\n\n        int ix, iy;\n        int jx, jy;\n        int kx, ky;\n        int wx, wy, ww, wh;\n\n#ifdef DEBUG\n\tprintf( \"columnview_left_press\\n\" );\n#endif /*DEBUG*/\n\n        /* Find pos of columnview.\n         */\n        columnview_get_position( cview, &wx, &wy, &ww, &wh );\n\n        /* Position in virtual tally window.\n         */\n        ix = ev->button.x + wx;\n        iy = ev->button.y + wy;\n\n        /* Position in tally viewport.\n         */\n        jx = ix - wview->vp.left;\n        jy = iy - wview->vp.top;\n\n        /* So ... position of top LH corner of tally viewport in root window.\n         */\n        kx = ev->button.x_root - jx;\n        ky = ev->button.y_root - jy;\n\n        switch( cview->state ) {\n        case COL_WAIT:\n                cview->state = COL_SELECT;\n\n                /* Record offset of mouse in columnview title bar.\n                 */\n                cview->rx = ev->button.x;\n                cview->ry = ev->button.y;\n\n                /* Position of tally window in root window.\n                 */\n                cview->tx = kx;\n                cview->ty = ky;\n\n                /* Start position of mouse in virtual tally window.\n                 */\n                cview->sx = ix;\n                cview->sy = iy;\n\n                break;\n\n        case COL_SELECT:\n        case COL_DRAG:\n        case COL_EDIT:\n                break;\n\n        default:\n\t\tg_assert( FALSE );\n        }\n}\n\nstatic void\ncolumnview_add_shadow( Columnview *old_cview )\n{\n\tColumn *col = COLUMN( VOBJECT( old_cview )->iobject );\n\tWorkspaceview *wview = old_cview->wview;\n\n\tif( !old_cview->shadow ) { \n\t\tColumnview *new_cview;\n\n\t\tnew_cview = COLUMNVIEW( columnview_new() ); \n\t\tnew_cview->wview = wview; \n\t\tVIEW( new_cview )->parent = VIEW( wview ); \n\t\tVOBJECT( new_cview )->iobject = IOBJECT( col ); \n\n\t\tgtk_fixed_put( GTK_FIXED( wview->fixed ),\n\t\t\tGTK_WIDGET( new_cview ), col->x, col->y );\n\n\t\tgtk_widget_show( GTK_WIDGET( new_cview ) ); \n\n\t\told_cview->shadow = new_cview;\n\t\tnew_cview->master = old_cview;\n\n\t\t/* The shadow will be on top of the real column and hide it. \n\t\t * Put the real column to the front.\n\t\t */\n\t\tmodel_front( MODEL( col ) ); \n\t}\n}\n\nstatic void\ncolumnview_left_motion( Columnview *cview, GdkEvent *ev )\n{\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\tWorkspace *ws = col->ws;\n\tWorkspaceview *wview = cview->wview;\n\n\tint u, v;\n\n        /* Posn of pointer in tally viewport.\n         */\n        int ix = ev->motion.x_root - cview->tx;\n        int iy = ev->motion.y_root - cview->ty;\n\n        /* Posn in virtual tally cods.\n         */\n        int jx = ix + wview->vp.left;\n        int jy = iy + wview->vp.top;\n\n        /* Amount of drag since we started.\n         */\n        int xoff = jx - cview->sx;\n        int yoff = jy - cview->sy;\n\n        /* New columnview position.\n         */\n        int xnew = IM_MAX( 0, jx - cview->rx );\n        int ynew = IM_MAX( 0, jy - cview->ry );\n\n#ifdef DEBUG\n\tprintf( \"columnview_left_motion\\n\" );\n#endif /*DEBUG*/\n\n        switch( cview->state ) {\n        case COL_EDIT:\n        case COL_WAIT:\n                break;\n\n        case COL_SELECT:\n                /* How much drag?\n                 */\n                if( abs( xoff ) > 5 || abs( yoff ) > 5 ) {\n                        cview->state = COL_DRAG;\n\t\t\tworkspaceview_set_cursor( wview, IWINDOW_SHAPE_MOVE );\n\t\t\tgtk_grab_add( cview->title ); \n\n\t\t\tcolumnview_add_shadow( cview );\n                }\n\n                break;\n\n        case COL_DRAG:\n\t\tcol->x = xnew;\n\t\tcol->y = ynew;\n\n\t\tiobject_changed( IOBJECT( col ) );\n\n#ifdef DEBUG\n\t\tprintf( \"drag columnview: x=%d, y=%d\", col->x, col->y );\n#endif /*DEBUG*/\n\n                /* Set vars for bg scroll.\n                 */\n\t\tu = 0;\n                if( ix > wview->vp.width )\n                        u = 10;\n                else if( ix < 0 )\n                        u = -10;\n\n\t\tv = 0;\n                if( iy > wview->vp.height )\n                        v = 10;\n                else if( iy < 0 )\n                        v = -10;\n\n\t\tworkspaceview_scroll_background( wview, u, v );\n\n\t\t/* Move other columns about.\n\t\t */\n\t\tmodel_layout( MODEL( ws ) ); \n\n                break;\n\n        default:\n\t\tg_assert( FALSE );\n        }\n}\n\nstatic void\ncolumnview_left_release( Columnview *cview, GdkEvent *ev )\n{\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\tWorkspace *ws = col->ws;\n\tWorkspaceview *wview = cview->wview;\n\n#ifdef DEBUG\n\tprintf( \"columnview_left_release\\n\" );\n#endif /*DEBUG*/\n\n        /* Back to wait.\n         */\n        switch( cview->state ) {\n        case COL_SELECT:\n                cview->state = COL_WAIT;\n                workspace_column_select( ws, col );\n\n                break;\n\n        case COL_DRAG:\n                cview->state = COL_WAIT;\n\t\tworkspaceview_scroll_background( wview, 0, 0 );\n\t\tworkspaceview_set_cursor( wview, IWINDOW_SHAPE_NONE );\n\t\tgtk_grab_remove( cview->title ); \n\t\tDESTROY_GTK( cview->shadow ); \n\n\t\t/* Move columns to their final position.\n\t\t */\n\t\tmodel_layout( MODEL( ws ) ); \n\t\tworkspace_set_modified( ws, TRUE );\n\n                break;\n\n        case COL_EDIT:\n        case COL_WAIT:\n                break;\n\n        default:\n                g_assert( FALSE );\n        }\n}\n\n/* Event in columnview title bar.\n */\nstatic gboolean\ncolumnview_title_event_cb( GtkWidget *widget, GdkEvent *ev, Columnview *cview )\n{\n\tgboolean handled = FALSE;\n\n#ifdef DEBUG\n{\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\n\tprintf( \"columnview_title_event_cb: %s %d\\n\", \n\t\tIOBJECT( col )->name, \n\t\tev->type );\n}\n#endif /*DEBUG*/\n\n        switch( ev->type ) {\n        case GDK_BUTTON_PRESS:\n                if( ev->button.button == 1 ) {\n                        columnview_left_press( cview, ev );\n                        handled = TRUE;\n                }\n\n                break;\n\n        case GDK_2BUTTON_PRESS:\n                if( ev->button.button == 1 ) {\n\t\t\tif( cview->state != COL_EDIT ) {\n\t\t\t\tcview->state = COL_EDIT;\n\t\t\t\tvobject_refresh_queue( VOBJECT( cview ) );\n\t\t\t}\n                        handled = TRUE;\n                }\n\n                break;\n\n        case GDK_MOTION_NOTIFY:\n                if( ev->motion.state & GDK_BUTTON1_MASK ) {\n                        columnview_left_motion( cview, ev );\n                        handled = TRUE;\n                }\n\n                break;\n\n        case GDK_BUTTON_RELEASE:\n                if( ev->button.button == 1 ) {\n                        columnview_left_release( cview, ev );\n                        handled = TRUE;\n                }\n\n                break;\n\n        default:\n                break;\n        }\n\n        return( handled );\n}\n\nstatic void \ncolumnview_destroy( GtkObject *object )\n{\n\tColumnview *cview;\n\tColumn *col;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_COLUMNVIEW( object ) );\n\n\tcview = COLUMNVIEW( object );\n\tcol = COLUMN( VOBJECT( cview )->iobject );\n\n#ifdef DEBUG\n\tprintf( \"columnview_destroy:\\n\" );\n#endif /*DEBUG*/\n\n\tDESTROY_GTK( cview->shadow );\n\n\t/* The column has gone .. relayout.\n\t */\n\tif( col &&\n\t\tcol->ws ) {\n\t\tworkspace_set_needs_layout( col->ws, TRUE ); \n\t\tmainw_layout();\n\t}\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\ncolumnview_size_allocate( GtkWidget *widget, GtkAllocation *allocation )\n{\n\tColumnview *cview = COLUMNVIEW( widget ); \n\n\tif( cview->old_width != allocation->width ||\n\t\tcview->old_height != allocation->height ) { \n\t\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\t\tWorkspace *ws = col->ws;\n\n\t\tcview->old_width = allocation->width;\n\t\tcview->old_height = allocation->height;\n\n\t\tworkspace_set_needs_layout( ws, TRUE ); \n\t\tmainw_layout();\n\t}\n\n\tGTK_WIDGET_CLASS( parent_class )->size_allocate( widget, allocation );\n}\n\n/* Arrow button on title bar.\n */\nstatic void\ncolumnview_updown_cb( GtkWidget *wid, Columnview *cview )\n{\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\n\tcolumn_set_open( col, !col->open );\n}\n\n/* Delete this column from the popup menu.\n */\nstatic void\ncolumnview_destroy_cb( GtkWidget *wid, GtkWidget *host, Columnview *cview )\n{\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\n\tmodel_check_destroy( view_get_toplevel( VIEW( cview ) ), \n\t\tMODEL( col ), NULL );\n}\n\n/* Delete this column with a click on the 'x' button.\n */\nstatic void\ncolumnview_destroy2_cb( GtkWidget *wid, Columnview *cview )\n{\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\n\tmodel_check_destroy( view_get_toplevel( VIEW( cview ) ), \n\t\tMODEL( col ), NULL );\n}\n\n/* Callback for enter in caption edit box.\n */\nstatic void\ncolumnview_caption_enter_cb( GtkWidget *wid, Columnview *cview )\n{\n        const char *text = gtk_entry_get_text( GTK_ENTRY( cview->capedit ) );\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\tWorkspace *ws = col->ws;\n\n        cview->state = COL_WAIT;\n\tiobject_changed( IOBJECT( col ) );\n\n\tif( strcmp( text, \"\" ) != 0 ) \n\t\tiobject_set( IOBJECT( col ), NULL, text );\n\n\tworkspace_set_modified( ws, TRUE );\n\n\t/* The ws view needs to update the jumpto menus.\n\t */\n\tiobject_changed( IOBJECT( ws ) );\n}\n\n/* Detect cancel in a caption field.\n */\nstatic gboolean\ncolumnview_caption_cancel_cb( GtkWidget *widget, \n\tGdkEvent *ev, Columnview *cview )\n{\n        if( ev->type != GDK_KEY_PRESS || ev->key.keyval != GDK_Escape )\n                return( FALSE );\n\n        /* Turn off edit.\n         */\n        cview->state = COL_WAIT;\n        vobject_refresh_queue( VOBJECT( cview ) );\n\n        return( TRUE );\n}\n\n/* Add a caption entry to a columnview if not there.\n */\nstatic void\ncolumnview_add_caption( Columnview *cview )\n{\n        if( cview->capedit )\n                return;\n\n        cview->capedit = gtk_entry_new();\n\tgtk_entry_set_has_frame( GTK_ENTRY( cview->capedit ), FALSE );\n        gtk_box_pack_start( GTK_BOX( cview->titlehb ),\n                cview->capedit, FALSE, FALSE, 0 );\n        set_tooltip( cview->capedit, _( \"Edit caption, press enter to \"\n                \"accept changes, press escape to cancel\" ) );\n\n        gtk_signal_connect( GTK_OBJECT( cview->capedit ), \"activate\",\n                GTK_SIGNAL_FUNC( columnview_caption_enter_cb ), cview );\n        gtk_signal_connect( GTK_OBJECT( cview->capedit ), \"event\",\n                GTK_SIGNAL_FUNC( columnview_caption_cancel_cb ), cview );\n}\n\n/* Callback for enter in new def widget.\n */\nstatic void\ncolumnview_text_enter_cb( GtkWidget *wid, Columnview *cview )\n{\n        const char *text = gtk_entry_get_text( GTK_ENTRY( cview->text ) );\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\tWorkspace *ws = col->ws;\n        Symbol *sym;\n\n        if( !text || strspn( text, WHITESPACE ) == strlen( text ) )\n\t\treturn;\n\n\tif( !(sym = workspace_add_def_recalc( ws, text )) ) {\n\t\tiwindow_alert( wid, GTK_MESSAGE_ERROR );\n\t\tsymbol_recalculate_all();\n\t\treturn;\n\t}\n\n\tset_gentry( cview->text, NULL );\n}\n\n/* Add bottom entry widget.\n */\nstatic void\ncolumnview_add_text( Columnview *cview )\n{\n        GtkWidget *inv;\n\n        if( cview->textfr )\n                return;\n\n        cview->textfr = gtk_hbox_new( FALSE, 0 );\n        gtk_box_pack_end( GTK_BOX( cview->vbox ), \n\t\tcview->textfr, FALSE, FALSE, 0 );\n        inv = gtk_label_new( \"\" );\n        gtk_box_pack_start( GTK_BOX( cview->textfr ), inv, FALSE, FALSE, 25 );\n        gtk_widget_show( inv );\n        cview->text = gtk_entry_new();\n        gtk_box_pack_start( GTK_BOX( cview->textfr ), \n\t\tcview->text, TRUE, TRUE, 0 );\n        gtk_signal_connect( GTK_OBJECT( cview->text ), \"activate\",\n                GTK_SIGNAL_FUNC( columnview_text_enter_cb ), cview );\n        gtk_widget_show( cview->text );\n        set_tooltip( cview->text, _( \"Enter expressions here\" ) );\n}\n\nstatic void \ncolumnview_refresh( vObject *vobject )\n{\n\tColumnview *cview = COLUMNVIEW( vobject );\n\tColumnview *shadow = cview->shadow;\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\tgboolean editable = col->ws->mode != WORKSPACE_MODE_NOEDIT;\n\n#ifdef DEBUG\n\tprintf( \"columnview_refresh: %s\\n\", IOBJECT( col )->name );\n#endif /*DEBUG*/\n\n\t/* If this column has a shadow, workspaceview will have put a layout\n\t * position into it. See workspaceview_layout_set_pos(). \n\t */\n\tif( shadow )  \n\t\tview_child_position( VIEW( shadow ) ); \n\n\tif( shadow ) {\n\t\tgtk_widget_set_size_request( GTK_WIDGET( shadow->frame ), \n\t\t\tGTK_WIDGET( cview->frame )->allocation.width, \n\t\t\tGTK_WIDGET( cview->frame )->allocation.height );\n\t\tgtk_frame_set_shadow_type( GTK_FRAME( shadow->frame ),\n\t\t\tGTK_SHADOW_IN );\n\t}\n\n\n\tif( col->x != cview->lx || \n\t\tcol->y != cview->ly ) {\n#ifdef DEBUG\n\t\tprintf( \"columnview_refresh: move column %s to %d x %d\\n\",\n\t\t\tIOBJECT( col )->name, col->x, col->y );\n#endif /*DEBUG*/\n\n\t\tcview->lx = col->x;\n\t\tcview->ly = col->y;\n\t\tview_child_position( VIEW( cview ) ); \n\n\t\t/* Update the save offset hints too.\n\t\t */\n\t\tfilemodel_set_offset( FILEMODEL( col ), cview->lx, cview->ly );\n\t}\n\n\t/* Turn titlebar on/off.\n\t */\n\twidget_visible( cview->title, editable );\n\tif( editable ) \n\t\tgtk_frame_set_label( GTK_FRAME( cview->frame ), NULL );\n\telse if( IOBJECT( col )->caption ) {\n\t\tGtkWidget *label;\n\t\tchar buf[256];\n\t\tchar buf2[256];\n\n\t\tgtk_frame_set_label( GTK_FRAME( cview->frame ), \"x\" );\n\t\tlabel = gtk_frame_get_label_widget( GTK_FRAME( cview->frame ) );\n\t\tescape_markup( IOBJECT( col )->caption, buf2, 256 );\n\t\tim_snprintf( buf, 256, \"<b>%s</b>\", buf2 );\n\t\tgtk_label_set_markup( GTK_LABEL( label ), buf );\n\t\tgtk_misc_set_padding( GTK_MISC( label ), 2, 6 );\n\t}\n\n\t/* Update names.\n\t */\n        set_glabel( cview->lab, \"%s - \", IOBJECT( col )->name );\n        if( IOBJECT( col )->caption )\n\t\tset_glabel( cview->head, \"%s\", IOBJECT( col )->caption );\n\telse {\n\t\tchar buf[256];\n\n\t\tim_snprintf( buf, 256, \"<i>%s</i>\", \n\t\t\t_( \"doubleclick to set title\" ) );\n\t\tgtk_label_set_markup( GTK_LABEL( cview->head ), buf );\n\t}\n\n\t/* Set open/closed.\n\t */\n\tif( col->open ) {\n                gtk_arrow_set( GTK_ARROW( cview->updown ),\n                        GTK_ARROW_DOWN, GTK_SHADOW_OUT );\n                set_tooltip( cview->updownb, _( \"Fold the column away\" ) );\n\t}\n\telse {\n                gtk_arrow_set( GTK_ARROW( cview->updown ),\n                        GTK_ARROW_RIGHT, GTK_SHADOW_OUT );\n                set_tooltip( cview->updownb, _( \"Open the column\" ) );\n\t}\n\tmodel_display( MODEL( col->scol ), col->open );\n\n\t/* Closed columns are hidden in NOEDIT mode.\n\t */\n\twidget_visible( GTK_WIDGET( cview ), editable || col->open );\n\n        /* Set caption edit.\n         */\n        if( cview->state == COL_EDIT ) {\n                columnview_add_caption( cview );\n\n                gtk_widget_show( cview->capedit );\n                gtk_widget_hide( cview->headfr );\n\n\t\tif( IOBJECT( col )->caption ) {\n\t\t\tset_gentry( cview->capedit, \"%s\", \n\t\t\t\tIOBJECT( col )->caption );\n\t\t\tgtk_editable_select_region( \n\t\t\t\tGTK_EDITABLE( cview->capedit ), 0, -1 );\n\t\t}\n                gtk_widget_grab_focus( cview->capedit );\n        }\n        else {\n                gtk_widget_show( cview->headfr );\n                DESTROY_GTK( cview->capedit );\n        }\n\n        /* Set bottom entry.\n         */\n        if( col->selected && \n\t\tcol->open && \n\t\teditable &&\n\t\t!cview->master ) {\n                columnview_add_text( cview );\n                gtk_widget_show( cview->textfr );\n        }\n        else\n                DESTROY_GTK( cview->textfr );\n\n\t/* Set select state.\n\t */\n        if( cview->master ) \n                gtk_widget_set_name( cview->title, \"shadow_widget\" );\n\telse if( col->selected && !cview->selected ) {\n                gtk_widget_set_name( cview->title, \"selected_widget\" );\n\t\tcview->selected = TRUE;\n\t\tif( cview->textfr )\n\t\t\tgtk_widget_grab_focus( cview->text );\n\t}\n        else if( !col->selected ) {\n\t\t/* Always do this, even if cview->selected, so we set on the\n\t\t * first _refresh().\n\t\t */\n                gtk_widget_set_name( cview->title, \"column_widget\" );\n\t\tcview->selected = FALSE;\n\t}\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\ncolumnview_link( View *view, Model *model, View *parent )\n{\n\tColumnview *cview = COLUMNVIEW( view );\n\tWorkspaceview *wview = WORKSPACEVIEW( parent );\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\tcview->wview = wview;\n}\n\nstatic void\ncolumnview_child_add( View *parent, View *child )\n{\n\tColumnview *cview = COLUMNVIEW( parent );\n\tSubcolumnview *sview = SUBCOLUMNVIEW( child );\n\n\tVIEW_CLASS( parent_class )->child_add( parent, child );\n\n\tgtk_container_add( GTK_CONTAINER( cview->frame ), GTK_WIDGET( sview ) );\n}\n\n/* Scroll to keep the text entry at the bottom of the columnview on screen.\n * We can't use the position/size of the text widget for positioning, since it\n * may not be properly realized yet ... make the bottom of the column visible\n * instead.\n */\nstatic void\ncolumnview_scrollto( View *view, ModelScrollPosition position )\n{\n\tColumnview *cview = COLUMNVIEW( view );\n\tWorkspaceview *wview = cview->wview;\n\tint x, y, w, h;\n\n\tcolumnview_get_position( cview, &x, &y, &w, &h );\n\n\tif( position == MODEL_SCROLL_BOTTOM )\n\t\t/* 35 is supposed to be enough to ensure the whole of the edit\n\t\t * box gets on the screen.\n\t\t */\n\t\tworkspaceview_scroll( wview, x, y + h, w, 35 );\n\telse\n\t\tworkspaceview_scroll( wview, \n\t\t\tx, y, w, cview->title->allocation.height );\n}\n\nstatic void\ncolumnview_class_init( ColumnviewClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tGtkWidgetClass *widget_class = (GtkWidgetClass *) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tGtkWidget *pane;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tobject_class->destroy = columnview_destroy;\n\n\twidget_class->size_allocate = columnview_size_allocate;\n\n\tvobject_class->refresh = columnview_refresh;\n\n\tview_class->link = columnview_link;\n\tview_class->child_add = columnview_child_add;\n\tview_class->scrollto = columnview_scrollto;\n\n\tpane = columnview_menu = popup_build( _( \"Column menu\" ) );\n\tpopup_add_but( pane, _( \"_Edit Caption\" ), \n\t\tPOPUP_FUNC( columnview_caption_cb ) );\n\tpopup_add_but( pane, _( \"Select _All\" ), \n\t\tPOPUP_FUNC( columnview_select_cb ) );\n\tpopup_add_but( pane, STOCK_DUPLICATE,\n\t\tPOPUP_FUNC( columnview_clone_cb ) );\n\tpopup_add_but( pane, _( \"Merge Into Column\" ),\n\t\tPOPUP_FUNC( columnview_merge_cb ) );\n\tpopup_add_but( pane, GTK_STOCK_SAVE_AS,\n\t\tPOPUP_FUNC( columnview_save_as_cb ) );\n\tmenu_add_sep( pane );\n\tpopup_add_but( pane, _( \"Make Column Into _Menu Item\" ),\n\t\tPOPUP_FUNC( columnview_to_menu_cb ) );\n\tmenu_add_sep( pane );\n\tpopup_add_but( pane, GTK_STOCK_DELETE,\n\t\tPOPUP_FUNC( columnview_destroy_cb ) );\n}\n\nstatic gboolean\ncolumnview_event_cb( GtkWidget *wid, GdkEvent *ev, Columnview *cview )\n{\n\tgboolean handled;\n\n\thandled = FALSE;\n\n        switch( ev->type ) {\n        case GDK_BUTTON_PRESS:\n                if( ev->button.button == 1 ) \n\t\t\t/* We want to sop our enclosing notebook seeing\n\t\t\t * left doubleclicks and creating new tabs. We want to\n\t\t\t * not block things like scroll events and\n\t\t\t * middle-drag.\n\t\t\t */\n                        handled = TRUE;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn( handled ); \n}\n\nstatic void\ncolumnview_init( Columnview *cview )\n{\n        GtkWidget *sb;\n        GtkWidget *frame;\n        GtkWidget *icon;\n        GtkWidget *but;\n\n        /* No position yet.\n         */\n        cview->lx = -1;\n        cview->ly = -1;\n\n\tcview->state = COL_WAIT;\n\tcview->selected = FALSE;\n\n\tcview->old_width = -1;\n\tcview->old_height = -1;\n\n        /* Make outer vb.\n         */\n        cview->main = gtk_event_box_new();\n\tgtk_widget_add_events( GTK_WIDGET( cview->main ), \n\t\tGDK_BUTTON_PRESS_MASK ); \n        cview->vbox = gtk_vbox_new( FALSE, 0 );\n        gtk_container_add( GTK_CONTAINER( cview->main ), cview->vbox );\n\n        /* Frame for whole title bar. Need an event_box to catch clicks.\n         */\n        cview->title = gtk_event_box_new();\n\tgtk_widget_add_events( GTK_WIDGET( cview->title ), \n\t\tGDK_POINTER_MOTION_MASK | \n\t\tGDK_POINTER_MOTION_HINT_MASK |\n\t\tGDK_BUTTON_PRESS_MASK | \n\t\tGDK_BUTTON_RELEASE_MASK ); \n        gtk_box_pack_start( GTK_BOX( cview->vbox ), \n\t\tcview->title, FALSE, FALSE, 0 );\n        set_tooltip( cview->title, _( \"Left-drag to move, left-double-click to \"\n                \"set title, right-click for menu\" ) );\n        frame = gtk_frame_new( NULL );\n        gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_NONE );\n        gtk_container_add( GTK_CONTAINER( cview->title ), frame );\n        popup_attach( cview->title, columnview_menu, cview );\n        gtk_signal_connect( GTK_OBJECT( cview->title ), \"event\",\n                GTK_SIGNAL_FUNC( columnview_title_event_cb ), cview );\n\n        /* Layout contents of title bar.\n         */\n        cview->titlehb = gtk_hbox_new( FALSE, 0 );\n        gtk_container_add( GTK_CONTAINER( frame ), cview->titlehb );\n\n        /* Up/down button.\n         */\n        cview->updownb = gtk_button_new();\n        gtk_button_set_relief( GTK_BUTTON( cview->updownb ), GTK_RELIEF_NONE );\n        gtk_container_set_border_width( GTK_CONTAINER( cview->updownb ), 0 );\n        gtk_box_pack_start( GTK_BOX( cview->titlehb ),\n                cview->updownb, FALSE, FALSE, 0 );\n        cview->updown = gtk_arrow_new( GTK_ARROW_DOWN, GTK_SHADOW_OUT );\n        gtk_container_add( GTK_CONTAINER( cview->updownb ), cview->updown );\n        gtk_signal_connect( GTK_OBJECT( cview->updownb ), \"clicked\",\n                GTK_SIGNAL_FUNC( columnview_updown_cb ), cview );\n\n        /* Remove columnview button.\n         */\n        sb = gtk_vbox_new( FALSE, 0 );\n        gtk_box_pack_end( GTK_BOX( cview->titlehb ), sb, FALSE, FALSE, 1 );\n        but = gtk_button_new();\n        gtk_button_set_relief( GTK_BUTTON( but ), GTK_RELIEF_NONE );\n        gtk_box_pack_start( GTK_BOX( sb ), but, TRUE, FALSE, 0 );\n        set_tooltip( but, _( \"Delete the column\" ) );\n\ticon = gtk_image_new_from_stock( GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU );\n        gtk_container_add( GTK_CONTAINER( but ), icon );\n        gtk_signal_connect( GTK_OBJECT( but ), \"clicked\",\n                GTK_SIGNAL_FUNC( columnview_destroy2_cb ), cview );\n\n        /* Columnview name.\n         */\n        cview->lab = gtk_label_new( \"\" );\n        gtk_box_pack_start( GTK_BOX( cview->titlehb ), \n\t\tcview->lab, FALSE, FALSE, 2 );\n\n        /* Comment. Wrap a frame around it, to make it the same size as\n         * an entry widget.\n         */\n        cview->headfr = gtk_frame_new( NULL );\n        gtk_frame_set_shadow_type( GTK_FRAME( cview->headfr ), \n\t\tGTK_SHADOW_NONE );\n        gtk_box_pack_start( GTK_BOX( cview->titlehb ),\n                cview->headfr, FALSE, FALSE, 0 );\n        cview->head = gtk_label_new( \"\" );\n        gtk_container_add( GTK_CONTAINER( cview->headfr ), cview->head );\n\n        /* Make centre table for tally roll.\n         */\n        cview->frame = gtk_frame_new( NULL );\n\tgtk_frame_set_shadow_type( GTK_FRAME( cview->frame ),\n\t\tGTK_SHADOW_NONE );\n        gtk_box_pack_start( GTK_BOX( cview->vbox ), \n\t\tcview->frame, TRUE, TRUE, 0 );\n\n        gtk_box_pack_start( GTK_BOX( cview ), cview->main, FALSE, FALSE, 0 );\n\n\t/* We need to stop our enclosing thing seeing doubeclicks and all\n\t * that.\n\t */\n\tgtk_signal_connect( GTK_OBJECT( cview ), \"event\", \n\t\tGTK_SIGNAL_FUNC( columnview_event_cb ), cview );\n\n        gtk_widget_show_all( GTK_WIDGET( cview ) );\n}\n\nGtkType\ncolumnview_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Columnview\",\n\t\t\tsizeof( Columnview ),\n\t\t\tsizeof( ColumnviewClass ),\n\t\t\t(GtkClassInitFunc) columnview_class_init,\n\t\t\t(GtkObjectInitFunc) columnview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_VIEW, &info );\n\t}\n\n\treturn( type );\n}\n\nView *\ncolumnview_new( void )\n{\n\tColumnview *cview = gtk_type_new( TYPE_COLUMNVIEW );\n\n\treturn( VIEW( cview ) );\n}\n\n"
  },
  {
    "path": "src/columnview.h",
    "content": "/* view of a column\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_COLUMNVIEW (columnview_get_type())\n#define COLUMNVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_COLUMNVIEW, Columnview ))\n#define COLUMNVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_COLUMNVIEW, ColumnviewClass ))\n#define IS_COLUMNVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_COLUMNVIEW ))\n#define IS_COLUMNVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_COLUMNVIEW ))\n\n/* State ... for mouse titlebar interactions.\n */\ntypedef enum {\n\tCOL_WAIT,\t\t/* Rest state */\n\tCOL_SELECT,\t\t/* Select start, but no drag yet */\n\tCOL_DRAG,\t\t/* Drag state */\n        COL_EDIT\t\t/* Editing caption */\n} ColumnviewState;\n\nstruct _Columnview {\n\tView view;\n\n\t/* Our enclosing workspaceview.\n\t */\n\tWorkspaceview *wview;\n\n        /* Display parts.\n         */\n        GtkWidget *main; \t\t/* Enclosing window for whole cview */\n        GtkWidget *lab;               \t/* Columnview name label */\n        GtkWidget *vbox;               \t/* Outermost vbox for cview */\n        GtkWidget *frame;              \t/* Enclosing frame for tally stuff */\n        GtkWidget *title;              \t/* Eventbox wrapper for title bar */\n        GtkWidget *titlehb;            \t/* Title bar hbox */\n        GtkWidget *updown;             \t/* Fold up/down arrow */\n        GtkWidget *updownb;            \t/* Fold up/down button */\n        GtkWidget *head;               \t/* Label on columnview */\n        GtkWidget *headfr;             \t/* Frame wrapper around label */\n        GtkWidget *text;               \t/* Text entry at bottom */\n        GtkWidget *textfr;             \t/* Enclosing stuff for text entry */\n        GtkWidget *capedit;            \t/* Shadow text for editing caption */\n\n\t/* A shadow for this cview, used during drag to show where this column\n\t * will end up.\n\t *\n\t * And if we are a shadow, the master cview we are the shadow for.\n\t */\n\tColumnview *shadow;\n\tColumnview *master;\n\n        /* Appearance state info.\n         */\n        int lx, ly;\t\t\t/* last pos we set */\n        ColumnviewState state;         \t/* Waiting or dragging */\n        int sx, sy;                     /* Drag start point */\n        int rx, ry;                     /* Drag offset */\n        int tx, ty;                     /* Tally window pos in root cods */\n\tgboolean selected;\t\t/* Last drawn in selected state? */\n\n\t/* We watch resize events and trigger a workspace relayout with these.\n\t */\n\tint old_width;\n\tint old_height;\n};\n\ntypedef struct _ColumnviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} ColumnviewClass;\n\nvoid columnview_get_position( Columnview *cview, \n\tint *x, int *y, int *w, int *h );\n\nGtkType columnview_get_type( void );\nView *columnview_new( void );\n"
  },
  {
    "path": "src/compile.c",
    "content": "/* Stuff to parse and compile text.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG_RESOLVE\n */\n\n/* regular (and very slow) sanity checks on symbols ... needs DEBUG in\n * symbol.c as well\n#define DEBUG_SANITY\n */\n\n/* count how many nodes we find with common sub-expression removal.\n#define DEBUG_COMMON\n */\n\n/* show what everything compiled to\n#define DEBUG_RESULT\n */\n\n/* trace list comp compile\n#define DEBUG_LCOMP\n */\n\n/* trace pattern LHS generation\n#define DEBUG_PATTERN\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic iContainerClass *parent_class = NULL;\n\nCompile *\ncompile_get_parent( Compile *compile )\n{\n\tif( !ICONTAINER( compile->sym )->parent )\n\t\treturn( NULL );\n\n\treturn( COMPILE( ICONTAINER( compile->sym )->parent ) );\n}\n\nvoid *\ncompile_name_print( Compile *compile )\n{\n\tprintf( \"compile(%p) \", compile );\n\tsymbol_name_print( compile->sym );\n\n\treturn( NULL );\n}\n\nstatic void *\ncompile_name_sub( Expr *expr, VipsBuf *buf )\n{\n\tif( expr->row ) {\n\t\tif( !vips_buf_is_empty( buf ) )\n\t\t\tvips_buf_appends( buf, \", \" );\n\t\trow_qualified_name( expr->row, buf );\n\t}\n\n\treturn( NULL );\n}\n\nvoid\ncompile_name( Compile *compile, VipsBuf *buf )\n{\n\tchar txt[256];\n\tVipsBuf buf2 = VIPS_BUF_STATIC( txt );\n\n\tvips_buf_appends( buf, \"\\\"\" );\n\tsymbol_qualified_name( compile->sym, buf );\n\tvips_buf_appends( buf, \"\\\"\" );\n\n\tslist_map( compile->exprs,\n\t\t(SListMapFn) compile_name_sub, &buf2 );\n\tif( !vips_buf_is_empty( &buf2 ) ) \n\t\tvips_buf_appendf( buf, \" (%s)\", vips_buf_all( &buf2 ) );\n}\n\nstatic Compile *\ncompile_map_all_sub( Symbol *sym, map_compile_fn fn, void *a )\n{\n\tif( !sym->expr || !sym->expr->compile )\n\t\treturn( NULL );\n\telse \n\t\treturn( compile_map_all( sym->expr->compile, fn, a ) );\n}\n\n/* Apply a function to a compile ... and any local compiles. Do top-down.\n */\nCompile *\ncompile_map_all( Compile *compile, map_compile_fn fn, void *a )\n{\n\tCompile *res;\n\n\t/* Us first.\n\t */\n\tif( (res = fn( compile, a )) )\n\t\treturn( res );\n\n\t/* Then any children.\n\t */\n\tif( (res = (Compile *) icontainer_map( ICONTAINER( compile ),\n\t\t(icontainer_map_fn) compile_map_all_sub, (void *) fn, a )) )\n\t\treturn( res );\n\n\treturn( NULL );\n}\n\n/* Look up by name.\n */\nSymbol *\ncompile_lookup( Compile *compile, const char *name )\n{\n\treturn( SYMBOL( \n\t\ticontainer_child_lookup( ICONTAINER( compile ), name ) ) );\n}\n\n/* Make a dependency. Text in compile refers to sym.\n */\nvoid\ncompile_link_make( Compile *compile, Symbol *child )\n{\n\t/* Already a dependency? Don't make a second link.\n\t */\n\tif( !g_slist_find( compile->children, child ) ) {\n\t\t/* New link, each direction.\n\t\t */\n\t\tcompile->children = g_slist_prepend( compile->children, child );\n\t\tchild->parents = g_slist_prepend( child->parents, compile );\n\n\t\t/* If the child is a forward reference, we may have to patch \n\t\t * this later. Save the pointer-to-child pointer on child.\n\t\t */\n\t\tif( child->type == SYM_ZOMBIE )\n\t\t\t(void) symbol_patch_add( \n\t\t\t\t&compile->children->data, child );\n\t}\n\n#ifdef DEBUG_SANITY\n\t/* Sanity check.\n\t */\n\tsymbol_sanity( child );\n\tsymbol_leaf_set_sanity();\n#endif /*DEBUG_SANITY*/\n}\n\n/* Break a dependency. Text in compile referred to child.\n */\nvoid *\ncompile_link_break( Compile *compile, Symbol *child )\n{\n\t/* Sanity check.\n\t */\n#ifdef DEBUG_SANITY\n\tsymbol_sanity( child );\n\tsymbol_leaf_set_sanity();\n#endif /*DEBUG_SANITY*/\n\n\t/* Must be there.\n\t */\n\tg_assert( g_slist_find( compile->children, child ) &&\n\t\tg_slist_find( child->parents, compile ) );\n\n\tcompile->children = g_slist_remove( compile->children, child );\n\tchild->parents = g_slist_remove( child->parents, compile );\n\n\t/* Sanity check.\n\t */\n#ifdef DEBUG_SANITY\n\tsymbol_sanity( child );\n\tsymbol_leaf_set_sanity();\n#endif /*DEBUG_SANITY*/\n\n\treturn( NULL );\n}\n\nvoid *\ncompile_expr_link_break( Compile *compile, Expr *expr )\n{\n\tg_assert( expr->compile == compile );\n\tg_assert( g_slist_find( compile->exprs, expr ) );\n\n\texpr->compile = NULL;\n\tcompile->exprs = g_slist_remove( compile->exprs, expr );\n\n\tg_object_unref( G_OBJECT( compile ) );\n\n\treturn( NULL );\n}\n\nvoid *\ncompile_expr_link_break_rev( Expr *expr, Compile *compile )\n{\n\treturn( compile_expr_link_break( compile, expr ) );\n}\n\nvoid \ncompile_expr_link_make( Compile *compile, Expr *expr )\n{\n\tg_assert( !expr->compile );\n\tg_assert( !g_slist_find( compile->exprs, expr ) );\n\tg_assert( compile->sym == expr->sym );\n\n\texpr->compile = compile;\n\tcompile->exprs = g_slist_prepend( compile->exprs, expr );\n\n        g_object_ref( G_OBJECT( compile ) );\n\tiobject_sink( IOBJECT( compile ) );\n}\n\nstatic void\ncompile_finalize( GObject *gobject )\n{\n\tCompile *compile;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_COMPILE( gobject ) );\n\n\tcompile = COMPILE( gobject );\n\n#ifdef DEBUG\n\tprintf( \"compile_finalize: \" );\n\tcompile_name_print( compile );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\n\t/* Junk parse tree.\n\t */\n\tslist_map( compile->treefrag, (SListMapFn) tree_node_destroy, NULL );\n\tIM_FREEF( g_slist_free, compile->treefrag );\n\tcompile->tree = NULL;\n\n\t/* Break links to all locals.\n\t */\n\tIM_FREEF( g_slist_free, compile->param );\n\tcompile->nparam = 0;\n\tIM_FREEF( g_slist_free, compile->secret );\n\tcompile->nsecret = 0;\n\tcompile->this = NULL;\n\tcompile->super = NULL;\n\t(void) slist_map( compile->children, \n\t\t(SListMapFn) symbol_link_break, compile );\n\tIM_FREEF( g_slist_free, compile->children );\n\n\t/* Remove static strings we created.\n\t */\n\tslist_map( compile->statics, \n\t\t(SListMapFn) managed_destroy_nonheap, NULL );\n\tIM_FREEF( g_slist_free, compile->statics );\n\n\t/* Junk heap.\n\t */\n\tif( compile->heap ) {\n\t\tcompile->base.type = ELEMENT_NOVAL;\n\t\tcompile->base.ele = (void *) 1;\n\t\theap_unregister_element( compile->heap, &compile->base ); \n\t\tUNREF( compile->heap );\n\t}\n\n\t/* Junk text.\n\t */\n\tIM_FREE( compile->text );\n\tIM_FREE( compile->prhstext );\n\tIM_FREE( compile->rhstext );\n\n\tcompile->sym = NULL;\n\n\t/* If we're being finalized, we must have a ref count of zero, so\n\t * there shouldn't be any exprs looking at us.\n\t */\n\tg_assert( !compile->exprs );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\ncompile_class_init( CompileClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = compile_finalize;\n\n\t/* Create signals.\n\t */\n\n\t/* Init default methods.\n\t */\n}\n\nstatic void\ncompile_init( Compile *compile )\n{\n\t/* Init our instance fields.\n\t */\n\tcompile->sym = NULL;\n\n\tcompile->exprs = NULL;\n\n\tcompile->is_klass = FALSE;\n\tcompile->has_super = FALSE;\n\n\tcompile->text = NULL;\n\tcompile->prhstext = NULL;\n\tcompile->rhstext = NULL;\n\n\tcompile->tree = NULL;\n\tcompile->treefrag = NULL;\n\tcompile->last_sym = NULL;\n\n\tcompile->nparam = 0;\n\tcompile->param = NULL;\n\tcompile->nsecret = 0;\n\tcompile->secret = NULL;\n\tcompile->this = NULL;\n\tcompile->super = NULL;\n\tcompile->children = NULL;\n\n\tcompile->base.type = ELEMENT_NOVAL;\n\tcompile->heap = NULL;\n\tcompile->statics = NULL;\n}\n\nGType\ncompile_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( CompileClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) compile_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Compile ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) compile_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_ICONTAINER, \n\t\t\t\"Compile\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\n/* Make a compile linked to an expr.\n */\nCompile *\ncompile_new( Expr *expr )\n{\n\tCompile *compile = COMPILE( g_object_new( TYPE_COMPILE, NULL ) );\n\n\tcompile->sym = expr->sym;\n\n\t/* Junk any old compile.\n\t */\n\tif( expr->compile )\n\t\tcompile_expr_link_break( expr->compile, expr );\n\n\tcompile_expr_link_make( compile, expr );\n\n\t/* We'll want to be able to do name lookups.\n\t */\n\ticontainer_set_hash( ICONTAINER( compile ) );\n\n#ifdef DEBUG\n\tprintf( \"compile_new: \" );\n\tcompile_name_print( compile );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\treturn( compile );\n}\n\n/* Max cells function for symbols. Enough to compile something big.\n */\nstatic int\ncompile_heap_max_fn( Heap *heap )\n{\n\treturn( 10000 );\n}\n\n/* Make a exprinfo suitable for a top-level symbol.\n */\nCompile *\ncompile_new_toplevel( Expr *expr )\n{\n\tCompile *compile = compile_new( expr );\n\n\tcompile->heap = heap_new( compile, compile_heap_max_fn, 100, 1000 );\n\tg_object_ref( G_OBJECT( compile->heap ) );\n\tiobject_sink( IOBJECT( compile->heap ) );\n\n\theap_register_element( compile->heap, &compile->base ); \n\n\treturn( compile );\n}\n\n/* Make a exprinfo suitable for a local.\n */\nCompile *\ncompile_new_local( Expr *expr )\n{\n\tCompile *compile = compile_new( expr );\n\n\tcompile->heap = heap_new( compile, compile_heap_max_fn, 100, 100 );\n\tg_object_ref( G_OBJECT( compile->heap ) );\n\tiobject_sink( IOBJECT( compile->heap ) );\n\n\theap_register_element( compile->heap, &compile->base ); \n\n\treturn( compile );\n}\n\n/* Code generation.\n */\n\n/* Generate a binop. Point arg1 and arg2 at the elements to be filled in:\n * caller sets them later. First arg is the compile that this operator came \n * from. \n */\nstatic gboolean\ncompile_binop( Compile *compile, \n\tBinOp bop, PElement *arg1, PElement *arg2, PElement *out )\n{\n\tHeap *heap = compile->heap;\n\n\tHeapNode *hn1, *hn2, *hn3;\n\tPElement e1, e2;\n\n\tif( NEWNODE( heap, hn1 ) )\n\t\treturn( FALSE );\n\thn1->type = TAG_APPL;\n\tPPUT( hn1, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL );\n\tPEPUTP( out, ELEMENT_NODE, hn1 );\n\tPEPOINTLEFT( hn1, &e1 );\n\tPEPOINTRIGHT( hn1, arg2 );\n\n\tif( NEWNODE( heap, hn2 ) )\n\t\treturn( FALSE );\n\thn2->type = TAG_APPL;\n\tPPUT( hn2, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL );\n\tPEPUTP( &e1, ELEMENT_NODE, hn2 );\n\tPEPOINTRIGHT( hn2, arg1 );\n\tPEPOINTLEFT( hn2, &e2 );\n\n\tif( NEWNODE( heap, hn3 ) )\n\t\treturn( FALSE );\n\thn3->type = TAG_APPL;\n\tPPUT( hn3, ELEMENT_BINOP, bop, ELEMENT_COMPILEREF, compile );\n\tPEPUTP( &e2, ELEMENT_NODE, hn3 );\n\n\treturn( TRUE );\n}\n\n/* Generate \"x.sym\". Set x to be NULL and point rhs at it .. caller\n * fills in later.\n */\nstatic gboolean\ncompile_dotsym( Compile *compile, Symbol *sym, PElement *rhs, PElement *out )\n{\n\tPElement e;\n\n\tif( !compile_binop( compile, BI_DOT, rhs, &e, out ) )\n\t\treturn( FALSE );\n\tPEPUTP( &e, ELEMENT_SYMREF, sym );\n\n\treturn( TRUE );\n}\n\n/* Compile a reference to sym from expr.\n */\nstatic gboolean\ncompile_reference( Compile *compile, Symbol *sym, PElement *out )\n{\n\tHeap *heap = compile->heap;\n\tCompile *parent = compile_get_parent( compile );\n\n#ifdef DEBUG\n\tprintf( \"generate_reference: ref to \" );\n\tsymbol_name_print( sym );\n\tprintf( \"inside \" );\n\tcompile_name_print( compile );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( g_slist_find( compile->param, sym ) || \n\t\tg_slist_find( compile->secret, sym ) ) {\n\t\t/* sym is a simple parameter, easy!\n\t\t */\n\t\tPEPUTP( out, ELEMENT_SYMBOL, sym );\n\t}\n\telse if( is_class( parent ) && \n\t\t(symbol_get_parent( sym ) == parent->sym ||\n\t\tg_slist_find( parent->secret, sym )) ) {\n\t\tSymbol *ths = parent->this;\n\n\t\t/* sym is a member of the same class as expr, or sym is a\n\t\t * secret to our constructor (in which case it'll be in this\n\t\t * as well) ... generate (.sym this)\n\t\t *\n\t\t * Optimisation: don't generate (.this this)\n\t\t */\n\t\tif( sym == ths ) {\n\t\t\tPEPUTP( out, ELEMENT_SYMBOL, ths );\n\t\t}\n\t\telse {\n\t\t\tPElement rhs;\n\n\t\t\tif( !compile_dotsym( compile, sym, &rhs, out ) )\n\t\t\t\treturn( FALSE );\n\t\t\tPEPUTP( &rhs, ELEMENT_SYMBOL, ths );\n\t\t}\n\t}\n\telse if( is_member_enclosing( compile, sym ) ) {\n\t\tSymbol *sths = symbol_get_parent( sym )->expr->compile->this;\n\t\tPElement rhs;\n\n\t\t/* Sym is a member of an enclosing class ...\n\t\t * generate (.sym ref-to-this-for-that-class)\n\t\t */\n\t\tif( !compile_dotsym( compile, sym, &rhs, out ) ||\n\t\t\t!compile_reference( compile, sths, &rhs ) )\n\t\t\treturn( FALSE );\n\t}\n\telse {\n\t\t/* some other reference ... generate (sym secret1 .. secretn)\n\t\t * recurse for secrets, since we may have to fetch them from \n\t\t * \"this\"\n\t\t */\n\t\tPElement e = *out;\n\t\tPElement f;\n\t\tGSList *l;\n\n\t\tPEPUTP( &e, ELEMENT_SYMBOL, sym );\n\n\t\t/* Build secret args to this sym.\n\t\t */\n\t\tif( sym->expr && sym->expr->compile )\n\t\t\tfor( l = sym->expr->compile->secret; l; l = l->next ) {\n\t\t\t\tSymbol *arg = SYMBOL( l->data );\n\t\t\t\tHeapNode *hn1;\n\n\t\t\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\t\t\treturn( FALSE );\n\t\t\t\thn1->type = TAG_APPL;\n\t\t\t\tPEPUTLEFT( hn1, &e );\n\t\t\t\tPPUTRIGHT( hn1, ELEMENT_ELIST, NULL ); \n\t\t\t\tPEPUTP( &e, ELEMENT_NODE, hn1 );\n\n\t\t\t\tPEPOINTRIGHT( hn1, &f );\n\t\t\t\tif( !compile_reference( compile, arg, &f ) )\n\t\t\t\t\treturn( FALSE );\n\t\t\t}\n\t}\n\n\treturn( TRUE );\n}\n\n/* Build a graph with vars still in it. Write result to *out.\n */\nstatic gboolean\ncompile_graph( Compile *compile, ParseNode *pn, PElement *out )\n{\n\tHeap *heap = compile->heap;\n\tHeapNode *hn1, *hn2, *hn3;\n\tPElement e1, e2, e3;\n\tGSList *l;\n\n\tswitch( pn->type ) {\n\tcase NODE_APPLY:\n\t\t/* Build apply node.\n\t\t */\n\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\treturn( FALSE );\n\t\thn1->type = TAG_APPL;\n\t\tPPUT( hn1, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL );\n\t\tPEPUTP( out, ELEMENT_NODE, hn1 );\n\n\t\t/* Make sides.\n\t\t */\n\t\tPEPOINTLEFT( hn1, &e1 );\n\t\tPEPOINTRIGHT( hn1, &e2 );\n\t\tif( !compile_graph( compile, pn->arg1, &e1 ) ||\n\t\t\t!compile_graph( compile, pn->arg2, &e2 ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\n\tcase NODE_UOP:\n\t\t/* Build apply node.\n\t\t */\n\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\treturn( FALSE );\n\t\thn1->type = TAG_APPL;\n\t\tPPUT( hn1, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL );\n\t\tPEPUTP( out, ELEMENT_NODE, hn1 );\n\t\tPEPOINTLEFT( hn1, &e1 );\n\n\t\tif( NEWNODE( heap, hn2 ) )\n\t\t\treturn( FALSE );\n\t\thn2->type = TAG_APPL;\n\t\tPPUT( hn2, ELEMENT_UNOP, pn->uop, ELEMENT_COMPILEREF, compile );\n\t\tPEPUTP( &e1, ELEMENT_NODE, hn2 );\n\n\t\t/* Build arg.\n\t\t */\n\t\tPEPOINTRIGHT( hn1, &e2 );\n\t\tif( !compile_graph( compile, pn->arg1, &e2 ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\n\tcase NODE_BINOP:\n\t\tif( !compile_binop( compile, pn->biop, &e1, &e2, out ) ||\n\t\t\t!compile_graph( compile, pn->arg1, &e1 ) ||\n\t\t\t!compile_graph( compile, pn->arg2, &e2 ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\n\tcase NODE_COMPOSE:\n\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\treturn( FALSE );\n\t\thn1->type = TAG_APPL;\n\t\tPPUT( hn1, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL );\n\t\tPEPUTP( out, ELEMENT_NODE, hn1 );\n\t\tPEPOINTLEFT( hn1, &e1 );\n\n\t\tif( NEWNODE( heap, hn2 ) )\n\t\t\treturn( FALSE );\n\t\thn2->type = TAG_APPL;\n\t\tPPUT( hn2, ELEMENT_COMB, COMB_SR, \n\t\t\tELEMENT_ELIST, NULL );\n\t\tPEPUTP( &e1, ELEMENT_NODE, hn2 );\n\n\t\t/* Build args.\n\t\t */\n\t\tPEPOINTRIGHT( hn1, &e2 );\n\t\tPEPOINTRIGHT( hn2, &e3 );\n\t\tif( !compile_graph( compile, pn->arg1, &e3 ) ||\n\t\t\t!compile_graph( compile, pn->arg2, &e2 ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\n\tcase NODE_LEAF:\n\t\t/* A reference to a symbol. \n\t\t */\n\t\tif( !compile_reference( compile, pn->leaf, out ) )\n\t\t\treturn( FALSE );\n\n\t\tbreak;\n\n\tcase NODE_CLASS:\n\t\t/* Output constructor.\n\t\t */\n\t\tPEPUTP( out, ELEMENT_CONSTRUCTOR, pn->klass );\n\t\tbreak;\n\n\tcase NODE_TAG:\n\t\t/* RHS of projection. \n\t\t */\n\t\tPEPUTP( out, ELEMENT_TAG, pn->tag );\n\t\tbreak;\n\n\tcase NODE_GENERATOR:\n\t\t/* Build apply nodes.\n\t\t */\n\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\treturn( FALSE );\n\t\thn1->type = TAG_APPL;\n\t\tPPUT( hn1, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL );\n\t\tPEPUTP( out, ELEMENT_NODE, hn1 );\n\t\tPEPOINTLEFT( hn1, &e1 );\n\n\t\tif( NEWNODE( heap, hn2 ) )\n\t\t\treturn( FALSE );\n\t\thn2->type = TAG_APPL;\n\t\tPPUT( hn2, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL );\n\t\tPEPUTP( &e1, ELEMENT_NODE, hn2 );\n\t\tPEPOINTLEFT( hn2, &e2 );\n\n\t\tif( NEWNODE( heap, hn3 ) )\n\t\t\treturn( FALSE );\n\t\thn3->type = TAG_APPL;\n\t\tPPUT( hn3, ELEMENT_COMB, COMB_GEN, ELEMENT_ELIST, NULL );\n\t\tPEPUTP( &e2, ELEMENT_NODE, hn3 );\n\n\t\t/* Build args.\n\t\t */\n\t\tPEPOINTRIGHT( hn1, &e3 );\n\t\tPEPOINTRIGHT( hn2, &e2 );\n\t\tPEPOINTRIGHT( hn3, &e1 );\n\t\tif( !compile_graph( compile, pn->arg1, &e1 ) )\n\t\t\treturn( FALSE );\n\t\tif( pn->arg2 )\n\t\t\tif( !compile_graph( compile, pn->arg2, &e2 ) )\n\t\t\t\treturn( FALSE );\n\t\tif( pn->arg3 )\n\t\t\tif( !compile_graph( compile, pn->arg3, &e3 ) )\n\t\t\t\treturn( FALSE );\n\n\t\tbreak;\n\n\tcase NODE_LISTCONST:\n\tcase NODE_SUPER:\n\t\t/* List of expressions.\n\t\t */\n\n\t\t/* Make first RHS ... the end of the list. \n\t\t */\n\t\te1 = *out;\n\t\tPEPUTP( &e1, ELEMENT_ELIST, NULL );\n\n\t\t/* Build @':' for each element.\n\t\t */\n\t\tfor( l = pn->elist; l; l = l->next ) {\n\t\t\tParseNode *arg = (ParseNode *) l->data;\n\n\t\t\t/* Build apply nodes.\n\t\t\t */\n\t\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\t\treturn( FALSE );\n\t\t\thn1->type = TAG_APPL;\n\t\t\tPPUT( hn1, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL );\n\t\t\tPEPUTP( &e1, ELEMENT_NODE, hn1 );\n\t\t\tPEPOINTLEFT( hn1, &e2 );\n\n\t\t\tif( NEWNODE( heap, hn2 ) )\n\t\t\t\treturn( FALSE );\n\t\t\thn2->type = TAG_APPL;\n\t\t\tPPUT( hn2, ELEMENT_ELIST, NULL, ELEMENT_ELIST, NULL );\n\t\t\tPEPUTP( &e2, ELEMENT_NODE, hn2 );\n\t\t\tPEPOINTLEFT( hn2, &e2 );\n\n\t\t\tif( NEWNODE( heap, hn3 ) )\n\t\t\t\treturn( FALSE );\n\t\t\thn3->type = TAG_APPL;\n\t\t\tPPUT( hn3, ELEMENT_BINOP, BI_CONS, \n\t\t\t\tELEMENT_COMPILEREF, compile );\n\t\t\tPEPUTP( &e2, ELEMENT_NODE, hn3 );\n\n\t\t\t/* Build arg.\n\t\t\t */\n\t\t\tPEPOINTRIGHT( hn2, &e3 );\n\t\t\tif( !compile_graph( compile, arg, &e3 ) )\n\t\t\t\treturn( FALSE );\n\n\t\t\t/* APPL is now our LHS.\n\t\t\t */\n\t\t\tPEPOINTRIGHT( hn1, &e1 );\n\t\t}\n\n\t\tbreak;\n\n\tcase NODE_CONST:\n\t\t/* Constant.\n\t\t */\n\t\tswitch( pn->con.type ) {\n\t\tcase PARSE_CONST_STR:\n\t\t{\n\t\t\tManagedstring *managedstring;\n\t\t\t\t\n\t\t\tif( !(managedstring = managedstring_find( \n\t\t\t\treduce_context->heap, \n\t\t\t\tpn->con.val.str )) )\n\t\t\t\treturn( FALSE );\n\t\t\tMANAGED_REF( managedstring );\n\t\t\tcompile->statics = g_slist_prepend( compile->statics,\n\t\t\t\tmanagedstring );\n\t\t\tPEPUTP( out, ELEMENT_MANAGED, managedstring );\n\t\t}\n\t\t\tbreak;\n\n\t\tcase PARSE_CONST_CHAR:\n\t\t\tPEPUTP( out, ELEMENT_CHAR, pn->con.val.ch );\n\t\t\tbreak;\n\n\t\tcase PARSE_CONST_BOOL:\n\t\t\tPEPUTP( out, ELEMENT_BOOL, pn->con.val.bol );\n\t\t\tbreak;\n\n\t\tcase PARSE_CONST_ELIST:\n\t\t\tPEPUTP( out, ELEMENT_ELIST, NULL );\n\t\t\tbreak;\n\n\t\tcase PARSE_CONST_NUM:\n\t\t\tif( !heap_real_new( heap, pn->con.val.num, out ) )\n\t\t\t\treturn( FALSE );\n\t\t\tbreak;\n\n\t\tcase PARSE_CONST_COMPLEX:\n\t\t\tif( !heap_complex_new( heap, 0, pn->con.val.num, out ) )\n\t\t\t\treturn( FALSE );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tg_assert( FALSE );\n\t\t}\n\n\t\tbreak;\n\n\tcase NODE_NONE:\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Parameter abstraction.\n */\n\n/* Abstract a symbol from the body of a piece of graph. Set *used if we found \n * the symbol in this piece of graph ... ie. if our caller should add an\n * Sx-combinator for us.  Update *root with the new piece of graph.\n */\nstatic int\ncompile_abstract_body( Compile *compile, \n\tPElement *root, Symbol *sym, gboolean *used )\n{\n\tHeap *heap = compile->heap;\n\tHeapNode *hn;\n\tHeapNode *hn1;\n\tPElement e1, e2;\n\tgboolean b1, b2;\n\tCombinatorType comb;\n\n\tswitch( PEGETTYPE( root ) ) {\n\tcase ELEMENT_NODE:\n\t\thn = PEGETVAL( root );\n\t\tswitch( hn->type ) {\n\t\tcase TAG_APPL:\t\t\n\t\tcase TAG_CONS:\n\t\t\tb1 = FALSE; b2 = FALSE;\n\t\t\tPEPOINTLEFT( hn, &e1 );\n\t\t\tPEPOINTRIGHT( hn, &e2 );\n\t\t\tif( compile_abstract_body( compile, &e1, sym, &b1 ) ||\n\t\t\t\tcompile_abstract_body( compile, \n\t\t\t\t\t&e2, sym, &b2 ) )\n\t\t\t\treturn( -1 );\n\n\t\t\tif( PEISCOMB( &e2 ) && \n\t\t\t\tPEGETCOMB( &e2 ) == COMB_I && !b1 && b2 &&\n\t\t\t\thn->type == TAG_APPL ) {\n\t\t\t\tPEPUTPE( root, &e1 );\n\t\t\t\t*used = TRUE;\n\t\t\t}\n\t\t\telse if( b1 || b2 ) {\n\t\t\t\tif( b1 && !b2 ) \n\t\t\t\t\tcomb = COMB_SL;\n\t\t\t\telse if( !b1 && b2 ) \n\t\t\t\t\tcomb = COMB_SR;\n\t\t\t\telse \n\t\t\t\t\tcomb = COMB_S;\n\n\t\t\t\t/* Generate Sx combinator.\n\t\t\t\t */\n\t\t\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\t\t\treturn( -1 );\n\t\t\t\thn1->type = TAG_APPL;\n\t\t\t\tPPUTLEFT( hn1, ELEMENT_COMB, comb );\n\t\t\t\tPEPUTRIGHT( hn1, &e1 );\n\t\t\t\tPEPUTP( &e1, ELEMENT_NODE, hn1 );\n\n\t\t\t\t/* We've used the var too!\n\t\t\t\t */\n\t\t\t\t*used = TRUE;\n\t\t\t}\n\n\t\t\tbreak;\n\n\t\tcase TAG_DOUBLE:\n\t\tcase TAG_COMPLEX:\n\t\tcase TAG_CLASS:\n\t\tcase TAG_GEN:\n\t\t\tbreak;\n\n\t\tcase TAG_FILE:\n\t\tcase TAG_FREE:\t\n\t\tdefault:\n\t\t\tg_assert( FALSE );\n\t\t}\n\n\t\tbreak;\n\n\tcase ELEMENT_SYMBOL:\n\t\tif( SYMBOL( PEGETVAL( root ) ) == sym ) {\n\t\t\t/* Found an instance! Make an I combinator.\n\t\t\t */\n\t\t\t*used = TRUE;\n\t\t\tPEPUTP( root, ELEMENT_COMB, COMB_I );\n\t\t}\n\t\tbreak;\n\n\tcase ELEMENT_CONSTRUCTOR:\n\t\t/* set used .. to stop K being generated for this\n\t\t * class parameter.\n\t\t */\n\t\t*used = TRUE;\n\t\tbreak;\n\n\tcase ELEMENT_MANAGED:\n\tcase ELEMENT_CHAR:\n\tcase ELEMENT_BOOL:\n\tcase ELEMENT_BINOP:\n\tcase ELEMENT_UNOP:\n\tcase ELEMENT_COMB:\n\tcase ELEMENT_ELIST:\n\tcase ELEMENT_SYMREF:\n\tcase ELEMENT_COMPILEREF:\n\tcase ELEMENT_NOVAL:\n\tcase ELEMENT_TAG:\n\t\t/* Leave alone.\n\t\t */\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( 0 );\n}\n\n/* Abstract a symbol from a graph. As above, but make a K if the symbol is\n * entirely unused. \n */\nstatic void *\ncompile_abstract_symbol( Symbol *sym, Compile *compile, PElement *root )\n{\n\tHeap *heap = compile->heap;\n\tgboolean b;\n\n#ifdef DEBUG\n\tprintf( \"abstracting \" );\n\tsymbol_name_print( sym );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tb = FALSE;\n\tif( compile_abstract_body( compile, root, sym, &b ) )\n\t\treturn( sym );\n\n\tif( !b ) {\n\t\tHeapNode *hn1;\n\n\t\t/* Parameter not used! Need a K.\n\t\t */\n\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\treturn( sym );\n\t\thn1->type = TAG_APPL;\n\t\tPPUTLEFT( hn1, ELEMENT_COMB, COMB_K );\n\t\tPEPUTRIGHT( hn1, root );\n\n\t\t/* Update root.\n\t\t */\n\t\tPEPUTP( root, ELEMENT_NODE, hn1 );\n\t}\n\n\treturn( NULL );\n}\n\n/* Common sub-expression elimination.\n */\n\n#ifdef DEBUG_COMMON\nstatic void *\ncompile_node_count_sub( HeapNode *hn, int *n )\n{\n\t*n += 1;\n\n\treturn( NULL );\n}\n\nstatic int\ncompile_node_count( HeapNode *hn )\n{\n\tint n;\n\n\tn = 0;\n\theap_map( hn, (heap_map_fn) compile_node_count_sub, &n, NULL );\n\n\treturn( n );\n}\n\n/* Accumulate total saved here during walk of this tree.\n */\nstatic int compile_node_sum;\n#endif /*DEBUG_COMMON*/\n\n/* A hash code we calculate from a bit of heap.\n */\ntypedef gpointer CompileHash;\n\n/* Combine two hashes.\n */\n#define COMPILEHASH_ADD( A, B ) \\\n\tGUINT_TO_POINTER( GPOINTER_TO_UINT( A ) +  GPOINTER_TO_UINT( B ) )\n\n/* An int to a hash.\n */\n#define INT_TO_HASH GUINT_TO_POINTER\n\n/* Build one of these during sharing analysis. From node pointers to\n * hash codes, and from hash codes to a list of matching node pointers.\n */\ntypedef struct _CompileShare {\n\tCompile *compile;\n\n\tGHashTable *node2hash;\n\tGHashTable *hash2nodel;\n} CompileShare;\n\nstatic gboolean\ncompile_share_destroy_sub( gpointer key, gpointer value, gpointer user_data )\n{\n\tif( value )\n\t\tg_slist_free( (GSList *) value );\n\n\treturn( TRUE );\n}\n\nstatic void\ncompile_share_destroy( CompileShare *share )\n{\n\tshare->compile = NULL;\n\tif( share->node2hash ) {\n\t\tg_hash_table_destroy( share->node2hash );\n\t\tshare->node2hash = NULL;\n\t}\n\tif( share->hash2nodel ) {\n\t\tg_hash_table_foreach_remove( share->hash2nodel,\n\t\t\tcompile_share_destroy_sub, NULL );\n\t\tg_hash_table_destroy( share->hash2nodel );\n\t\tshare->hash2nodel = NULL;\n\t}\n}\n\nstatic void\ncompile_share_init( CompileShare *share, Compile *compile )\n{\n\tshare->compile = compile;\n\tshare->node2hash = g_hash_table_new( NULL, g_direct_equal );\n\tshare->hash2nodel = g_hash_table_new( NULL, g_direct_equal );\n}\n\n/* Remove a heapnode from the share.\n */\nstatic void *\ncompile_share_remove( HeapNode *hn, CompileShare *share )\n{\n\tCompileHash hash;\n\n\tif( (hash = g_hash_table_lookup( share->node2hash, hn )) ) {\n\t\tGSList *nodel;\n\n\t\tif( (nodel = g_hash_table_lookup( share->hash2nodel, \n\t\t\thash )) ) {\n\t\t\tnodel = slist_remove_all( nodel, hn );\n\t\t\tg_hash_table_replace( share->hash2nodel, \n\t\t\t\thash, nodel );\n\t\t}\n\n\t\tg_hash_table_remove( share->node2hash, hn );\n\t}\n\n\treturn( NULL );\n}\n\n/* Add a new heapnode.\n */\nstatic void\ncompile_share_add( CompileShare *share, HeapNode *hn, CompileHash hash )\n{\n\t/* Make sure hash is non-zero (very unlikely).\n\t */\n\tif( !hash )\n\t\thash = INT_TO_HASH( 1 );\n\n\tif( !g_hash_table_lookup( share->node2hash, hn ) ) {\n\t\tGSList *nodel;\n\n\t\tg_hash_table_insert( share->node2hash, hn, hash ); \n\n\t\tif( (nodel = g_hash_table_lookup( share->hash2nodel, hash )) ) {\n\t\t\tnodel = g_slist_prepend( nodel, hn );\n\t\t\tg_hash_table_replace( share->hash2nodel, hash, nodel );\n\t\t}\n\t\telse {\n\t\t\tnodel = g_slist_prepend( NULL, hn );\n\t\t\tg_hash_table_insert( share->hash2nodel, hash, nodel );\n\t\t}\n\t}\n}\n\n/* From a HeapNode, find a list of the other heapnodes which hashed to the same\n * value.\n */\nstatic GSList *\ncompile_share_lookup( CompileShare *share, HeapNode *hn )\n{\n\tCompileHash hash;\n\n\tif( (hash = (CompileHash) \n\t\tg_hash_table_lookup( share->node2hash, hn )) ) \n\t\treturn( g_hash_table_lookup( share->hash2nodel, \n\t\t\t(gpointer) hash ) );\n\n\treturn( NULL );\n}\n\nstatic CompileHash compile_share_scan_node( CompileShare *share, \n\tHeapNode *hn );\n\nstatic CompileHash\ncompile_share_scan_element( CompileShare *share, PElement *e )\n{\n\tCompileHash hash;\n\n\tswitch( PEGETTYPE( e ) ) {\n\tcase ELEMENT_NODE:\n\t\thash = compile_share_scan_node( share, PEGETVAL( e ) );\n\t\tbreak;\n\n\tcase ELEMENT_SYMBOL:\n\tcase ELEMENT_SYMREF:\n\tcase ELEMENT_COMPILEREF:\n\tcase ELEMENT_CHAR:\n\tcase ELEMENT_BOOL:\n\tcase ELEMENT_BINOP:\n\tcase ELEMENT_UNOP:\n\tcase ELEMENT_COMB:\n\tcase ELEMENT_CONSTRUCTOR:\n\t\thash = INT_TO_HASH( PEGETTYPE( e ) + PEGETVAL( e ) );\n\t\tbreak;\n\n\tcase ELEMENT_ELIST:\n\t\thash = INT_TO_HASH( ELEMENT_ELIST );\n\t\tbreak;\n\n\tcase ELEMENT_TAG:\n\t\thash = INT_TO_HASH( g_str_hash( PEGETTAG( e ) ) );\n\t\tbreak;\n\n\tcase ELEMENT_MANAGED:\n\t\thash = INT_TO_HASH( PEGETMANAGED( e )->hash );\n\t\tbreak;\n\n\tcase ELEMENT_NOVAL:\n\tdefault:\n\t\thash = 0; \n\t\tg_assert( 0 );\n\t}\n\n\treturn( hash );\n}\n\n/* Calculate a hash for every node in a tree. We can just recurse and\n * calculate bottom-up, since we'll never get very deep. If we were scanning\n * run-time code, we'd need a better scheme.\n */\nstatic CompileHash\ncompile_share_scan_node( CompileShare *share, HeapNode *hn )\n{\n\tCompileHash hash;\n\tPElement a;\n\n\thash = INT_TO_HASH( 0 );\n\tswitch( hn->type ) {\n\tcase TAG_CONS:\n\tcase TAG_GEN:\n\tcase TAG_CLASS:\n\tcase TAG_COMPLEX:\n\tcase TAG_APPL:\n\t\tPEPOINTLEFT( hn, &a );\n\t\thash = COMPILEHASH_ADD( hash, \n\t\t\tcompile_share_scan_element( share, &a ) );\n\t\tPEPOINTRIGHT( hn, &a );\n\t\thash = COMPILEHASH_ADD( hash, \n\t\t\tcompile_share_scan_element( share, &a ) );\n\t\thash = COMPILEHASH_ADD( hash, \n\t\t\tINT_TO_HASH( (int) hn->type ) );\n\t\tbreak;\n\n\tcase TAG_DOUBLE:\n\t\thash = COMPILEHASH_ADD( hash, \n\t\t\tINT_TO_HASH( (int) hn->body.num ) );\n\t\thash = COMPILEHASH_ADD( hash, \n\t\t\tINT_TO_HASH( (int) hn->type ) );\n\t\tbreak;\n\n\tcase TAG_FILE:\n\tcase TAG_REFERENCE:\n\tcase TAG_SHARED:\n\tcase TAG_FREE:\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\t/* Add to accumulated table.\n\t */\n\tcompile_share_add( share, hn, hash );\n\n\treturn( hash );\n}\n\n/* Test two sub-trees for equality.\n */\nstatic gboolean\ncompile_equal_node( HeapNode *hn1, HeapNode *hn2 )\n{\n\t/* Test for pointer equality.\n\t */\n\tif( hn1 == hn2 )\n\t\treturn( TRUE );\n\n\t/* Test type tags for equality.\n\t */\n\tif( hn1->type != hn2->type )\n\t\treturn( FALSE );\n\n\t/* If double, test immediately.\n\t */\n\tif( hn1->type == TAG_DOUBLE ) {\n\t\tif( hn1->body.num == hn2->body.num )\n\t\t\treturn( TRUE );\n\t\telse\n\t\t\treturn( FALSE );\n\t}\n\n\t/* If complex, test immediately.\n\t */\n\tif( hn1->type == TAG_COMPLEX ) {\n\t\tif( GETLEFT( hn1 )->body.num == GETLEFT( hn2 )->body.num &&\n\t\t\tGETRIGHT( hn1 )->body.num == GETRIGHT( hn2 )->body.num )\n\t\t\treturn( TRUE );\n\t\telse\n\t\t\treturn( FALSE );\n\t}\n\n\t/* If compound type, something is wrong! Only built by reduce.\n\t */\n\tg_assert( hn1->type != TAG_CLASS );\n\n\t/* In two parts, test tags.\n\t */\n\tif( GETLT( hn1 ) != GETLT( hn2 ) )\n\t\treturn( FALSE );\n\tif( GETRT( hn1 ) != GETRT( hn2 ) )\n\t\treturn( FALSE );\n\n\t/* Test non-subtree parts.\n\t */\n\tif( GETLT( hn1 ) != ELEMENT_NODE ) \n\t\tif( GETLEFT( hn1 ) != GETLEFT( hn2 ) )\n\t\t\treturn( FALSE );\n\tif( GETRT( hn1 ) != ELEMENT_NODE ) \n\t\tif( GETRIGHT( hn1 ) != GETRIGHT( hn2 ) )\n\t\t\treturn( FALSE );\n\n\t/* If sub-trees, test them.\n\t */\n\tif( GETLT( hn1 ) == ELEMENT_NODE ) \n\t\tif( !compile_equal_node( GETLEFT( hn1 ), GETLEFT( hn2 ) ) )\n\t\t\treturn( FALSE );\n\tif( GETRT( hn1 ) == ELEMENT_NODE ) \n\t\tif( !compile_equal_node( GETRIGHT( hn1 ), GETRIGHT( hn2 ) ) )\n\t\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Found two equal sub-expressions. We can change hn1 to just be a reference\n * to hn2.\n */\nstatic int\ncompile_transform_reference( Compile *compile, HeapNode *hn1, HeapNode *hn2 )\n{\n#ifdef DEBUG\n{\n\tHeap *heap = compile->heap;\n\tchar txt[100];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_node( heap, &buf, hn1, TRUE );\n\tprintf( \"Found common subexpression: %s\\n\", vips_buf_all( &buf ) );\n}\n#endif /*DEBUG*/\n\n#ifdef DEBUG_COMMON\n\tcompile_node_sum += compile_node_count( hn1 );\n#endif /*DEBUG_COMMON*/\n\n\t/* Zap nodes to indicate sharing. \n\t */\n\thn1->type = TAG_REFERENCE;\n\tPPUTLEFT( hn1, ELEMENT_NODE, hn2 );\n\tPPUTRIGHT( hn1, ELEMENT_NODE, NULL );\n\n\treturn( 0 );\n}\n\n/* Node other hashes to the same value as our node. Test for equality, and if\n * they match, turn us into a share point and turn the other node into a ref.\n */\nstatic void *\ncompile_share_test( HeapNode *other, CompileShare *share, HeapNode *hn )\n{\n\tif( hn != other && compile_equal_node( hn, other ) ) {\n\t\theap_map( other,\n\t\t\t(heap_map_fn) compile_share_remove, share, NULL );\n\t\tcompile_transform_reference( share->compile, other, hn );\n\t}\n\n\treturn( NULL );\n}\n\n/* Scan a chunk of tree top-down, looking for and eliminating common nodes.\n */\nstatic void\ncompile_share_trim( CompileShare *share, HeapNode *hn )\n{\n\tPElement a;\n\tGSList *nodel;\n\n\tif( (nodel = compile_share_lookup( share, hn )) ) \n\t\tslist_map2( nodel,\n\t\t\t(SListMap2Fn) compile_share_test, share, hn );\n\n\tswitch( hn->type ) {\n\tcase TAG_CONS:\n\tcase TAG_GEN:\n\tcase TAG_CLASS:\n\tcase TAG_COMPLEX:\n\tcase TAG_APPL:\n\t\tPEPOINTLEFT( hn, &a );\n\t\tif( PEISNODE( &a ) )\n\t\t\tcompile_share_trim( share, PEGETVAL( &a ) );\n\t\tPEPOINTRIGHT( hn, &a );\n\t\tif( PEISNODE( &a ) )\n\t\t\tcompile_share_trim( share, PEGETVAL( &a ) );\n\t\tbreak;\n\n\tcase TAG_DOUBLE:\n\tcase TAG_REFERENCE:\n\t\tbreak;\n\n\tcase TAG_SHARED:\n\tcase TAG_FREE:\n\tcase TAG_FILE:\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n}\n\nstatic void\ncompile_share_scan( Compile *compile, PElement *a )\n{\n\tif( PEISNODE( a ) ) {\n\t\tHeapNode *hn = PEGETVAL( a );\n\t\tCompileShare share;\n\n\t\tcompile_share_init( &share, compile );\n\t\tcompile_share_scan_node( &share, hn );\n\t\tcompile_share_trim( &share, hn );\n\t\tcompile_share_destroy( &share );\n\t}\n}\n\n/* Use this to generate an id for each SHARE node.\n */\nstatic int compile_share_number = 0;\n\n/* If this is a REF node, make sure dest is a SHARE node.\n */\nstatic void *\ncompile_transform_share( HeapNode *hn, Compile *compile )\n{\n\tHeap *heap = compile->heap;\n\n\tif( hn->type == TAG_REFERENCE ) {\n\t\tHeapNode *hn1 = GETLEFT( hn );\n\n\t\tif( hn1->type != TAG_SHARED ) {\n\t\t\tHeapNode *hn2;\n\n#ifdef DEBUG\n{\n\t\t\tchar txt[100];\n\t\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\t\tgraph_node( heap, &buf, hn1, TRUE );\n\t\t\tprintf( \"Found shared code: %s\\n\", \n\t\t\t\tvips_buf_all( &buf ) );\n}\n#endif /*DEBUG*/\n\n\t\t\tif( NEWNODE( heap, hn2 ) )\n\t\t\t\treturn( hn );\n\t\t\t*hn2 = *hn1;\n\t\t\thn1->type = TAG_SHARED;\n\t\t\tPPUT( hn1, \n\t\t\t\tELEMENT_NODE, hn2, \n\t\t\t\tELEMENT_CHAR, GUINT_TO_POINTER( \n\t\t\t\t\tcompile_share_number ) );\n\n\t\t\tcompile_share_number++;\n\t\t\tif( compile_share_number == MAX_RELOC ) {\n\t\t\t\terror_top( _( \"Too many shared nodes in \"\n\t\t\t\t\t\"graph.\" ) );\n\t\t\t\terror_sub( _( \"Raise MAX_RELOC\" ) );\n\t\t\t\treturn( hn );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn( NULL );\n}\n\n/* Do common-subexpression elimination. \n */\nstatic gboolean\ncompile_remove_subexpr( Compile *compile, PElement *root )\n{\n\tHeapNode *rootn = PEGETVAL( root );\n#ifdef DEBUG_COMMON\n\tstatic int compile_node_total = 0;\n#endif /*DEBUG_COMMON*/\n\n\tif( PEGETTYPE( root ) != ELEMENT_NODE )\n\t\t/* Nowt to do.\n\t\t */\n\t\treturn( TRUE );\n\n#ifdef DEBUG_COMMON\n\tcompile_node_sum = 0;\n#endif /*DEBUG_COMMON*/\n\n\t/* Scan for common nodes, replace stuff we remove with REFERENCE\n  \t * nodes.\n\t */\n\tcompile_share_scan( compile, root );\n\n\t/* Now search for destinations of reference nodes and mark all shared\n\t * sections. Each shared section is given a number ... saves a lookup\n\t * during copy.\n\t */\n\tcompile_share_number = 0;\n\tif( heap_map( rootn, \n\t\t(heap_map_fn) compile_transform_share, compile, NULL ) ) {\n\t\t/* We can't leave the graph half-done, it'll confuse the copier\n\t\t * later. Zap the graph.\n\t\t */\n\t\tPEPUTP( root, ELEMENT_NOVAL, NULL );\n\t\treturn( FALSE );\n\t}\n\n#ifdef DEBUG_COMMON\n\tif( compile_node_sum ) {\n\t\tcompile_node_total += compile_node_sum;\n\t\tprintf( \"compile_remove_subexpr: \" );\n\t\tsymbol_name_print( compile->sym );\n\t\tprintf( \"saved %d nodes (total %d)\\n\", \n\t\t\tcompile_node_sum, compile_node_total );\n\t}\n#endif /*DEBUG_COMMON*/\n\n\treturn( TRUE );\n}\n\n/* Top-level compiler driver.\n */\n\n/* Compile a symbol into a heap. \n */\nstatic void *\ncompile_heap( Compile *compile )\n{\n\tPElement base;\n\n\t/* Don't generate code for parser temps.\n\t */\n\tif( compile->sym->placeholder )\n\t\treturn( NULL );\n\n\tPEPOINTE( &base, &compile->base );\n\n\t/* Is there an existing function base? GC it away.\n\t */\n\tif( PEGETTYPE( &base ) != ELEMENT_NOVAL ) {\n\t\tPEPUTP( &base, ELEMENT_NOVAL, (void *) 2 );\n\t\tif( !heap_gc( compile->heap ) )\n\t\t\treturn( compile->sym );\n\n\t\treturn( NULL );\n\t}\n\n#ifdef DEBUG\n\tprintf( \"*** compile_expr: about to compile \" );\n\tsymbol_name_print( compile->sym );\n\tprintf( \"\\n\" );\n\tif( compile->tree )\n\t\tdump_tree( compile->tree );\n#endif /*DEBUG*/\n\n\t/* Compile function body. Tree can be NULL for classes.\n\t */\n\tif( compile->tree ) {\n\t\tif( !compile_graph( compile, compile->tree, &base ) )\n\t\t\treturn( compile->sym );\n\t}\n\telse {\n\t\tPEPUTP( &base, ELEMENT_NOVAL, (void *) 3 );\n\t}\n\n#ifdef DEBUG\n{\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_pelement( compile->heap, &buf, &base, TRUE );\n\tprintf( \"before var abstraction, compiled \\\"%s\\\" to: %s\\n\", \n\t\tIOBJECT( compile->sym )->name, vips_buf_all( &buf ) );\n}\n#endif /*DEBUG*/\n\n\t/* Abstract real parameters.\n\t */\n#ifdef DEBUG\n\tprintf( \"abstracting real params ...\\n\" );\n#endif /*DEBUG*/\n\tif( slist_map2_rev( compile->param,\n\t\t(SListMap2Fn) compile_abstract_symbol, compile, &base ) )\n\t\t\treturn( compile->sym );\n\n\t/* Abstract secret parameters. \n\t */\n#ifdef DEBUG\n\tprintf( \"abstracting secret params ...\\n\" );\n#endif /*DEBUG*/\n\tif( slist_map2_rev( compile->secret,\n\t\t(SListMap2Fn) compile_abstract_symbol, compile, &base ) )\n\t\t\treturn( compile->sym );\n\n\t/* Remove common sub-expressions.\n\t */\n\tif( !compile_remove_subexpr( compile, &base ) )\n\t\treturn( compile->sym );\n\n#ifdef DEBUG_RESULT\n{\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tprintf( \"compiled \" );\n\tsymbol_name_print( compile->sym );\n\tprintf( \"to: \" );\n\tgraph_pelement( compile->heap, &buf, &base, TRUE );\n\tprintf( \"%s\\n\", vips_buf_all( &buf ) );\n}\n#endif /*DEBUG_RESULT*/\n\n\treturn( NULL );\n}\n\nstatic void *compile_object_sub( Compile *compile );\n\nstatic void *\ncompile_symbol_sub( Symbol *sym )\n{\n\tCompile *compile;\n\n\tif( sym->expr && (compile = sym->expr->compile) )\n\t\tif( compile_object_sub( compile ) )\n\t\t\treturn( sym );\n\n\treturn( NULL );\n}\n\nstatic void *\ncompile_object_sub( Compile *compile )\n{\n\tif( icontainer_map( ICONTAINER( compile ),\n\t\t(icontainer_map_fn) compile_symbol_sub, NULL, NULL ) )\n\t\treturn( compile );\n\n\tif( compile_heap( compile ) )\n\t\treturn( compile );\n\n\treturn( NULL );\n}\n\n/* Top-level compile a thing entry point.\n */\nvoid *\ncompile_object( Compile *compile )\n{\n\t/* Walk this tree of symbols computing the secret lists.\n\t */\n\tsecret_build( compile );\n\n\t/* Compile all definitions from the inside out.\n\t */\n\tif( compile_object_sub( compile ) )\n\t\treturn( compile );\n\n\treturn( NULL );\n}\n\nstatic void *\ncompile_toolkit_sub( Tool *tool )\n{\n\tCompile *compile;\n\n\tif( tool->sym && tool->sym->expr && \n\t\t(compile = tool->sym->expr->compile )) \n\t\t/* Only if we have no code.\n\t\t */\n\t\tif( compile->base.type == ELEMENT_NOVAL ) \n\t\t\tif( compile_object( compile ) )\n\t\t\t\treturn( tool );\n\n\treturn( NULL );\n}\n\n/* Scan a toolkit and make sure all the symbols have been compiled.\n */\nvoid *\ncompile_toolkit( Toolkit *kit )\n{\n\treturn( toolkit_map( kit,\n\t\t(tool_map_fn) compile_toolkit_sub, NULL, NULL ) );\n}\n\n/* Parse support.\n */\n\nstatic ParseNode *\ncompile_check_i18n( Compile *compile, ParseNode *pn )\n{\n\tswitch( pn->type ) {\n\tcase NODE_APPLY:\n\t\tif( pn->arg1->type == NODE_LEAF && \n\t\t\tstrcmp( IOBJECT( pn->arg1->leaf )->name, \"_\" ) == 0 &&\n\t\t\tpn->arg2->type == NODE_CONST &&\n\t\t\tpn->arg2->con.type == PARSE_CONST_STR ) {\n\t\t\tconst char *text = pn->arg2->con.val.str;\n\n\t\t\tif( main_option_i18n ) {\n\t\t\t\t/* Remove msgid duplicates with this.\n\t\t\t\t */\n\t\t\t\tstatic GHashTable *msgid = NULL;\n\n\t\t\t\tif( !msgid ) \n\t\t\t\t\tmsgid = g_hash_table_new( \n\t\t\t\t\t\tg_str_hash, g_str_equal );\n\n\t\t\t\tif( !g_hash_table_lookup( msgid, text ) ) {\n\t\t\t\t\tchar buf[MAX_STRSIZE];\n\n\t\t\t\t\tg_hash_table_insert( msgid, \n\t\t\t\t\t\t(void *) text, NULL ); \n\t\t\t\t\tmy_strecpy( buf, text, TRUE );\n\t\t\t\t\tprintf( \"msgid \\\"%s\\\"\\n\", buf );\n\t\t\t\t\tprintf( \"msgstr \\\"\\\"\\n\\n\" );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* We can gettext these at compile time. Replace the\n\t\t\t * APPLY node with a fixed-up text string.\n\t\t\t */\n\t\t\tpn->type = NODE_CONST;\n\t\t\tpn->con.type = PARSE_CONST_STR;\n\t\t\tpn->con.val.str = im_strdupn( _( text ) );\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn( NULL );\n}\n\nstatic ParseNode *\ncompile_check_more( Compile *compile, ParseNode *pn )\n{\n\tswitch( pn->type ) {\n\tcase NODE_BINOP:\n\t\tswitch( pn->biop ) {\n\t\tcase BI_MORE:\n\t\t\tpn->biop = BI_LESS;\n\t\t\tSWAPP( pn->arg1, pn->arg2 );\n\t\t\tbreak;\n\n\t\tcase BI_MOREEQ:\n\t\t\tpn->biop = BI_LESSEQ;\n\t\t\tSWAPP( pn->arg1, pn->arg2 );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn( NULL );\n}\n\n/* Do end-of-parse checks. Called after every 'A = ...' style definition (not \n * just top-level syms). Used to do lots of checks, not much left now.\n */\ngboolean\ncompile_check( Compile *compile )\n{\n\tSymbol *sym = compile->sym;\n\tSymbol *parent = symbol_get_parent( sym );\n\n\t/* Check \"check\" member. \n\t */ \n\tif( is_member( sym ) &&\n\t\tstrcmp( IOBJECT( sym )->name, MEMBER_CHECK ) == 0 ) {\n\t\tif( compile->nparam != 0 ) {\n\t\t\terror_top( _( \"Too many arguments.\" ) );\n\t\t\terror_sub( _( \"Member \\\"%s\\\" of class \"\n\t\t\t\t\"\\\"%s\\\" should have no arguments.\" ),\n\t\t\t\tMEMBER_CHECK, symbol_name( parent ) );\n\n\t\t\treturn( FALSE );\n\t\t}\n\t}\n\n\t/* Look for (_ \"string constant\") and pump it through gettext. We can\n\t * do a lot of i18n at compile-time.\n\t */\n#ifdef DEBUG\n\tprintf( \"compile_check_i18n: \" );\n\tcompile_name_print( compile );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\t(void) tree_map( compile, \n\t\t(tree_map_fn) compile_check_i18n, compile->tree, NULL, NULL );\n\n\t/* Swap MORE and MOREEQ for LESS and LESSEQ. Reduces the number of\n\t * cases for the compiler. \n\t */\n\t(void) tree_map( compile, \n\t\t(tree_map_fn) compile_check_more, compile->tree, NULL, NULL );\n\n\treturn( TRUE );\n}\n\n/* Mark error on all exprs using this compile.\n */\nvoid\ncompile_error_set( Compile *compile )\n{\n\t(void) slist_map( compile->exprs, (SListMapFn) expr_error_set, NULL );\n}\n\n/* Patch a pointer on a patch list. \n */\nstatic void *\ncompile_patch_pointers_sub( void **pnt, void *nsym, void *osym )\n{\n\tg_assert( *pnt == osym );\n\n\t*pnt = nsym;\n\n\treturn( NULL );\n}\n\n/* Patch pointers to old to point to new instead.\n */\nstatic void\ncompile_patch_pointers( Symbol *nsym, Symbol *osym )\n{\n\t(void) slist_map2( osym->patch, \n\t\t(SListMap2Fn) compile_patch_pointers_sub, nsym, osym );\n}\n\n/* Sub fn of below.\n */\nstatic void *\ncompile_resolve_sub( Compile *pnt, Symbol *sym )\n{\n\tif( !g_slist_find( sym->parents, pnt ) ) \n\t\tsym->parents = g_slist_prepend( sym->parents, pnt );\n\n\treturn( NULL );\n}\n\n/* Sub fn 2 of below.\n */\nstatic void *\ncompile_resolve_sub1( Compile *compile )\n{\n\treturn( symbol_fix_counts( compile->sym ) );\n}\n\n/* We've found a symbol which is the true definition of an unresolved symbol.\n * We fiddle references to zombie to refer to sym instead.\n */\nstatic void\ncompile_resolve( Symbol *sym, Symbol *zombie )\n{\n#ifdef DEBUG_RESOLVE\n\tprintf( \"compile_resolve: resolving zombie \" );\n\tsymbol_name_print( zombie );\n\tprintf( \"to symbol \" );\n\tsymbol_name_print( sym );\n\tprintf( \"\\n\" );\n#endif /*DEBUG_RESOLVE*/\n\n\t/* Symbol on outer table. Patch pointers to zombie to point to\n\t * sym instead.\n\t */\n\tcompile_patch_pointers( sym, zombie );\n\n\t/* Also unresolved in outer scope?\n\t */\n\tif( sym->type == SYM_ZOMBIE )\n\t\t/* We may need to move it again - so add the patch\n\t\t * pointers we have just used to the patch list on\n\t\t * sym.\n\t\t */\n\t\t(void) slist_map( zombie->patch, \n\t\t\t(SListMapFn) symbol_patch_add, sym );\n\n\t/* Add other information the ZOMBIE has picked up. We only\n\t * need to make the link one way: the patching will make the\n\t * other half for us.\n\t */\n\t(void) slist_map( zombie->parents, \n\t\t(SListMapFn) compile_resolve_sub, sym );\n\n\t/* Make sure the dirty counts are set correctly. We have\n\t * changed dep (maybe), so need a fiddle.\n\t */\n\t(void) slist_map( zombie->parents, \n\t\t(SListMapFn) compile_resolve_sub1, NULL );\n\n\t/* No one refers to the zombie now.\n\t */\n\tIM_FREEF( g_slist_free, zombie->parents );\n\n\tIDESTROY( zombie );\n}\n\n/* Sub-function of below.\n */\nstatic void *\ncompile_resolve_names_sub( Symbol *sym, Compile *outer )\n{\n\tconst char *name = IOBJECT( sym )->name;\n\tSymbol *old;\n\n\t/* Is it the sort of thing we are looking for? ZOMBIEs only, please.\n\t */\n\tif( sym->type != SYM_ZOMBIE )\n\t\treturn( NULL );\n\n\tif( (old = compile_lookup( outer, name )) ) \n\t\tcompile_resolve( old, sym );\n\telse {\n\t\t/* Nothing on the outer table of that name. Can just move the\n\t\t * symbol across.\n\t\t */\n\t\tg_object_ref( G_OBJECT( sym ) );\n\t\ticontainer_child_remove( ICONTAINER( sym ) );\n\t\ticontainer_child_add( ICONTAINER( outer ), \n\t\t\tICONTAINER( sym ), -1 );\n\t\tg_object_unref( G_OBJECT( sym ) );\n\t}\n\n\treturn( NULL );\n}\n\n/* End of definition parse: we search the symbol table we have built for this\n * definition, looking for unresolved names (ZOMBIEs). If we find any, we move\n * the zombie to the enclosing symbol table, since the name may be\n * resolved one level up. If we find a symbol on the enclosing table of the\n * same name, we have to patch pointers to our inner ZOMBIE to point to this\n * new symbol. Nasty!\n */\nvoid\ncompile_resolve_names( Compile *inner, Compile *outer )\n{\n\t(void) icontainer_map( ICONTAINER( inner ), \n\t\t(icontainer_map_fn) compile_resolve_names_sub, outer, NULL );\n}\n\n/* Hit a top-level zombie during reduction. Search outwards to root looking on\n * enclosing tables for a match.\n */\nSymbol *\ncompile_resolve_top( Symbol *sym )\n{\n\tCompile *enclosing;\n\n\tfor( enclosing = COMPILE( ICONTAINER( sym )->parent ); enclosing;\n\t\tenclosing = compile_get_parent( enclosing ) ) {\n\t\tSymbol *outer_sym;\n\n\t\tif( (outer_sym = compile_lookup( enclosing, \n\t\t\tIOBJECT( sym )->name )) &&\n\t\t\touter_sym->type != SYM_ZOMBIE )\n\t\t\treturn( outer_sym );\n\t}\n\n\treturn( NULL );\n}\n\n/* Search outwards for this sym.\n */\nstatic void *\ncompile_resolve_dynamic_sub( Symbol *sym, Compile *context )\n{\n\tCompile *tab;\n\n\tif( sym->type != SYM_ZOMBIE )\n\t\treturn( NULL );\n\n\tfor( tab = context; tab; tab = compile_get_parent( tab ) ) {\n\t\tSymbol *def = compile_lookup( tab, IOBJECT( sym )->name );\n\n\t\tif( def && def->type != SYM_ZOMBIE ) {\n\t\t\t/* We've found a non-zombie! Bind and we're done.\n\t\t\t */\n\t\t\tcompile_resolve( def, sym );\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn( NULL );\n}\n\n/* Resolve ZOMBIEs in tab by searching outwards from context. We only move \n * and patch if we find a match ... otherwise we leave the zombie where is is.\n *\n * This is used for dynamic exprs in the tally display: we don't care about\n * fwd refs, but we want to be able to handle multiple scope contexts.\n */\nvoid \ncompile_resolve_dynamic( Compile *tab, Compile *context )\n{\n\t(void) icontainer_map( ICONTAINER( tab ), \n\t\t(icontainer_map_fn) compile_resolve_dynamic_sub, \n\t\tcontext, NULL );\n}\n\nSymbol *\ncompile_get_member( Compile *compile, const char *name )\n{\n\tiContainer *child;\n\n\tif( is_class( compile ) && \n\t\t(child = icontainer_child_lookup( ICONTAINER( compile ), \n\t\t\tname )) )\n\t\treturn( SYMBOL( child ) );\n\n\treturn( NULL );\n}\n\nconst char *\ncompile_get_member_string( Compile *compile, const char *name )\n{\n\tSymbol *member;\n\tCompile *member_compile;\n\n\tif( (member = compile_get_member( compile, name )) &&\n\t\tis_value( member ) && \n\t\t(member_compile = member->expr->compile) &&\n\t\tmember_compile->tree && \n\t\tmember_compile->tree->type == NODE_CONST &&\n\t\tmember_compile->tree->con.type == PARSE_CONST_STR ) \n\t\treturn( member_compile->tree->con.val.str );\n\n\treturn( NULL );\n}\n\nstatic void *\ncompile_find_generated_node( Compile *compile, ParseNode *node,\n\tGSList **list )\n{\n\tSymbol *sym = node->leaf;\n\n        if( node->type == NODE_LEAF &&\n\t\tsym->generated &&\n\t\tsymbol_get_parent( sym ) &&\n\t\tsymbol_get_parent( sym )->expr->compile == compile ) \n\t\t*list = g_slist_prepend( *list, sym );\n\n\treturn( NULL );\n}\n\n/* Search a scrap of tree and build a list of all the lambdas/lcomps/etc. it\n * generated.\n */\nstatic GSList *\ncompile_find_generated( Compile *compile, ParseNode *tree )\n{\n\tGSList *list;\n\n\tlist = NULL;\n\ttree_map( compile,\n\t\t(tree_map_fn) compile_find_generated_node, tree, &list, NULL );\n\n\treturn( list );\n}\n\n/* Make a copy of sym (and all it's children and trees) in the destination \n * scope. This only works for stuff from the parse stage. Symbols which have\n * values and stuff attached are too complicated to copy easily.\n */\nstatic void *\ncompile_copy_sym( Symbol *sym, Compile *dest )\n{\n\tconst char *name = IOBJECT( sym )->name;\n\tSymbol *copy_sym;\n\n#ifdef DEBUG\n\tprintf( \"compile_copy_sym: copying \" );\n\tsymbol_name_print( sym );\n\tprintf( \"to scope of \" );\n\tcompile_name_print( dest );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Must be a different place.\n\t */\n\tg_assert( symbol_get_parent( sym )->expr->compile != dest );\n\n\t/* Must not be an existing sym of that name. Or if there is, it has to\n\t * be a zombie.\n\t */\n\tg_assert( !compile_lookup( dest, name ) ||\n\t\tcompile_lookup( dest, name )->type == SYM_ZOMBIE );\n\n\tswitch( sym->type ) {\n\tcase SYM_VALUE:\n\t\tcopy_sym = symbol_new_defining( dest, name );\n\t\tcopy_sym->generated = sym->generated;\n\t\t(void) symbol_user_init( copy_sym );\n\t\t(void) compile_new_local( copy_sym->expr );\n\n\t\t/* Copy any locals over. We have to do this before we copy the\n\t\t * tree so that the new tree links to the new syms.\n\t\t */\n\t\ticontainer_map( ICONTAINER( sym->expr->compile ),\n\t\t\t(icontainer_map_fn) compile_copy_sym, \n\t\t\tcopy_sym->expr->compile, NULL );\n\n\t\tcopy_sym->expr->compile->tree = tree_copy( \n\t\t\tcopy_sym->expr->compile, sym->expr->compile->tree );\n\n\t\t/* Copying the tree may have made some zombies. Resolve \n\t\t * outwards.\n\t\t */\n\t\tcompile_resolve_names( copy_sym->expr->compile, dest );\n\n\t\tbreak;\n\n\tcase SYM_PARAM:\n\t\tcopy_sym = symbol_new_defining( dest, name );\n\t\tcopy_sym->generated = sym->generated;\n\t\tsymbol_parameter_init( copy_sym );\n\t\tbreak;\n\n\tcase SYM_ZOMBIE:\n\t\tbreak;\n\n\tcase SYM_WORKSPACE:\n\tcase SYM_WORKSPACEROOT:\n\tcase SYM_ROOT:\n\tcase SYM_EXTERNAL:\n\tcase SYM_BUILTIN:\n\tdefault:\n\t\tg_assert( 0 );\n\t}\n\n\treturn( NULL );\n}\n\n/* tree is a scrap of graph in fromscope's context. It may have caused the\n * generation of a number of lambdas, lcomps etc. in fromscope. Make a copy\n * of the tree in toscope and copy over any generated syms too. fromscope and\n * toscope can be the same, in which case we can just copy the tree.\n */\nParseNode *\ncompile_copy_tree( Compile *fromscope, ParseNode *tree, Compile *toscope )\n{\n\tParseNode *copy_tree;\n\n#ifdef DEBUG\n\tprintf( \"compile_copy_tree: copying tree from \" );\n\tcompile_name_print( fromscope );\n\tprintf( \" to \" );\n\tcompile_name_print( toscope );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* A new context? Copy generated syms over.\n\t */\n\tif( fromscope != toscope ) {\n\t\tGSList *generated;\n\n\t\tgenerated = compile_find_generated( fromscope, tree );\n\n#ifdef DEBUG\n\t\tprintf( \"with generated children: \" ); \n\t\t(void) slist_map( generated, (SListMapFn) dump_tiny, NULL );\n\t\tprintf( \"\\n\" ); \n#endif /*DEBUG*/\n\n\t\tslist_map( generated, \n\t\t\t(SListMapFn) compile_copy_sym, toscope );\n\n\t\tg_slist_free( generated );\n\t}\n\n\tcopy_tree = tree_copy( toscope, tree );\n\n\t/* Copying the tree may have made some zombies. Resolve \n\t * outwards.\n\t */\n\tcompile_resolve_names( toscope, compile_get_parent( toscope ) );\n\n\treturn( copy_tree );\n}\n\n/* Generate the parse tree for this list comprehension. \n\n  Example: after parse we have:\n\n\t[(x, y) :: x <- [1..3]; y <- [x..3]; x + y > 3];\n\n\t... $$lcomp1 ...\n\t{\n\t\t$$lcomp1 = NULL\n\t\t{\n\t\t\t$$result = (x, y);\n\t\t\t// elements in left-to-right order\n\t\t\t// in compile->children\n\t\t\tx = [1..3]\n\t\t\ty = [x..3]\n\t\t\t$$filter1 = x + y > 3\n\t\t}\n\t}\n\n  and we generate this code:\n\n  \tz = $$lcomp1\n\t{\n\t\t$$lcomp1 = foldr $f1 [] [1..3]\n\t\t{\n\t\t\t$f1 x $sofar = foldr $f2 $sofar [x..3]\n\t\t\t{\n\t\t\t\t$f2 y $sofar = if x + y > 3 then $f3 else $sofar\n\t\t\t\t{\n\t\t\t\t\t$f3 = (x, y) : $sofar;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n */\n\n/* Find the placeholders generated by the parser. Filters, generators,\n * patterns and $$result. \n */\nstatic void *\ncompile_lcomp_find( Symbol *sym, GSList **children )\n{\n\tif( sym->placeholder )\n\t\t*children = g_slist_append( *children, sym );\n\n\treturn( NULL );\n}\n\nstatic Symbol *\ncompile_lcomp_find_pattern( GSList *children, const char *generator )\n{\n\tint n;\n\tchar pattern[256];\n\tGSList *p;\n\n\tif( sscanf( generator, \"$$generator%d\", &n ) != 1 )\n\t\treturn( NULL );\n\tim_snprintf( pattern, 256, \"$$pattern%d\", n );\n\n\tfor( p = children; p; p = p->next ) {\n\t\tSymbol *sym = (Symbol *) p->data;\n\n\t\tif( strcmp( IOBJECT( sym )->name, pattern ) == 0 )\n\t\t\treturn( sym );\n\t}\n\n\treturn( NULL );\n}\n\nvoid \ncompile_lcomp( Compile *compile )\n{\n\t/* Number nested locals with this. Keep numbering global so debugging\n\t * nested lcomps is easier.\n\t */\n\tstatic int count = 1;\n\n\tGSList *children;\n\tgboolean sofar;\n\tCompile *scope;\n\tSymbol *result;\n\tGSList *p;\n\tSymbol *child;\n\tchar name[256];\n\tParseNode *n1, *n2, *n3;\n\n#ifdef DEBUG_LCOMP\n\tprintf( \"before compile_lcomp:\\n\" );\n\tdump_compile( compile );\n#endif /*DEBUG_LCOMP*/\n\n\t/* Find all the elements of the lcomp: generators, filters, patterns \n\t * and $$result.\n\t */\n\tchildren = NULL;\n\t(void) icontainer_map( ICONTAINER( compile ), \n\t\t(icontainer_map_fn) compile_lcomp_find, &children, NULL );\n\n#ifdef DEBUG_LCOMP\n\tprintf( \"list comp \" );\n\tcompile_name_print( compile );\n\tprintf( \" has children: \" ); \n\t(void) slist_map( children, (SListMapFn) dump_tiny, NULL );\n\tprintf( \"\\n\" ); \n#endif /*DEBUG_LCOMP*/\n\n\t/* As yet no list to build on.\n\t */\n\tsofar = FALSE;\n\n\t/* Start by building a tree in this scope.\n\t */\n\tscope = compile;\n\n\t/* Not seen the result element yet, but we should.\n\t */\n\tresult = NULL;\n\n\t/* Now generate code for each element, either a filter or a generator.\n\t * If we do a generator, we need to search for the associated pattern\n\t * and expand it.\n\t */\n\tfor( p = children; p; p = p->next ) {\n\t\tSymbol *element = (Symbol *) p->data;\n\n\t\t/* Just note the result element ... we use it right at the end.\n\t\t */\n\t\tif( strcmp( \"$$result\", IOBJECT( element )->name ) == 0 ) {\n\t\t\tresult = element;\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* And only process filter/gen.\n\t\t */\n\t\tif( !is_prefix( \"$$filter\", IOBJECT( element )->name ) &&\n\t\t\t!is_prefix( \"$$gen\", IOBJECT( element )->name ) ) \n\t\t\tcontinue;\n\n\t\t/* Start the next nest in. child is the local we will make for\n\t\t * this scope.\n\t\t */\n\t\tim_snprintf( name, 256, \"$$fn%d\", count++ );\n\t\tchild = symbol_new_defining( scope, name );\n\t\tchild->generated = TRUE;\n\t\t(void) symbol_user_init( child );\n\t\t(void) compile_new_local( child->expr );\n\n\t\tif( is_prefix( \"$$filter\", IOBJECT( element )->name ) ) {\n\t\t\t/* A filter.\n\t\t\t */\n\t\t\tn1 = compile_copy_tree( compile, \n\t\t\t\telement->expr->compile->tree,\n\t\t\t\tscope );\n\t\t\tn2 = tree_leafsym_new( scope, child );\n\t\t\tn3 = tree_leaf_new( scope, \"$$sofar\" );\n\t\t\tn1 = tree_ifelse_new( scope, n1, n2, n3 );\n\t\t\tscope->tree = n1;\n\t\t}\n\t\telse if( is_prefix( \"$$gen\", IOBJECT( element )->name ) ) {\n\t\t\tSymbol *param1;\n\t\t\tSymbol *param2;\n\t\t\tSymbol *pattern;\n\t\t\tGSList *built_syms;\n\n\t\t\t/* A generator. \n\t\t\t */\n\t\t\tparam1 = symbol_new_defining( child->expr->compile, \n\t\t\t\tIOBJECT( element )->name );\n\t\t\tparam1->generated = TRUE;\n\t\t\tsymbol_parameter_init( param1 );\n\t\t\tparam2 = symbol_new_defining( child->expr->compile, \n\t\t\t\t\"$$sofar\" );\n\t\t\tparam2->generated = TRUE;\n\t\t\tsymbol_parameter_init( param2 );\n\n\t\t\t/* Now expand the pattern: it will access parts of the\n\t\t\t * $$generator argument.\n\t\t\t */\n\t\t\tpattern = compile_lcomp_find_pattern( children, \n\t\t\t\tIOBJECT( element )->name );\n\t\t\tg_assert( pattern );\n\t\t\tbuilt_syms = compile_pattern_lhs( child->expr->compile, \n\t\t\t\tparam1, pattern->expr->compile->tree );\n\t\t\tg_slist_free( built_syms );\n\n\t\t\t/* Make the \"foldr $$fn $sofar expr\" tree.\n\t\t\t */\n\t\t\tn1 = tree_leaf_new( scope, \"foldr\" );\n\t\t\tn2 = tree_leafsym_new( scope, child );\n\t\t\tn3 = tree_appl_new( scope, n1, n2 );\n\t\t\tif( sofar )\n\t\t\t\tn2 = tree_leaf_new( scope, \"$$sofar\" );\n\t\t\telse {\n\t\t\t\tParseConst con;\n\n\t\t\t\tcon.type = PARSE_CONST_ELIST;\n\t\t\t\tn2 = tree_const_new( scope, con );\n\t\t\t}\n\t\t\tn3 = tree_appl_new( scope, n3, n2 );\n\t\t\tn2 = compile_copy_tree( compile,\n\t\t\t\telement->expr->compile->tree, \n\t\t\t\tscope );\n\t\t\tn3 = tree_appl_new( scope, n3, n2 );\n\t\t\tscope->tree = n3;\n\n\t\t\t/* There's now an enclosing sofar we can use.\n\t\t\t */\n\t\t\tsofar = TRUE;\n\t\t}\n\n\t\t/* Nest in again.\n\t\t */\n\t\tscope = child->expr->compile;\n\t}\n\n\t/* Copy the code for the final result.\n\t */\n\tg_assert( result );\n\n\tn1 = compile_copy_tree( result->expr->compile, \n\t\tresult->expr->compile->tree, scope );\n\tn2 = tree_leaf_new( scope, \"$$sofar\" );\n\tn3 = tree_binop_new( compile, BI_CONS, n1, n2 );\n\tscope->tree = n3;\n\n\t/* Loop outwards again, closing the scopes we made.\n\t */\n\twhile( scope != compile ) {\n\t\t/* We know check can't fail on generated code.\n\n\t\t   \tFIXME ... yuk, maybe compile_lcomp should be \n\t\t\tfailable too\n\n\t\t */\n\t\t(void) compile_check( scope );\n\t\tcompile_resolve_names( scope, compile_get_parent( scope ) );\n\n\t\tscope = compile_get_parent( scope );\n\t}\n\n#ifdef DEBUG_LCOMP\n\tprintf( \"after compile_lcomp:\\n\" );\n\tdump_compile( compile );\n#endif /*DEBUG_LCOMP*/\n\n\tg_slist_free( children );\n}\n\n/* Compile a pattern LHS. Generate a sym for each pattern variable, each of\n * which checks and accesses sym. For example:\n *\n *\t[a] = x;\n *\n * compiles to:\n *\n * \tsym = x;\n * \ta = if is_list sym && len sym == 1 then sym?0 else error \"..\";\n */\n\n/* Generate code to access element n of a pattern trail. Eg, pattern is\n * \t[[[a]]]\n * the trail will be \n * \t0) LISTCONST 1) LISTCONST 2) LISTCONST 3) LEAF\n * then access(0) will be\n * \tleaf\n * and access(1) will be\n * \tleaf?0\n * and access(3) (to get the value for a) will be\n * \tleaf?0?0?0\n */\nstatic ParseNode *\ncompile_pattern_access( Compile *compile, \n\tSymbol *leaf, ParseNode **trail, int n )\n{\n\tParseNode *node;\n\tParseNode *left;\n\tParseNode *right;\n\tParseConst c;\n\tint i;\n\n\t/* The initial leaf ref we access from.\n\t */\n\tnode = tree_leafsym_new( compile, leaf );\n\n\tfor( i = 0; i < n; i++ )\n\t\tswitch( trail[i]->type ) {\n\t\tcase NODE_CONST:\n\t\tcase NODE_PATTERN_CLASS:\n\t\tcase NODE_LEAF:\n\t\t\tbreak;\n\n\t\tcase NODE_BINOP:\n\t\t\tswitch( trail[i]->biop ) {\n\t\t\tcase BI_COMMA:\n\t\t\t\t/* Generate re or im?\n\t\t\t\t */\n\t\t\t\tif( trail[i]->arg1 == trail[i + 1] )\n\t\t\t\t\tleft = tree_leaf_new( compile, \"re\" );\n\t\t\t\telse\n\t\t\t\t\tleft = tree_leaf_new( compile, \"im\" );\n\t\t\t\tnode = tree_appl_new( compile, left, node );\n\t\t\t\tbreak;\n\n\t\t\tcase BI_CONS:\n\t\t\t\t/* Generate hd or tl?\n\t\t\t\t */\n\t\t\t\tif( trail[i]->arg1 == trail[i + 1] )\n\t\t\t\t\tleft = tree_leaf_new( compile, \"hd\" );\n\t\t\t\telse\n\t\t\t\t\tleft = tree_leaf_new( compile, \"tl\" );\n\t\t\t\tnode = tree_appl_new( compile, left, node );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tg_assert( 0 );\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase NODE_LISTCONST:\n\t\t\t/* Which list element do we need? Look for the next\n\t\t\t * item in the trail in the list of elements.\n\t\t\t */\n\t\t\tc.type = PARSE_CONST_NUM;\n\t\t\tc.val.num = g_slist_index( trail[i]->elist, \n\t\t\t\ttrail[i + 1] );\n\t\t\tright = tree_const_new( compile, c );\n\t\t\tnode = tree_binop_new( compile, \n\t\t\t\tBI_SELECT, node, right );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tg_assert( 0 );\n\t\t}\n\n\treturn( node );\n}\n\n/* Generate a parsetree for the condition test. The array of nodes represents\n * the set of conditions we have to test, left to right. \n */\nstatic ParseNode *\ncompile_pattern_condition( Compile *compile, \n\tSymbol *leaf, ParseNode **trail, int depth )\n{\n\tParseConst n;\n\tParseNode *node;\n\tParseNode *node2;\n\tParseNode *left;\n\tParseNode *right;\n\tint i;\n\n\tn.type = PARSE_CONST_BOOL;\n\tn.val.bol = TRUE;\n\tnode = tree_const_new( compile, n );\n\n\tfor( i = depth - 1; i >= 0; i-- ) {\n\t\tswitch( trail[i]->type ) {\n\t\tcase NODE_LEAF:\n\t\t\tbreak;\n\n\t\tcase NODE_BINOP:\n\t\t\tswitch( trail[i]->biop ) {\n\t\t\tcase BI_COMMA:\n\t\t\t\t/* Generate is_complex x.\n\t\t\t\t */\n\t\t\t\tleft = tree_leaf_new( compile, \"is_complex\" );\n\t\t\t\tright = compile_pattern_access( compile, \n\t\t\t\t\tleaf, trail, i );\n\t\t\t\tnode2 = tree_appl_new( compile, left, right );\n\n\t\t\t\tnode = tree_binop_new( compile, \n\t\t\t\t\tBI_LAND, node2, node );\n\t\t\t\tbreak;\n\n\t\t\tcase BI_CONS:\n\t\t\t\t/* Generate is_list x && x != [].\n\t\t\t\t */\n\t\t\t\tleft = tree_leaf_new( compile, \"is_list\" );\n\t\t\t\tright = compile_pattern_access( compile, \n\t\t\t\t\tleaf, trail, i );\n\t\t\t\tnode2 = tree_appl_new( compile, left, right );\n\n\t\t\t\tnode = tree_binop_new( compile, \n\t\t\t\t\tBI_LAND, node2, node );\n\n\t\t\t\tleft = compile_pattern_access( compile, \n\t\t\t\t\tleaf, trail, i );\n\t\t\t\tn.type = PARSE_CONST_ELIST;\n\t\t\t\tright = tree_const_new( compile, n );\n\t\t\t\tnode2 = tree_binop_new( compile, \n\t\t\t\t\tBI_NOTEQ, left, right );\n\n\t\t\t\tnode = tree_binop_new( compile, \n\t\t\t\t\tBI_LAND, node, node2 );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tg_assert( 0 );\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase NODE_LISTCONST:\n\t\t\t/* Generate is_list x && is_list_len n x.\n\t\t\t */\n\t\t\tleft = tree_leaf_new( compile, \"is_list\" );\n\t\t\tright = compile_pattern_access( compile, \n\t\t\t\tleaf, trail, i );\n\t\t\tnode2 = tree_appl_new( compile, left, right );\n\n\t\t\tnode = tree_binop_new( compile, BI_LAND, node2, node );\n\n\t\t\tleft = tree_leaf_new( compile, \"is_list_len\" );\n\t\t\tn.type = PARSE_CONST_NUM;\n\t\t\tn.val.num = g_slist_length( trail[i]->elist );\n\t\t\tright = tree_const_new( compile, n );\n\t\t\tleft = tree_appl_new( compile, left, right );\n\t\t\tright = compile_pattern_access( compile, \n\t\t\t\tleaf, trail, i );\n\t\t\tnode2 = tree_appl_new( compile, left, right );\n\n\t\t\tnode = tree_binop_new( compile, BI_LAND, node, node2 );\n\t\t\tbreak;\n\n\t\tcase NODE_CONST:\n\t\t\t/* Generate x == n.\n\t\t\t */\n\t\t\tleft = compile_pattern_access( compile, \n\t\t\t\tleaf, trail, i );\n\t\t\tright = tree_const_new( compile, trail[i]->con );\n\t\t\tnode2 = tree_binop_new( compile, BI_EQ, left, right );\n\n\t\t\tnode = tree_binop_new( compile, BI_LAND, node2, node );\n\t\t\tbreak;\n\n\t\tcase NODE_PATTERN_CLASS:\n\t\t\t/* Generate is_instanceof \"class-name\" x.\n\t\t\t */\n\t\t\tleft = tree_leaf_new( compile, \"is_instanceof\" );\n\t\t\tn.type = PARSE_CONST_STR;\n\t\t\tn.val.str = im_strdupn( trail[i]->tag );\n\t\t\tright = tree_const_new( compile, n );\n\t\t\tnode2 = tree_appl_new( compile, left, right );\n\t\t\tright = compile_pattern_access( compile, \n\t\t\t\tleaf, trail, i );\n\t\t\tnode2 = tree_appl_new( compile, node2, right );\n\n\t\t\tnode = tree_binop_new( compile, BI_LAND, node2, node );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tg_assert( 0 );\n\t\t}\n\t}\n\n\treturn( node );\n}\n\n/* Generate a parsetree for a \"pattern match failed\" error.\n */\nstatic ParseNode *\ncompile_pattern_error( Compile *compile, Symbol *leaf )\n{\n\tParseNode *left;\n\tParseConst n;\n\tParseNode *right;\n\tParseNode *node;\n\n\tleft = tree_leaf_new( compile, \"error\" );\n\tn.type = PARSE_CONST_STR;\n\tn.val.str = im_strdupn( _( \"pattern match failed\" ) );\n\tright = tree_const_new( compile, n );\n\tnode = tree_appl_new( compile, left, right );\n\n\treturn( node );\n}\n\n/* Depth of trail we keep as we walk the pattern.\n */\n#define MAX_TRAIL (10)\n\ntypedef struct _PatternLhs {\n\tCompile *compile;\t/* Scope in which we generate new symbols */\n\tSymbol *sym;\t\t/* Thing we access */\n\n\t/* The trail of nodes representing this slice of the pattern.\n\t */\n\tParseNode *trail[MAX_TRAIL];\n\tint depth;\n\tGSList *built_syms;\n} PatternLhs;\n\n/* Generate one reference. leaf is the new sym we generate.\n */\nstatic void\ncompile_pattern_lhs_leaf( PatternLhs *lhs, Symbol *leaf )\n{\n\tSymbol *sym;\n\tCompile *compile;\n\n\tsym = symbol_new_defining( lhs->compile, IOBJECT( leaf )->name );\n\tsym->generated = TRUE;\n\t(void) symbol_user_init( sym );\n\t(void) compile_new_local( sym->expr );\n\tlhs->built_syms = g_slist_prepend( lhs->built_syms, sym );\n\tcompile = sym->expr->compile;\n\n\tcompile->tree = tree_ifelse_new( compile, \n\t\tcompile_pattern_condition( compile, \n\t\t\tlhs->sym, lhs->trail, lhs->depth ),\n\t\tcompile_pattern_access( compile, \n\t\t\tlhs->sym, lhs->trail, lhs->depth ),\n\t\tcompile_pattern_error( compile, leaf ) );\n\n#ifdef DEBUG_PATTERN\n\tprintf( \"compile_pattern_lhs_leaf: generated\\n\" );\n\tdump_compile( compile );\n#endif /*DEBUG_PATTERN*/\n}\n\n/* Recurse over the pattern generating references.\n */\nstatic void *\ncompile_pattern_lhs_sub( ParseNode *node, PatternLhs *lhs )\n{\n\tlhs->trail[lhs->depth++] = node;\n\n\tswitch( node->type ) {\n\tcase NODE_LEAF:\n\t\tcompile_pattern_lhs_leaf( lhs, node->leaf );\n\t\tbreak;\n\n\tcase NODE_PATTERN_CLASS:\n\t\tcompile_pattern_lhs_sub( node->arg1, lhs );\n\t\tbreak;\n\n\tcase NODE_BINOP:\n\t\tcompile_pattern_lhs_sub( node->arg1, lhs );\n\t\tcompile_pattern_lhs_sub( node->arg2, lhs );\n\t\tbreak;\n\n\tcase NODE_LISTCONST:\n\t\tslist_map( node->elist,\n\t\t\t(SListMapFn) compile_pattern_lhs_sub, lhs );\n\t\tbreak;\n\n\tcase NODE_CONST:\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( 0 );\n\t}\n\n\tlhs->depth--;\n\n\treturn( NULL );\n}\n\n/* Something like \"[a] = [1];\". sym is the $$pattern we are generating access \n * syms for, node is the pattern tree, compile is the scope in which we\n * generate the new defining symbols. Return a list of the syms we built: they\n * will need any final finishing up and then having symbol_made() called on \n * them. You need to free the list, too.\n */\nGSList *\ncompile_pattern_lhs( Compile *compile, Symbol *sym, ParseNode *node )\n{\n\tPatternLhs lhs;\n\n#ifdef DEBUG_PATTERN\n\tprintf( \"compile_pattern_lhs: building access fns for %s\\n\", \n\t\tsymbol_name( sym ) );\n#endif /*DEBUG_PATTERN*/\n\n\tlhs.compile = compile;\n\tlhs.sym = sym;\n\tlhs.depth = 0;\n\tlhs.built_syms = NULL;\n\n\tcompile_pattern_lhs_sub( node, &lhs );\n\n\tg_assert( lhs.depth == 0 );\n\n\treturn( lhs.built_syms );\n}\n\nstatic ParseNode *\ncompile_pattern_has_leaf_sub( Compile *compile, \n\tParseNode *node, void *a, void *b )\n{\n\tif( node->type == NODE_LEAF )\n\t\treturn( node );\n\n\treturn( NULL );\n}\n\n/* Does a pattern contain a leaf? We don't allow const-only patterns in\n * definitions.\n */\ngboolean\ncompile_pattern_has_leaf( ParseNode *node )\n{\n\treturn( tree_map( NULL, \n\t\t(tree_map_fn) compile_pattern_has_leaf_sub, node, \n\t\tNULL, NULL ) != NULL );\n}\n"
  },
  {
    "path": "src/compile.h",
    "content": "/* Stuff to parse and compile text.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* Maximum number of shared sections of code in a copy.\n */\n#define MAX_RELOC (1000)\n\n#define TYPE_COMPILE (compile_get_type())\n#define COMPILE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_COMPILE, Compile ))\n#define COMPILE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_COMPILE, CompileClass))\n#define IS_COMPILE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_COMPILE ))\n#define IS_COMPILE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_COMPILE ))\n#define COMPILE_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_COMPILE, CompileClass ))\n\n/* What we track to parse and compile some text. Our children are our locals.\n */\nstruct _Compile {\n\tiContainer parent_object;\n\n\tSymbol *sym;\t\t/* We are part of this symbol, scopewise */\n\n\tGSList *exprs;\t\t/* We are used by these expressions */\n\n\tgboolean is_klass;\t/* True if this is a class */\n\tgboolean has_super;\t/* True if has a super-class */\n\n\tchar *text;\t\t/* The original text */\n\tchar *prhstext;\t\t/* Parameters plus the RHS of the definition */\n\tchar *rhstext;\t\t/* Just the RHS of the definition */\n\n\tParseNode *tree;\t/* Parse tree we built */\n\tGSList *treefrag;\t/* List of tree bits for easy freeing */\n\tSymbol *last_sym;\t/* The last child we added in this context */\n\n\tint nparam;\t\t/* Number of real parameters */\n\tGSList *param;\t\t/* Pointers into locals for real params */\n\tint nsecret;\t\t/* Number of secret parameters */\n\tGSList *secret;\t\t/* Pointers into locals for secret params */\n\tSymbol *this;\t\t/* If we are a class, the \"this\" local */\n\tSymbol *super;\t\t/* If we are a class, the \"super\" local */\n\tGSList *children;\t/* Symbols which we directly refer to */\n\n\tElement base; \t\t/* Base of compiled code */\n\tHeap *heap;\t\t/* Heap containing compiled code */\n\tGSList *statics;\t/* Static strings we built */\n};\n\ntypedef struct _CompileClass {\n\tiContainerClass parent_class;\n\n\t/* My methods.\n\t */\n} CompileClass;\n\nCompile *compile_get_parent( Compile *compile );\nvoid *compile_name_print( Compile *compile );\nvoid compile_name( Compile *compile, VipsBuf *buf );\n\ntypedef void *(*map_compile_fn)( Compile *, void * );\nCompile *compile_map_all( Compile *compile, map_compile_fn fn, void *a );\n\nSymbol *compile_lookup( Compile *compile, const char *name );\n\nvoid compile_link_make( Compile *compile, Symbol *child );\nvoid *compile_link_break( Compile *compile, Symbol *child );\n\nGtkType compile_get_type( void );\n\nvoid *compile_expr_link_break( Compile *compile, Expr *expr );\nvoid *compile_expr_link_break_rev( Expr *expr, Compile *compile );\nvoid compile_expr_link_make( Compile *compile, Expr *expr );\n\nCompile *compile_new( Expr *expr );\nCompile *compile_new_toplevel( Expr *expr );\nCompile *compile_new_local( Expr *expr );\n\nvoid *compile_object( Compile *compile );\nvoid *compile_toolkit( Toolkit *kit );\n\nvoid compile_error_set( Compile *compile );\ngboolean compile_check( Compile *compile );\n\nvoid compile_resolve_names( Compile *inner, Compile *outer );\nSymbol *compile_resolve_top( Symbol *sym );\nvoid compile_resolve_dynamic( Compile *tab, Compile *context );\n\nSymbol *compile_get_member( Compile *compile, const char *name );\nconst char *compile_get_member_string( Compile *compile, const char *name );\n\nParseNode *compile_copy_tree( Compile *fromscope, ParseNode *tree,\n\tCompile *toscope );\n\nvoid compile_lcomp( Compile *compile );\n\nGSList *compile_pattern_lhs( Compile *compile, Symbol *sym, ParseNode *node );\ngboolean compile_pattern_has_leaf( ParseNode *node );\ngboolean compile_pattern_has_args( Compile *compile );\n"
  },
  {
    "path": "src/conversion.c",
    "content": "/* Manage display conversion parameters.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* Our signals. \n */\nenum {\n\tSIG_AREA_CHANGED,\t/* Area of repaint image has changed */\n\tSIG_IMAGEINFO_CHANGED,\t/* The imageinfo we hold has been replaced */\n\tSIG_LAST\n};\n\nstatic guint conversion_signals[SIG_LAST] = { 0 };\n\nstatic ModelClass *parent_class = NULL;\n\n/* All active conversions.\n */\nstatic GSList *conversion_all = NULL;\n\nstatic void *\nconversion_imageinfo_changed( Conversion *conv )\n{\n#ifdef DEBUG\n\tg_print( \"conversion_imageinfo_changed: \" );\n\tiobject_print( IOBJECT( conv ) );\n#endif /*DEBUG*/\n\n\tg_signal_emit( G_OBJECT( conv ), \n\t\tconversion_signals[SIG_IMAGEINFO_CHANGED], 0 );\n\n\treturn( NULL );\n}\n\nstatic void\nconversion_area_changed( Conversion *conv, Rect *dirty )\n{\n\tg_signal_emit( G_OBJECT( conv ), \n\t\tconversion_signals[SIG_AREA_CHANGED], 0, dirty );\n}\n\nstatic void\nconversion_dispose( GObject *gobject )\n{\n\tConversion *conv;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_CONVERSION( gobject ) );\n\n\tconv = CONVERSION( gobject );\n\n#ifdef DEBUG\n\tg_print( \"conversion_dispose: \" );\n\tiobject_print( IOBJECT( conv ) );\n#endif /*DEBUG*/\n\n\tFREESID( conv->changed_sid, conv->ii );\n\tFREESID( conv->area_changed_sid, conv->ii );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\nconversion_finalize( GObject *gobject )\n{\n\tConversion *conv;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_CONVERSION( gobject ) );\n\n\tconv = CONVERSION( gobject );\n\n#ifdef DEBUG\n\tg_print( \"conversion_finalize: \" );\n\tiobject_print( IOBJECT( conv ) );\n#endif /*DEBUG*/\n\n\tconversion_all = g_slist_remove( conversion_all, conv );\n\n\tIM_FREEF( im_region_free, conv->ireg );\n\tIM_FREEF( im_region_free, conv->mreg );\n\tIM_FREEF( im_region_free, conv->reg );\n\n\tMANAGED_UNREF( conv->repaint_ii );\n\tMANAGED_UNREF( conv->display_ii );\n\tMANAGED_UNREF( conv->visual_ii );\n\tMANAGED_UNREF( conv->ii );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\n/* Make the visualisation image ... eg. we im_histplot histograms, and we\n * log scale fourier images.\n */\nstatic IMAGE *\nconversion_make_visualise( Conversion *conv, IMAGE *in )\n{\n\tIMAGE *out = im_open( \"conversion_make_visualise\", \"p\" );\n\tint tconv = !(conv && conv->enabled && !conv->type);\n\n        /* Histogram type ... plot the histogram. Keep this old hist display\n\t * method in case the goffice plotter is not available.\n         */\n        if( tconv && in->Type == IM_TYPE_HISTOGRAM && \n\t\t(in->Xsize == 1 || in->Ysize == 1) ) {\n                IMAGE *t[3];\n\n\t\tif( in->Coding == IM_CODING_LABQ ) {\n\t\t\tIMAGE *t = im_open_local( out, \"conv:1\", \"p\" );\n\n\t\t\tif( !t || im_LabQ2Lab( in, t ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\n\t\t\tin = t;\n\t\t}\n\n\t\tif( in->Coding == IM_CODING_RAD ) {\n\t\t\tIMAGE *t = im_open_local( out, \"conv:1\", \"p\" );\n\n\t\t\tif( !t || im_rad2float( in, t ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\n\t\t\tin = t;\n\t\t}\n\n                if( im_open_local_array( out, t, 3, \"conv-1\", \"p\" ) ||\n                        im_histnorm( in, t[0] ) ||\n                        im_histplot( t[0], t[1] ) ) {\n                        im_close( out );\n                        return( NULL );\n                }\n\n                /* Scale to a sensible size ... aim for a height of 256\n                 * elements.\n                 */\n                if( in->Xsize == 1 && t[1]->Xsize > 256 ) {\n                        if( im_subsample( t[1], t[2], t[1]->Xsize / 256, 1 ) ) {\n                                im_close( out );\n                                return( NULL );\n                        }\n                }\n                else if( in->Ysize == 1 && t[1]->Ysize > 256 ) {\n                        if( im_subsample( t[1], t[2], 1, t[1]->Ysize / 256 ) ) {\n                                im_close( out );\n                                return( NULL );\n                        }\n                }\n                else\n                        t[2] = t[1];\n  \n                in = t[2];\n        }\n\n\t/* IM_TYPE_FOURIER type ... pow/log scale, good for fourier \n\t * transforms.\n\t */\n\tif( tconv && in->Type == IM_TYPE_FOURIER ) {\n\t\tIMAGE *t[2];\n\n\t\tif( im_open_local_array( out, t, 2, \"conv-1\", \"p\" ) ||\n\t\t\tim_abs( in, t[0] ) || \n\t\t\tim_scaleps( t[0], t[1] ) ) {\n\t\t\tim_close( out );\n\t\t\treturn( NULL );\n\t\t}\n\n\t\tin = t[1];\n\t}\n\n\tif( im_copy( in, out ) ) {\n\t\tim_close( out );\n\t\treturn( NULL );\n\t}\n\n\treturn( out );\n}\n\n/* What we send from the notify callback to the main GUI thread.\n */\ntypedef struct _ConversionUpdate {\n\tConversion *conv;\n\n\tIMAGE *im;\t\t\n\tRect area;\n} ConversionUpdate;\n\nstatic gboolean\nconversion_render_idle_cb( gpointer data )\n{\n\tConversionUpdate *update = (ConversionUpdate *) data;\n\tConversion *conv = update->conv;\n\n\t/* Must be a valid conversion, must be for the image that that \n\t * conversion is still using for display.\n\t */\n\tif( g_slist_find( conversion_all, conv ) &&\n\t\timageinfo_get( FALSE, conv->display_ii ) == update->im ) {\n#ifdef DEBUG\n\t\tg_print( \"conversion_update_dispatch: left = %d, top = %d, \"\n\t\t\t\"width = %d, height = %d\\n\",\n\t\t\tupdate->area.left, update->area.top, \n\t\t\tupdate->area.width, update->area.height );\n#endif /*DEBUG*/\n\n\t\t/* We need to invalid the main image too, since those \n\t\t * regions will have black in from the failed first calc.\n\t\t *\n\t\t * im_render() can't do this invalidate for us, \n\t\t * it needs to be done from the main loop.\n\t\t *\n\t\t * commented out, vips_sink_screen() now does this for us. \n\t\t *\n\t\tim_invalidate( conv->mask ); im_invalidate( imageinfo_get( FALSE, conv->display_ii ) );\n\t\t */\n\n\t\tconversion_area_changed( conv, &update->area );\n\t}\n#ifdef DEBUG\n\telse\n\t\tg_print( \"conversion_render_idle_cb: skipping dead update\\n\" );\n#endif /*DEBUG*/\n\n\tg_free( update );\n\n\treturn( FALSE );\n}\n\n/* Here from the im_render() background thread.\n */\nstatic void\nconversion_render_notify_cb( IMAGE *im, Rect *area, void *client )\n{\n\tConversionUpdate *update = g_new( ConversionUpdate, 1 );\n\n\t/* Can't use CONVERSION() in this thread ... the GUI thread will check \n\t * this pointer for us when it reads from the queue.\n\t */\n\tupdate->conv = (Conversion *) client;\n\tupdate->im = im;\n\tupdate->area = *area;\n\n\tg_idle_add( conversion_render_idle_cb, update );\n}\n\n/* How many tiles should we ask for? A bit more than the number needed to \n * paint the screen.\n */\nstatic int\nconversion_get_default_tiles( Conversion *conv )\n{\n\tGdkScreen *screen = gdk_screen_get_default();\n\tint width = gdk_screen_get_width( screen ) / conv->tile_size;\n\tint height = gdk_screen_get_height( screen ) / conv->tile_size;\n\n\treturn( 2 * width * height );\n}\n\n/* Resize to screen coordinates and cache it.\n */\nstatic IMAGE *\nconversion_make_display( Conversion *conv, IMAGE *in, IMAGE **mask_out )\n{\n\tIMAGE *out = im_open( \"conversion_display:1\", \"p\" );\n\n\tif( !out )\n\t\treturn( NULL );\n\n\tif( conv->mag < 0 ) {\n\t\t/* Ordinary image ... use im_subsample().\n\n\t\t\tFIXME ... look for pyramid TIFFs here\n\n\t\t */\n\t\tIMAGE *t = im_open_local( out, \"conv:s\", \"p\" );\n\n\t\t/* Don't shrink by more than the image size (ie. to less than\n\t\t * 1 pixel).\n\t\t */\n\t\tint xshrink = IM_MIN( -conv->mag, in->Xsize );\n\t\tint yshrink = IM_MIN( -conv->mag, in->Ysize );\n\n\t\tif( DISPLAY_THUMBNAIL_HQ ) {\n\t\t\tif( !t || im_shrink( in, t, xshrink, yshrink ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif( !t || im_subsample( in, t, xshrink, yshrink ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\t\t}\n\n\t\tin = t;\n\t}\n\n\t/* Zoom, if necessary. \n\t */\n\tif( conv->mag > 1 ) {\n\t\tIMAGE *t = im_open_local( out, \"conv:z\", \"p\" );\n\n\t\tif( !t || im_zoom( in, t, conv->mag, conv->mag ) ) {\n\t\t\tim_close( out );\n\t\t\treturn( NULL );\n\t\t}\n\n\t\tin = t;\n\t}\n\n\t/* Cache it.\n\t */\n\tif( conv->synchronous ) {\n\t\tif( im_copy( in, out ) ) {\n\t\t\tim_close( out );\n\t\t\treturn( NULL );\n\t\t}\n\t}\n\telse {\n\t\tIMAGE *mask = im_open_local( out, \"conv:r\", \"p\" );\n\n\t\tif( im_render_priority( in, out, mask, \n\t\t\tconv->tile_size, conv->tile_size, \n\t\t\t\tconversion_get_default_tiles( conv ),\n\t\t\tconv->priority,\n\t\t\tconversion_render_notify_cb, conv ) ) {\n\t\t\tim_close( out );\n\t\t\treturn( NULL );\n\t\t}\n\n\t\tif( mask_out )\n\t\t\t*mask_out = mask;\n\t}\n\n\treturn( out );\n}\n\n/* Track during lintrauc.\n */\ntypedef struct {\n        double a, b;\n\tIMAGE *in, *out;\n} LintraInfo;\n\n/* Define what we do for each band element type. Non-complex input, uchar\n * output.\n */\n#define LOOP(IN) { \\\n        IN *p = (IN *) in; \\\n        PEL *q = (PEL *) out; \\\n        \\\n        for( x = 0; x < sz; x++ ) { \\\n\t\tdouble t; \\\n\t\t\\\n\t\tt = a * p[x] + b; \\\n\t\t\\\n\t\tif( t > 255 ) \\\n\t\t\tt = 255; \\\n\t\telse if( t < 0 ) \\\n\t\t\tt = 0; \\\n\t\t\\\n                q[x] = t; \\\n\t} \\\n}\n\n/* Complex input, uchar output.\n */\n#define LOOPCMPLX(IN) { \\\n        IN *p = (IN *) in; \\\n        PEL *q = (PEL *) out; \\\n        \\\n        for( x = 0; x < sz; x++ ) { \\\n\t\tdouble t; \\\n\t\t\\\n\t\tt = a * p[x << 1] + b; \\\n\t\t\\\n\t\tif( t > 255 ) \\\n\t\t\tt = 255; \\\n\t\telse if( t < 0 ) \\\n\t\t\tt = 0; \\\n\t\t\\\n                q[x] = t; \\\n\t} \\\n}\n\n/* Lintra a buffer, 1 set of scale/offset.\n */\nstatic int\nlintrauc_gen( PEL *in, PEL *out, int width, IMAGE *im, LintraInfo *inf )\n{       \n        double a = inf->a;\n        double b = inf->b;\n        int sz = width * im->Bands;\n        int x;\n\n        /* Lintra all input types.\n         */\n        switch( im->BandFmt ) {\n        case IM_BANDFMT_UCHAR:          \n\t\tLOOP( unsigned char ); break;\n        case IM_BANDFMT_CHAR:           \n\t\tLOOP( signed char ); break; \n        case IM_BANDFMT_USHORT:         \n\t\tLOOP( unsigned short ); break;\n        case IM_BANDFMT_SHORT:          \n\t\tLOOP( signed short ); break; \n        case IM_BANDFMT_UINT:           \n\t\tLOOP( unsigned int ); break;\n        case IM_BANDFMT_INT:            \n\t\tLOOP( signed int );  break;\n        case IM_BANDFMT_FLOAT:          \n\t\tLOOP( float ); break; \n        case IM_BANDFMT_DOUBLE:         \n\t\tLOOP( double ); break; \n        case IM_BANDFMT_COMPLEX:        \n\t\tLOOPCMPLX( float ); break; \n        case IM_BANDFMT_DPCOMPLEX:      \n\t\tLOOPCMPLX( double ); break;\n\n        default:\n                g_assert( 0 );\n        }\n\n        return( 0 );\n}\n\n/* im_lintra() that writes uchar (the VIPS one writes float/double).\n */\nstatic int\nim_lintrauc( double a, IMAGE *in, double b, IMAGE *out )\n{ \n        LintraInfo *inf;\n\n        if( in->Coding != IM_CODING_NONE ) {\n                im_error( \"im_lintrauc\", _( \"not uncoded\" ) );\n                return( -1 );\n        }\n\n        if( im_cp_desc( out, in ) )\n                return( -1 );\n\tout->Bbits = IM_BBITS_BYTE;\n\tout->BandFmt = IM_BANDFMT_UCHAR;\n\n        if( !(inf = IM_NEW( out, LintraInfo )) )\n                return( -1 );\n\tinf->a = a;\n\tinf->b = b;\n\tinf->in = in;\n\tinf->out = out;\n\n\tif( im_wrapone( in, out,\n\t\t(im_wrapone_fn) lintrauc_gen, in, inf ) )\n\t\treturn( -1 );\n\n        return( 0 );\n}\n\n/* Turn any IMAGE into a 1/3 band IM_BANDFMT_UCHAR ready for gdk_rgb_*().\n */\nstatic IMAGE *\nconversion_make_repaint( Conversion *conv, IMAGE *in )\n{\n\tIMAGE *out = im_open( \"conversion_apply:1\", \"p\" );\n\n\t/* 7 is sRGB.\n\n\t\tthis is all deprecated and unused now with vips-7.31 and later\n\t\ttag as unused to stop gcc complaints\n\n\t */\n\tstruct im_col_display *display __attribute__ ((unused)) = \n\t\tim_col_displays( 7 );\n\n\t/* Do we do colorimetric type conversions? Look for\n\t * interpret-type-toggle.\n\t */\n\tint tconv = !(conv && conv->enabled && !conv->type);\n\n\tif( !out )\n\t\treturn( NULL );\n\n\t/* Special case: if this is a IM_CODING_LABQ and the display control \n\t * bar is turned off, we can go straight to RGB for speed.\n\t */\n\tif( in->Coding == IM_CODING_LABQ && !(conv && conv->enabled) ) {\n\t\tIMAGE *t = im_open_local( out, \"conv:1\", \"p\" );\n\t\tstatic void *table = NULL;\n\n\t\t/* Make sure fast LabQ2disp tables are built.\n\t\t */\n\t\tif( !table ) \n\t\t\ttable = im_LabQ2disp_build_table( NULL, display );\n\n\t\tif( !t || im_LabQ2disp_table( in, t, table ) ) {\n\t\t\tim_close( out );\n\t\t\treturn( NULL );\n\t\t}\n\n\t\tin = t;\n\t}\n\n\t/* Get the bands right. If we have >3, drop down to 3. If we have 2,\n\t * drop down to 1.\n\t */\n\tif( in->Coding == IM_CODING_NONE ) {\n\t\tif( in->Bands == 2 ) {\n\t\t\tIMAGE *t = im_open_local( out, \"conv:1\", \"p\" );\n\n\t\t\tif( !t || im_extract_band( in, t, 0 ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\n\t\t\tin = t;\n\t\t}\n\t\telse if( in->Bands > 3 ) {\n\t\t\tIMAGE *t = im_open_local( out, \"conv:1\", \"p\" );\n\n\t\t\tif( !t ||\n\t\t\t\tim_extract_bands( in, t, 0, 3 ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\n\t\t\tin = t;\n\t\t}\n\t}\n\n\t/* Interpret the Type field for colorimetric images.\n\t */\n\tif( tconv &&\n\t\tin->Bands == 3 && in->BandFmt == IM_BANDFMT_SHORT && \n\t\tin->Type == IM_TYPE_LABS ) {\n\t\tIMAGE *t = im_open_local( out, \"conv:1\", \"p\" );\n\n\t\tif( !t || im_LabS2LabQ( in, t ) ) {\n\t\t\tim_close( out );\n\t\t\treturn( NULL );\n\t\t}\n\n\t\tin = t;\n\t}\n\n\tif( in->Coding == IM_CODING_LABQ ) {\n\t\tIMAGE *t = im_open_local( out, \"conv:1\", \"p\" );\n\n\t\tif( !t || im_LabQ2Lab( in, t ) ) {\n\t\t\tim_close( out );\n\t\t\treturn( NULL );\n\t\t}\n\n\t\tin = t;\n\t}\n\n\tif( in->Coding == IM_CODING_RAD ) {\n\t\tIMAGE *t = im_open_local( out, \"conv:1\", \"p\" );\n\n\t\tif( !t || im_rad2float( in, t ) ) {\n\t\t\tim_close( out );\n\t\t\treturn( NULL );\n\t\t}\n\n\t\tin = t;\n\t}\n\n\tif( in->Coding != IM_CODING_NONE ) {\n\t\tim_close( out );\n\t\treturn( NULL );\n\t}\n\n\t/* One of the colorimetric types?\n\t */\n\tif( tconv && in->Bands == 3 && \n\t\t(in->Type == IM_TYPE_LCH ||\n\t\tin->Type == IM_TYPE_YXY ||\n\t\tin->Type == IM_TYPE_UCS ||\n#if VIPS_MAJOR_VERSION > 7 || VIPS_MINOR_VERSION > 32\n\t\t/* scRGB colourspace added in 7.32.\n\t\t */\n\t\tin->Type == VIPS_INTERPRETATION_scRGB ||\n#endif\n\t\tin->Type == IM_TYPE_LAB ||\n\t\tin->Type == IM_TYPE_XYZ) ) {\n\t\tIMAGE *t[2];\n\n\t\t/* We need to scale/offset before we go to 8 bit to work well \n\t\t * with HDR.\n\t\t */\n\t\tif( conv && conv->enabled && \n\t\t\t(conv->scale != 1.0 || conv->offset != 0.0) ) {\n\t\t\tIMAGE *t = im_open_local( out, \"conv:1\", \"p\" );\n\n\t\t\tif( !t || im_lintra( conv->scale, in, \n\t\t\t\tconv->offset, t ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\n\t\t\tin = t;\n\t\t}\n\n\t\tif( in->Type == IM_TYPE_LCH ) {\n\t\t\tif( im_open_local_array( out, t, 2, \"conv-1\", \"p\" ) ||\n\t\t\t\tim_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) ||\n\t\t\t\tim_LCh2Lab( t[0], t[1] ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\n\t\t\tin = t[1];\n\t\t}\n\n#if VIPS_MAJOR_VERSION > 7 || VIPS_MINOR_VERSION > 32\n\t\tif( in->Type == VIPS_INTERPRETATION_scRGB ) {\n\t\t\tVipsImage *x;\n\n\t\t\tif( vips_scRGB2sRGB( in, &x, NULL ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\t\t\tvips_object_local( out, x ); \n\n\t\t\tin = x;\n\t\t}\n#endif\n\n\t\tif( in->Type == IM_TYPE_YXY ) {\n\t\t\tif( im_open_local_array( out, t, 2, \"conv-1\", \"p\" ) ||\n\t\t\t\tim_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) ||\n\t\t\t\tim_Yxy2XYZ( t[0], t[1] ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\n\t\t\tin = t[1];\n\t\t}\n\n\t\tif( in->Type == IM_TYPE_UCS ) {\n\t\t\tif( im_open_local_array( out, t, 2, \"conv-1\", \"p\" ) ||\n\t\t\t\tim_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) ||\n\t\t\t\tim_UCS2XYZ( t[0], t[1] ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\n\t\t\tin = t[1];\n\t\t}\n\n\t\tif( in->Type == IM_TYPE_LAB ) {\n\t\t\tif( im_open_local_array( out, t, 2, \"conv-1\", \"p\" ) ||\n\t\t\t\tim_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) ||\n\t\t\t\tim_Lab2XYZ( t[0], t[1] ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\n\t\t\tin = t[1];\n\t\t}\n\n\t\tif( in->Type == IM_TYPE_XYZ ) {\n\t\t\tif( im_open_local_array( out, t, 2, \"conv-1\", \"p\" ) ||\n\t\t\t\tim_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) ||\n\t\t\t\tim_XYZ2disp( t[0], t[1], display ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\n\t\t\tin = t[1];\n\t\t}\n\t}\n\telse {\n\t\t/* Not colorimetric. We can use a special ->uchar lintra for\n\t\t * scale/offset. Don't scale/offset fourier or histogram \n\t\t * images, they are presented above.\n\t\t */\n\t\tif( conv && conv->enabled &&\n\t\t\t(!tconv || in->Type != IM_TYPE_FOURIER) &&\n\t\t\t(!tconv || in->Type != IM_TYPE_HISTOGRAM) &&\n\t\t\t(conv->scale != 1.0 || conv->offset != 0.0) ) {\n\t\t\tIMAGE *t = im_open_local( out, \"conv:1\", \"p\" );\n\n\t\t\tif( !t || \n\t\t\t\tim_lintrauc( conv->scale, in, \n\t\t\t\t\tconv->offset, t ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\n\t\t\tin = t;\n\t\t}\n\t}\n\n\tif( tconv && \n\t\t(in->Type == IM_TYPE_RGB16 || in->Type == IM_TYPE_GREY16) ) {\n\t\tIMAGE *t[1];\n\n\t\tif( im_open_local_array( out, t, 1, \"conv-1\", \"p\" ) ) {\n\t\t\tim_close( out );\n\t\t\treturn( NULL );\n\t\t}\n\n\t\t/* im_msb() only works for the int formats.\n\t\t */\n\t\tif( vips_bandfmt_isint( in->BandFmt ) ) {\n\t\t\tif( im_msb( in, t[0] ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif( im_lintrauc( 1 / 256.0, in, 0.0, t[0] ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\t\t}\n\n\t\tin = t[0];\n\t}\n\n\t/* Clip to uchar if not there already.\n\t */\n\tif( in->BandFmt != IM_BANDFMT_UCHAR ) {\n\t\tIMAGE *t = im_open_local( out, \"conv:1\", \"p\" );\n\n\t\tif( !t || im_clip2fmt( in, t, IM_BANDFMT_UCHAR ) ) {\n\t\t\tim_close( out );\n\t\t\treturn( NULL );\n\t\t}\n\n\t\tin = t;\n\t}\n\n\t/* Falsecolour. Just use the green channel if we're RGB.\n\t */\n\tif( conv && conv->enabled && conv->falsecolour ) {\n\t\tIMAGE *t1 = im_open_local( out, \"conv:1\", \"p\" );\n\n\t\tif( !t1 ) {\n\t\t\tim_close( out );\n\t\t\treturn( NULL );\n\t\t}\n\n\t\tif( in->Bands == 3 ) {\n\t\t\tIMAGE *t2 = im_open_local( out, \"conv:1\", \"p\" );\n\n\t\t\tif( im_extract_band( in, t2, 1 ) ) {\n\t\t\t\tim_close( out );\n\t\t\t\treturn( NULL );\n\t\t\t}\n\n\t\t\tin = t2;\n\t\t}\n\n\t\tif( im_falsecolour( in, t1 ) ) {\n\t\t\tim_close( out );\n\t\t\treturn( NULL );\n\t\t}\n\n\t\tin = t1;\n\t}\n\n\tif( im_copy( in, out ) ) {\n\t\tim_close( out );\n\t\treturn( NULL );\n\t}\n\n\treturn( out );\n}\n\n/* Controls in the display conversion bar, or the display image have changed.\n * Remake the repaint image.\n */\nstatic void\nconversion_rebuild_repaint( Conversion *conv )\n{\n\tIMAGE *display_im;\n\tIMAGE *new_repaint_im;\n\tImageinfo *new_repaint_ii;\n\tREGION *new_ireg;\n\n#ifdef DEBUG\n\tg_print( \"conversion_remake_repaint: %p\\n\", conv );\n#endif /*DEBUG*/\n\n\tif( conv->display_ii )\n\t\tdisplay_im = imageinfo_get( FALSE, conv->display_ii );\n\telse\n\t\tdisplay_im = NULL;\n\n\t/* Keep gcc quiet about annoying possible-used-before-set warnings.\n\t */\n\tnew_repaint_ii = NULL;\n\tnew_ireg = NULL;\n\n\t/* Make the new stuff first.\n\t */\n\tif( display_im ) {\n\t\tif( !(new_repaint_im = \n\t\t\tconversion_make_repaint( conv, display_im )) ) \n\t\t\treturn;\n\t\tif( !(new_repaint_ii = imageinfo_new( main_imageinfogroup, \n\t\t\tNULL, new_repaint_im, NULL )) ) {\n\t\t\tim_close( new_repaint_im );\n\t\t\treturn;\n\t\t}\n\t\tmanaged_sub_add( MANAGED( new_repaint_ii ), \n\t\t\tMANAGED( conv->display_ii ) );\n\n\t\tif( !(new_ireg = im_region_create( new_repaint_im )) ) \n\t\t\treturn;\n\t}\n\n\tIM_FREEF( im_region_free, conv->ireg );\n\tMANAGED_UNREF( conv->repaint_ii );\n\n\tif( display_im ) {\n\t\tconv->repaint_ii = new_repaint_ii;\n\t\tMANAGED_REF( conv->repaint_ii );\n\t\tconv->ireg = new_ireg;\n\t}\t\n}\n\n/* The magnification or the visual image have changed ... remake the\n * display image.\n */\nstatic void\nconversion_rebuild_display( Conversion *conv )\n{\n\tIMAGE *visual_im;\n\tIMAGE *new_display_im;\n\tImageinfo *new_display_ii;\n\tIMAGE *mask;\n\tREGION *new_mreg;\n\n#ifdef DEBUG\n\tg_print( \"conversion_remake_display: %p\\n\", conv );\n#endif /*DEBUG*/\n\n\tif( conv->visual_ii )\n\t\tvisual_im = imageinfo_get( FALSE, conv->visual_ii );\n\telse\n\t\tvisual_im = NULL;\n\n\t/* Keep gcc quiet about annoying possible-used-before-set warnings.\n\t */\n\tnew_display_ii = NULL;\n\tnew_display_im = NULL;\n\tnew_mreg = NULL;\n\tmask = NULL;\n\n\t/* Make the new stuff first.\n\t */\n\tif( visual_im ) {\n\t\tif( !(new_display_im = \n\t\t\tconversion_make_display( conv, visual_im, &mask )) ) \n\t\t\treturn;\n\t\tif( !(new_display_ii = imageinfo_new( main_imageinfogroup, \n\t\t\tNULL, new_display_im, NULL )) ) {\n\t\t\tim_close( new_display_im );\n\t\t\treturn;\n\t\t}\n\t\tmanaged_sub_add( MANAGED( new_display_ii ), \n\t\t\tMANAGED( conv->visual_ii ) );\n\t\tif( mask && \n\t\t\t!(new_mreg = im_region_create( mask )) ) \n\t\t\treturn;\n\t}\n\n\tIM_FREEF( im_region_free, conv->mreg );\n\tMANAGED_UNREF( conv->display_ii );\n\n\tif( visual_im ) {\n\t\tconv->display_ii = new_display_ii;\n\t\tconv->mask = mask;\n\t\tconv->mreg = new_mreg;\n\t\tMANAGED_REF( conv->display_ii );\n\n\t\tconv->canvas.width = new_display_im->Xsize;\n\t\tconv->canvas.height = new_display_im->Ysize;\n\t}\t\n\n\t/* Certainly need a new repaint image.\n\t */\n\tconversion_rebuild_repaint( conv );\n}\n\n/* The underlying ii has changed. Remake the visualisation image.\n */\nstatic void\nconversion_rebuild_visual( Conversion *conv )\n{\n\tIMAGE *im = imageinfo_get( FALSE, conv->ii );\n\tIMAGE *new_visual_im;\n\tImageinfo *new_visual_ii;\n\tREGION *new_reg;\n\n#ifdef DEBUG\n\tg_print( \"conversion_rebuild_visual: %p\\n\", conv );\n#endif /*DEBUG*/\n\n\t/* Keep gcc quiet about annoying possible-used-before-set warnings.\n\t */\n\tnew_visual_im = NULL;\n\tnew_visual_ii = NULL;\n\tnew_reg = NULL;\n\n\t/* Make new visualization image.\n\t */\n\tif( im ) {\n\t\tif( !(new_visual_im = conversion_make_visualise( conv, im )) )\n\t\t\treturn;\n\t\tif( !(new_visual_ii = imageinfo_new( main_imageinfogroup, \n\t\t\tNULL, new_visual_im, NULL )) ) {\n\t\t\tim_close( new_visual_im );\n\t\t\treturn;\n\t\t}\n\t\tmanaged_sub_add( MANAGED( new_visual_ii ), \n\t\t\tMANAGED( conv->ii ) );\n\n\t\tif( !(new_reg = im_region_create( im )) ) \n\t\t\treturn;\n\t}\n\n\t/* Junk old stuff.\n\t */\n\tIM_FREEF( im_region_free, conv->reg );\n\tMANAGED_UNREF( conv->visual_ii );\n\n\t/* Install new stuff.\n\t */\n\tif( im ) {\n\t\tconv->visual_ii = new_visual_ii;\n\t\tMANAGED_REF( conv->visual_ii );\n\t\tconv->image.width = new_visual_im->Xsize;\n\t\tconv->image.height = new_visual_im->Ysize;\n\t\tconv->reg = new_reg;\n\t}\n\n\t/* Certainly need a new display.\n\t */\n\tconversion_rebuild_display( conv );\n}\n\n/* Something has changed ... check it out.\n */\nstatic void\nconversion_changed( iObject *iobject )\n{\n\tConversion *conv = CONVERSION( iobject );\n\n\tgboolean rebuild_display = FALSE;\n\tgboolean rebuild_repaint = FALSE;\n\n#ifdef DEBUG\n\tg_print( \"conversion_changed: %p\\n\", conv );\n#endif /*DEBUG*/\n\n\t/* Need to remake the display image if mag has changed.\n\t */\n\tif( conv->mag != conv->display_mag ) {\n\t\trebuild_display = TRUE;\n\t\tconv->display_mag = conv->mag;\n\t}\n\n\t/* Need to rebuild repaint if display control bar has changed.\n\t */\n\tif( conv->changed ) {\n\t\tconv->changed = FALSE;\n\t\trebuild_repaint = TRUE;\n\t}\n\n\tif( rebuild_display )\n\t\tconversion_rebuild_display( conv );\n\telse if( rebuild_repaint )\n\t\tconversion_rebuild_repaint( conv );\n\n\tIOBJECT_CLASS( parent_class )->changed( iobject );\n}\n\nstatic void\nconversion_class_init( ConversionClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = conversion_dispose;\n\tgobject_class->finalize = conversion_finalize;\n\n\tiobject_class->changed = conversion_changed;\n\n\t/* Create signals.\n\t */\n\tconversion_signals[SIG_AREA_CHANGED] = g_signal_new( \"area_changed\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ConversionClass, area_changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__POINTER,\n\t\tG_TYPE_NONE, 1,\n\t\tG_TYPE_POINTER );\n\tconversion_signals[SIG_IMAGEINFO_CHANGED] = g_signal_new( \n\t\t\"imageinfo_changed\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ConversionClass, imageinfo_changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n}\n\nstatic void\nconversion_init( Conversion *conv )\n{\n\tstatic const Rect emptyrect = { 0, 0, 0, 0 };\n\n#ifdef DEBUG\n\tg_print( \"conversion_init: \" );\n\tiobject_print( IOBJECT( conv ) );\n#endif /*DEBUG*/\n\n\tconv->ii = NULL;\n\tconv->changed_sid = 0;\n\tconv->area_changed_sid = 0;\n\tconv->reg = NULL;\n\tconv->synchronous = FALSE;\n\tconv->priority = 0;\n\tconv->visual_ii = NULL;\n\tconv->display_ii = NULL;\n\tconv->display_mag = 99999999;\n\tconv->repaint_ii = NULL;\n\tconv->ireg = NULL;\n\tconv->mreg = NULL;\n\n\t/* Default tile size ... OK for image display, too big for\n\t * thumbnails.\n\t */\n\tconv->tile_size = 64;\n\n\tconv->underlay = emptyrect;\n\tconv->image = emptyrect;\n\tconv->canvas = emptyrect;\n\tconv->visible = emptyrect;\n\tconv->mag = 1;\n\n\tconv->changed = FALSE;\n\tconv->enabled = FALSE;\n\tconv->scale = 1.0;\n\tconv->offset = 0.0;\n\tconv->falsecolour = FALSE;\n\tconv->type = TRUE;\n\n\tconversion_all = g_slist_prepend( conversion_all, conv );\n}\n\nGType\nconversion_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ConversionClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) conversion_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Conversion ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) conversion_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_MODEL, \n\t\t\t\"Conversion\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\nconversion_link( Conversion *conv, Imageinfo *ii )\n{\n\tiobject_set( IOBJECT( conv ), \"display_conversion\", NULL );\n\tconversion_set_image( conv, ii );\n}\n\nConversion *\nconversion_new( Imageinfo *ii )\n{\n\tConversion *conv;\n\n\tconv = CONVERSION( g_object_new( TYPE_CONVERSION, NULL ) );\n\tconversion_link( conv, ii );\n\n\treturn( conv );\n}\n\n/* Imageinfo has changed signal. The ii is the same, but the image it\n * represents may have changed from \"p\" to \"r\" or whatever. Assume size/etc.\n * stay the same.\n */\nstatic void\nconversion_ii_changed_cb( Imageinfo *ii, Conversion *conv )\n{\n\tconversion_rebuild_visual( conv );\n\tiobject_changed( IOBJECT( conv ) );\n}\n\n/* Something like a paint action on the ii.\n */\nstatic void\nconversion_ii_area_changed_cb( Imageinfo *imageinfo, \n\tRect *dirty, Conversion *conv )\n{\n\tRect repaint;\n\n\tconversion_im_to_disp_rect( conv, dirty, &repaint );\n\tconversion_area_changed( conv, &repaint );\n}\n\n/* Install a new image. \n */\nvoid \nconversion_set_image( Conversion *conv, Imageinfo *ii )\n{\n\t/* Pointer compare is safe, since we hold a ref to conv->ii and it\n\t * can't have been freed. So we can't have a new ii at the same\n\t * address as the old ii.\n\t */\n\tif( conv->ii != ii ) {\n\t\tIMAGE *im;\n\n\t\tif( ii )\n\t\t\tim = imageinfo_get( FALSE, ii );\n\t\telse\n\t\t\tim = NULL;\n\n\t\t/* Junk old stuff.\n\t\t */\n\t\tFREESID( conv->changed_sid, conv->ii );\n\t\tFREESID( conv->area_changed_sid, conv->ii );\n\t\tMANAGED_UNREF( conv->ii );\n\t\tconv->image.width = -1;\n\t\tconv->image.height = -1;\n\n\t\t/* Install new stuff.\n\t\t */\n\t\tif( ii ) {\n\t\t\tconv->ii = ii;\n\t\t\tMANAGED_REF( conv->ii );\n\t\t\tconv->changed_sid = g_signal_connect( \n\t\t\t\tG_OBJECT( ii ), \"changed\",\n\t\t\t\tG_CALLBACK( conversion_ii_changed_cb ), \n\t\t\t\tconv );\n\t\t\tconv->area_changed_sid = g_signal_connect( \n\t\t\t\tG_OBJECT( ii ), \"area_changed\", \n\t\t\t\tG_CALLBACK( conversion_ii_area_changed_cb ), \n\t\t\t\tconv );\n\t\t}\n\t\tif( im ) {\n\t\t\tconv->underlay.width = im->Xsize;\n\t\t\tconv->underlay.height = im->Ysize;\n\t\t}\n\n\t\t/* Make new visualization image.\n\t\t */\n\t\tconversion_rebuild_visual( conv );\n\n\t\t/* Tell everyone about our new ii.\n\t\t */\n\t\tconversion_imageinfo_changed( conv );\n\t}\n\n\tiobject_changed( IOBJECT( conv ) );\n}\n\ndouble\nconversion_dmag( int mag )\n{\n\tg_assert( mag != 0 );\n\n\tif( mag > 0 )\n\t\treturn( mag );\n\telse\n\t\treturn( 1.0 / (-mag) );\n}\n\n/* Zoom in and zoom out scale factors ... a little tricky with our funny -ve\n * representation for subsample.\n */\nint \nconversion_double( int mag )\n{\n\tg_assert( mag != -1 );\n\n\tif( mag == -3 )\n\t\treturn( -2 );\n\telse if( mag == -2 )\n\t\treturn( 1 );\n\telse if( mag > 0 )\n\t\treturn( mag * 2 );\n\telse\n\t\treturn( mag / 2 );\n}\n\nint \nconversion_halve( int mag )\n{\n\tg_assert( mag != -1 );\n\n\tif( mag == 1 )\n\t\treturn( -2 );\n\telse if( mag > 1 )\n\t\treturn( mag / 2 );\n\telse\n\t\treturn( mag * 2 );\n}\n\n/* Convert display to image coordinates and back.\n */\nvoid \nconversion_disp_to_im( Conversion *conv, int dx, int dy, int *ix, int *iy )\n{\n\tdouble fmag = conversion_dmag( conv->mag );\n\n\t*ix = (int) (dx / fmag);\n\t*iy = (int) (dy / fmag);\n}\n\nvoid \nconversion_im_to_disp( Conversion *conv, int ix, int iy, int *dx, int *dy )\n{\n\tdouble fmag = conversion_dmag( conv->mag );\n\n\t*dx = (int) (ix * fmag);\n\t*dy = (int) (iy * fmag);\n}\n\n/* Same for rects.\n */\nvoid\nconversion_disp_to_im_rect( Conversion *conv, Rect *dr, Rect *ir )\n{\n\tdouble fmag = conversion_dmag( conv->mag );\n\n\tint brx, bry;\n\tRect out;\n\n\tout.left = floor( dr->left / fmag );\n\tout.top = floor( dr->top / fmag );\n\tbrx = ceil( IM_RECT_RIGHT( dr ) / fmag );\n\tbry = ceil( IM_RECT_BOTTOM( dr ) / fmag );\n\tout.width = brx - out.left;\n\tout.height = bry - out.top;\n\n\t*ir = out;\n}\n\nvoid\nconversion_im_to_disp_rect( Conversion *conv, Rect *ir, Rect *dr )\n{\n\tdouble fmag = conversion_dmag( conv->mag );\n\n\tint brx, bry;\n\tRect out;\n\n\tout.left = floor( ir->left * fmag );\n\tout.top = floor( ir->top * fmag );\n\tbrx = ceil( IM_RECT_RIGHT( ir ) * fmag );\n\tbry = ceil( IM_RECT_BOTTOM( ir ) * fmag );\n\tout.width = brx - out.left;\n\tout.height = bry - out.top;\n\n\t*dr = out;\n}\n\nvoid\nconversion_set_mag( Conversion *conv, int mag )\n{\n\tint x, y;\n\n\t/* Mag 0 means scale image to fit window. Use visible hint in\n\t * conversion to pick the mag.\n\t */\n\tif( mag == 0 ) {\n\t\tfloat xfac;\n\t\tfloat yfac;\n\t\tfloat fac;\n\n\t\t/* Need to have image and visible set.\n\t\t */\n\t\tif( conv->visible.width <= 0 || \n\t\t\tconv->image.width <= 0 || !conv->ii || !conv->ii->im )\n\t\t\treturn;\n\n\t\txfac = (float) conv->visible.width / conv->image.width;\n\t\tyfac = (float) conv->visible.height / conv->image.height;\n\t\tfac = IM_MIN( xfac, yfac );\n\n\t\tif( fac >= 1 )\n\t\t\tmag = (int) fac;\n\t\telse\n\t\t\t/* 0.999 means we don't round up on an exact fit.\n\n\t\t\t \tFIXME ... yuk\n\n\t\t\t */\n\t\t\tmag = -((int) (0.99999999 + 1.0/fac));\n\n#ifdef DEBUG\n\t\tg_print( \"conversion_set_mag: shrink to fit:\\n\" );\n\t\tg_print( \" visible %dx%d, image %dx%d\\n\",\n\t\t\tconv->visible.width, conv->visible.height,\n\t\t\tconv->image.width, conv->image.height );\n\t\tg_print( \" picked mag of %d\\n\", mag );\n#endif /*DEBUG*/\n\t}\n\n\t/* Check for this-mag-will-cause-integer-overflow. Should flag an \n\t * error, but we just bail out instead.\n\t */\n\tif( mag > 0 &&\n\t\t((double) conv->image.width * mag > (double) INT_MAX / 2 ||\n\t\t(double) conv->image.height * mag > (double) INT_MAX / 2) ) \n\t\treturn;\n\n\t/* Will this mag result in width/height of <1? If it will, pick a\n\t * mag that most nearly gives us width/height 1.\n\t */\n\tconv->mag = mag;\n\tconversion_im_to_disp( conv, \n\t\tconv->image.width, conv->image.height, &x, &y );\n\tif( x <= 0  || y <= 0 ) {\n\t\tconv->mag = IM_MAX( -conv->image.width, -conv->image.height );\n\t\tif( conv->mag == -1 )\n\t\t\tconv->mag = 1;\n\t}\n\n\tif( conv->mag != conv->display_mag )\n\t\tiobject_changed( IOBJECT( conv ) );\n}\n\nvoid\nconversion_set_synchronous( Conversion *conv, gboolean synchronous )\n{\n\tif( conv->synchronous != synchronous ) {\n#ifdef DEBUG\n\t\tprintf( \"conversion_set_synchronous: %d\", synchronous );\n\t\tiobject_print( IOBJECT( conv ) );\n#endif /*DEBUG*/\n\n\t\tconv->synchronous = synchronous;\n\t\tif( conv->ii )\n\t\t\tiobject_changed( IOBJECT( conv->ii ) );\n\t}\n}\n\nvoid\nconversion_set_params( Conversion *conv, gboolean enabled,\n\tdouble scale, double offset, gboolean falsecolour, gboolean type )\n{\n\tgboolean changed = FALSE;\n\n\tif( conv->enabled != enabled )\n\t\tchanged = TRUE;\n\tif( enabled )\n\t\tif( conv->scale != scale ||\n\t\t\tconv->offset != offset ||\n\t\t\tconv->falsecolour != falsecolour ||\n\t\t\tconv->type != type )\n\t\tchanged = TRUE;\n\n\tif( changed ) {\n\t\tconv->enabled = enabled;\n\t\tconv->scale = scale;\n\t\tconv->offset = offset;\n\t\tconv->falsecolour = falsecolour;\n\t\tconv->type = type;\n\t\tconv->changed = TRUE;\n\t\tiobject_changed( IOBJECT( conv ) );\n\t}\n}\n"
  },
  {
    "path": "src/conversion.h",
    "content": "/* Manage display conversion parameters.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_CONVERSION (conversion_get_type())\n#define CONVERSION( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_CONVERSION, Conversion ))\n#define CONVERSION_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_CONVERSION, ConversionClass))\n#define IS_CONVERSION( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_CONVERSION ))\n#define IS_CONVERSION_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_CONVERSION ))\n#define CONVERSION_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_CONVERSION, ConversionClass ))\n\nstruct _Conversion {\n\tModel parent_class;\n\n\t/* Image.\n\t */\n\tImageinfo *ii;\t\t/* Underlying image */\n\tguint changed_sid;\t/* Watch ii with these two */\n\tguint area_changed_sid;\t\n\tREGION *reg;\t\t/* Region for input from underlying image */\n\tgboolean synchronous;\t/* TRUE to disable BG stuff */\n\tint priority;\t\t/* render priority */\n\n\tImageinfo *visual_ii;\t/* Visualisation image ... eg. histplot */\n\tImageinfo *display_ii;\t/* Sized and cached */\n\tint display_mag;\t/* What mag the display_ii is built for */\n\tIMAGE *mask;\t\t/* Read display mask from here */\n\tImageinfo *repaint_ii;\t/* Colour converted for screen */\n\tREGION *ireg;\t\t/* Region for input from repaint image */\n\tREGION *mreg;\t\t/* Region for input from repaint mask */\n\tint tile_size;\t\t/* Set smaller for thumbnails */\n\n\t/* Basic geometry.\n\t */\n\tRect underlay;\t\t/* Size of underlying image (at 0,0) */\n\tRect image;\t\t/* Size of visualisation image (at 0,0) */\n\tRect canvas;\t\t/* Size of image we display (always at 0,0) */\n\tRect visible;\t\t/* hint ... visible region of display image */\n\tint mag;\t\t/* -ve for shrink, +ve for expand */\n\n\t/* Visualisation controls. If enabled is set, we built the pipeline\n\t * using these params.\n\t */\n\tgboolean enabled;\n\tgboolean changed;\t/* Trigger a rebuild with these */\n\tdouble scale;\t\t/* Contrast/brightness */\n\tdouble offset;\n\tgboolean falsecolour;\t/* False colour display on */\n\tgboolean type;\t\t/* Interpret type field */\n};\n\ntypedef struct _ConversionClass {\n\tModelClass parent_class;\n\n\t/* My methods.\n\n\t\tarea_changed\twe forward the \"area\" changed signal off the\n\t\t\t\tii we are holding ... in repaint coordinates\n\n\t */\n\tvoid (*area_changed)( Conversion *, Rect * );\n\n\t/* The imageinfo has been swapped for a new one.\n\t */\n\tvoid (*imageinfo_changed)( Conversion * );\n} ConversionClass;\n\nGType conversion_get_type( void );\nConversion *conversion_new( Imageinfo *ii );\n\nvoid conversion_set_image( Conversion *conv, Imageinfo *ii );\ngboolean conversion_refresh_text( Conversion *conv );\n\ndouble conversion_dmag( int mag );\nint conversion_double( int mag );\nint conversion_halve( int mag );\n\nvoid conversion_disp_to_im( Conversion *conv, \n\tint dx, int dy, int *ix, int *iy );\nvoid conversion_im_to_disp( Conversion *conv, \n\tint ix, int iy, int *dx, int *dy );\nvoid conversion_disp_to_im_rect( Conversion *conv, Rect *dr, Rect *ir );\nvoid conversion_im_to_disp_rect( Conversion *conv, Rect *ir, Rect *dr );\n\nvoid conversion_set_mag( Conversion *conv, int mag );\nvoid conversion_set_synchronous( Conversion *conv, gboolean synchronous );\nvoid conversion_set_params( Conversion *conv, gboolean enabled,\n\tdouble scale, double offset, gboolean falsecolour, gboolean type );\n"
  },
  {
    "path": "src/conversionview.c",
    "content": "/* display an image in a window ... watching an Image model.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GtkEventBoxClass *parent_class = NULL;\n\n/* Find max and min of visible area of image.\n */\nstatic gboolean\nconversionview_findmaxmin( Imagemodel *imagemodel, double *min, double *max )\n{\n\tConversion *conv = imagemodel->conv;\n\tRect a, b;\n\n\tconversion_disp_to_im_rect( conv, &imagemodel->visible, &a );\n\tim_rect_intersectrect( &a, &conv->image, &b );\n\tif( findmaxmin( imageinfo_get( FALSE, conv->ii ), \n\t\tb.left, b.top, b.width, b.height, min, max ) ) {\n\t\terror_top( _( \"Unable to find image range.\" ) );\n\t\terror_sub( _( \"Find image range failed.\" ) );\n\t\terror_vips();\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic void\nconversionview_scale_cb( GtkWidget *wid, Conversionview *cv )\n{\n\tImagemodel *imagemodel = cv->imagemodel;\n\tdouble min, max;\n\n\tprogress_begin();\n\tif( !conversionview_findmaxmin( imagemodel, &min, &max ) ) {\n\t\tprogress_end();\n\t\tiwindow_alert( wid, GTK_MESSAGE_ERROR );\n\t\treturn;\n\t}\n\tprogress_end();\n\n        if( max - min < 1e-20 ) {\n                error_top( _( \"Unable to scale image.\" ) );\n                error_sub( _( \"Maximum and minimum pixel values are equal.\" ) );\n\t\tiwindow_alert( wid, GTK_MESSAGE_ERROR );\n                return;\n        }\n\n\timagemodel->scale = 255.0 / (max - min);\n\timagemodel->offset = -(min * imagemodel->scale);\n\tiobject_changed( IOBJECT( imagemodel ) );\n}\n\nstatic void\nconversionview_falsecolour_cb( GtkWidget *wid, Conversionview *cv )\n{\n\tImagemodel *imagemodel = cv->imagemodel;\n\tGtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM( wid );\n\n\timagemodel->falsecolour = item->active;\n\tiobject_changed( IOBJECT( imagemodel ) );\n}\n\nstatic void\nconversionview_interpret_cb( GtkWidget *wid, Conversionview *cv )\n{\n\tImagemodel *imagemodel = cv->imagemodel;\n\tGtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM( wid );\n\n\timagemodel->type = item->active;\n\tiobject_changed( IOBJECT( imagemodel ) );\n}\n\nstatic void\nconversionview_reset_cb( GtkWidget *wid, Conversionview *cv )\n{\n\tImagemodel *imagemodel = cv->imagemodel;\n\n\tif( imagemodel->iimage ) {\n\t\tRow *row = HEAPMODEL( imagemodel->iimage )->row;\n\n\t\timagemodel->scale = row->ws->scale;\n\t\timagemodel->offset = row->ws->offset;\n\t}\n\telse {\n\t\timagemodel->scale = 1.0;\n\t\timagemodel->offset = 0.0;\n\t}\n\n\timagemodel->falsecolour = FALSE;\n\timagemodel->type = TRUE;\n\tiobject_changed( IOBJECT( imagemodel ) );\n}\n\nstatic void\nconversionview_set_default_cb( GtkWidget *wid, Conversionview *cv )\n{\n\tImagemodel *imagemodel = cv->imagemodel;\n\n\tif( imagemodel->iimage ) {\n\t\tRow *row = HEAPMODEL( imagemodel->iimage )->row;\n\n\t\trow->ws->scale = imagemodel->scale;\n\t\trow->ws->offset = imagemodel->offset;\n\t}\n}\n\nstatic void\nconversionview_hide_cb( GtkWidget *wid, Conversionview *cv )\n{\n\tImagemodel *imagemodel = cv->imagemodel;\n\n\timagemodel_set_convert( imagemodel, FALSE );\n}\n\nstatic void\nconversionview_class_init( ConversionviewClass *class )\n{\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\n}\n\n/* Value changed in scale adjustment.\n */\nstatic void\nconversionview_scale_change_cb( Tslider *tslider, Conversionview *cv )\n{\n\tImagemodel *imagemodel = cv->imagemodel;\n\n\tif( imagemodel->scale != tslider->value ) {\n\t\timagemodel->scale = tslider->value; \n\t\tiobject_changed( IOBJECT( imagemodel ) );\n\t}\n}\n\n/* Value changed in offset adjustment.\n */\nstatic void\nconversionview_offset_change_cb( Tslider *tslider, Conversionview *cv )\n{\n\tImagemodel *imagemodel = cv->imagemodel;\n\n\tif( imagemodel->offset != tslider->value ) {\n\t\timagemodel->offset = tslider->value; \n\t\tiobject_changed( IOBJECT( imagemodel ) );\n\t}\n}\n\nstatic void\nconversionview_init( Conversionview *cv )\n{\n\tPopupbutton *popupbutton;\n\tGtkWidget *hb;\n\tGtkWidget *sep;\n\n\tGtkWidget *pane;\n\n\tcv->imagemodel = NULL;\n\n        gtk_frame_set_shadow_type( GTK_FRAME( cv ), GTK_SHADOW_OUT );\n\n\thb = gtk_hbox_new( FALSE, 2 );\n        gtk_container_set_border_width( GTK_CONTAINER( hb ), 2 );\n        gtk_container_add( GTK_CONTAINER( cv ), hb );\n\n        /* Build menu. One for each window, as we need to track falsecolour\n\t * etc. toggles. Could just have one, and modify pre-popup, but this\n\t * is easier.\n         */\n\tpane = menu_build( _( \"Convert menu\" ) );\n\tmenu_add_but( pane, _( \"_Scale\" ), \n\t\tGTK_SIGNAL_FUNC( conversionview_scale_cb ), cv );\n\tcv->falsecolour = menu_add_tog( pane, _( \"_False Color\" ), \n\t\tGTK_SIGNAL_FUNC( conversionview_falsecolour_cb ), cv );\n\tcv->type = menu_add_tog( pane, _( \"_Interpret\" ), \n\t\tGTK_SIGNAL_FUNC( conversionview_interpret_cb ), cv );\n\tmenu_add_but( pane, _( \"_Reset\" ), \n\t\tGTK_SIGNAL_FUNC( conversionview_reset_cb ), cv );\n\tmenu_add_but( pane, _( \"Set As Workspace _Default\" ), \n\t\tGTK_SIGNAL_FUNC( conversionview_set_default_cb ), cv );\n\tmenu_add_sep( pane );\n\tmenu_add_but( pane, GTK_STOCK_CLOSE,\n\t\tGTK_SIGNAL_FUNC( conversionview_hide_cb ), cv );\n\n\tpopupbutton = popupbutton_new();\n\tpopupbutton_set_menu( popupbutton, pane );\n        gtk_box_pack_start( GTK_BOX( hb ), GTK_WIDGET( popupbutton ), \n\t\tFALSE, FALSE, 0 );\n\n\tcv->scale = tslider_new();\n\ttslider_set_conversions( cv->scale, \n\t\ttslider_log_value_to_slider, tslider_log_slider_to_value );\n\tcv->scale->from = 0.001;\n\tcv->scale->to = 255.0;\n\tcv->scale->value = 1.0;\n\tcv->scale->svalue = 128;\n\tcv->scale->digits = 3;\n\ttslider_changed( cv->scale );\n        gtk_box_pack_start( GTK_BOX( hb ), \n\t\tGTK_WIDGET( cv->scale ), TRUE, TRUE, 0 );\n        gtk_signal_connect( GTK_OBJECT( cv->scale ), \"changed\", \n\t\tGTK_SIGNAL_FUNC( conversionview_scale_change_cb ), cv );\n\ttslider_set_ignore_scroll( cv->scale, FALSE );\n\n\tsep = gtk_vseparator_new();\n        gtk_box_pack_start( GTK_BOX( hb ), sep, FALSE, FALSE, 0 );\n\n\tcv->offset = tslider_new();\n\tcv->offset->from = -128;\n\tcv->offset->to = 128;\n\tcv->offset->value = 0;\n\tcv->offset->svalue = 0;\n\tcv->offset->digits = 1;\n\ttslider_changed( cv->offset );\n        gtk_box_pack_start( GTK_BOX( hb ), \n\t\tGTK_WIDGET( cv->offset ), TRUE, TRUE, 0 );\n        gtk_signal_connect( GTK_OBJECT( cv->offset ), \"changed\", \n\t\tGTK_SIGNAL_FUNC( conversionview_offset_change_cb ), cv );\n\ttslider_set_ignore_scroll( cv->offset, FALSE );\n\n\tgtk_widget_show_all( hb );\n}\n\nGtkType\nconversionview_get_type( void )\n{\n\tstatic GtkType conversionview_type = 0;\n\n\tif( !conversionview_type ) {\n\t\tstatic const GtkTypeInfo sinfo = {\n\t\t\t\"Conversionview\",\n\t\t\tsizeof( Conversionview ),\n\t\t\tsizeof( ConversionviewClass ),\n\t\t\t(GtkClassInitFunc) conversionview_class_init,\n\t\t\t(GtkObjectInitFunc) conversionview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tconversionview_type = \n\t\t\tgtk_type_unique( GTK_TYPE_FRAME, &sinfo );\n\t}\n\n\treturn( conversionview_type );\n}\n\n/* Our conversion has changed ... update.\n */\nstatic void\nconversionview_changed_cb( Imagemodel *imagemodel, Conversionview *cv )\n{\n\tGtkCheckMenuItem *item;\n\n\twidget_visible( GTK_WIDGET( cv ), imagemodel->show_convert );\n\tif( !imagemodel->show_convert )\n\t\treturn;\n\n\tif( cv->scale->value != imagemodel->scale ) {\n\t\tcv->scale->value = imagemodel->scale;\n\t\ttslider_changed( cv->scale );\n\t}\n\n\tif( cv->offset->value != imagemodel->offset ) {\n\t\tcv->offset->value = imagemodel->offset;\n\t\ttslider_changed( cv->offset );\n\t}\n\n\titem = GTK_CHECK_MENU_ITEM( cv->falsecolour );\n\tif( item->active != imagemodel->falsecolour ) \n\t\tgtk_check_menu_item_set_active( item, imagemodel->falsecolour );\n\n\titem = GTK_CHECK_MENU_ITEM( cv->type );\n\tif( item->active != imagemodel->type ) \n\t\tgtk_check_menu_item_set_active( item, imagemodel->type );\n}\n\nstatic void\nconversionview_link( Conversionview *cv, Imagemodel *imagemodel )\n{\n\tg_assert( !cv->imagemodel );\n\n\tcv->imagemodel = imagemodel;\n\tg_signal_connect( G_OBJECT( cv->imagemodel ), \n\t\t\"changed\", G_CALLBACK( conversionview_changed_cb ), cv );\n}\n\nConversionview *\nconversionview_new( Imagemodel *imagemodel )\n{\n\tConversionview *cv = gtk_type_new( TYPE_CONVERSIONVIEW );\n\n\tconversionview_link( cv, imagemodel );\n\n\treturn( cv );\n}\n"
  },
  {
    "path": "src/conversionview.h",
    "content": "/* Decls for conversionview.c ... controls for manipulating a conversion\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_CONVERSIONVIEW (conversionview_get_type())\n#define CONVERSIONVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_CONVERSIONVIEW, Conversionview ))\n#define CONVERSIONVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_CONVERSIONVIEW, ConversionviewClass ))\n#define IS_CONVERSIONVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_CONVERSIONVIEW ))\n#define IS_CONVERSIONVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_CONVERSIONVIEW ))\n\nstruct _Conversionview {\n\tGtkFrame parent_class;\n\n\tImagemodel *imagemodel;\n\n\tTslider *scale;\n\tTslider *offset;\n\n\tGtkWidget *falsecolour;\t\t/* Toggle menu items */\n\tGtkWidget *type;\t\n};\n\ntypedef struct _ConversionviewClass {\n\tGtkFrameClass parent_class;\n\n\t/* My methods.\n\t */\n} ConversionviewClass;\n\nGtkType conversionview_get_type( void );\nConversionview *conversionview_new( Imagemodel *imagemodel );\n"
  },
  {
    "path": "src/defbrowser.c",
    "content": "/* Defbrowser dialog.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk \n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\n/* Our columns.\n */\nenum {\n\tNAME_COLUMN,\t\t\t/* Kit or tool name */\n\tTOOLTIP_COLUMN,\t\n\tTOOL_POINTER_COLUMN,\t\t/* Pointer to tool */\n\tKIT_POINTER_COLUMN,\t\t/* Pointer to kit (if no tool) */\n\tN_COLUMNS\n};\n\nstatic void\ndefbrowser_destroy( GtkObject *object )\n{\n\tDefbrowser *defbrowser = DEFBROWSER( object );\n\n\tUNREF( defbrowser->store );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void \ndefbrowser_rebuild_item3( Defbrowser *defbrowser, \n\tconst char *name, const char *tip, \n\tTool *tool, Toolkit *kit )\n{\n\tGtkTreeIter iter;\n\n\tgtk_list_store_append( defbrowser->store, &iter );\n\tgtk_list_store_set( defbrowser->store, &iter,\n\t\tNAME_COLUMN, name, \n\t\tTOOLTIP_COLUMN, tip,\n\t\tTOOL_POINTER_COLUMN, tool,\n\t\tKIT_POINTER_COLUMN, kit,\n\t\t-1 );\n}\n\nstatic void *\ndefbrowser_rebuild_item2( Tool *tool, Defbrowser *defbrowser )\n{\n\tif( tool->toolitem &&\n\t\ttool->toolitem->tooltip )\n\t\tdefbrowser_rebuild_item3( defbrowser, \n\t\t\tIOBJECT( tool )->name, tool->toolitem->tooltip,\n\t\t\ttool, tool->kit );\n\telse\n\t\tdefbrowser_rebuild_item3( defbrowser,\n\t\t\tIOBJECT( tool )->name, tool->help,\n\t\t\ttool, tool->kit );\n\n\treturn( NULL );\n}\n\nstatic void *\ndefbrowser_rebuild_item( Toolkit *kit, Defbrowser *defbrowser )\n{\n\ttoolkit_map( kit, \n\t\t(tool_map_fn) defbrowser_rebuild_item2,\n\t\tdefbrowser, NULL );\n\n\treturn( NULL );\n}\n\nstatic void\ndefbrowser_refresh( vObject *vobject )\n{\n\tDefbrowser *defbrowser = DEFBROWSER( vobject );\n\n#ifdef DEBUG\n\tprintf( \"defbrowser_refresh:\\n\" );\n#endif /*DEBUG*/\n\n\tgtk_list_store_clear( defbrowser->store );\n\ttoolkitgroup_map( defbrowser->program->kitg,\n\t\t(toolkit_map_fn) defbrowser_rebuild_item, \n\t\tdefbrowser, NULL );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\ndefbrowser_class_init( DefbrowserClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = defbrowser_destroy;\n\n\tvobject_class->refresh = defbrowser_refresh;\n}\n\nstatic void\ndefbrowser_entry_changed_cb( GtkEditable *editable, \n\tDefbrowser *defbrowser )\n{\n\tgtk_tree_model_filter_refilter( \n\t\tGTK_TREE_MODEL_FILTER( defbrowser->filter ) );\n}\n\nstatic gboolean\ndefbrowser_rebuild_test( Tool *tool, const char *text )\n{\n\tif( tool->toolitem &&\n\t\ttool->toolitem->tooltip ) {\n\t\tif( my_strcasestr( tool->toolitem->tooltip, text ) )\n\t\t\treturn( TRUE );\n\t}\n\tif( my_strcasestr( IOBJECT( tool )->name, text ) )\n\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\nstatic gboolean\ndefbrowser_visible_func( GtkTreeModel *model, GtkTreeIter *iter, \n\tgpointer data )\n{\n\tDefbrowser *defbrowser = DEFBROWSER( data );\n\tconst char *text = gtk_entry_get_text( \n\t\tGTK_ENTRY( defbrowser->entry ) );\n\tTool *tool;\n\n\tgtk_tree_model_get( model, iter, \n\t\tTOOL_POINTER_COLUMN, &tool, \n\t\t-1 );\n\tif( !tool )\n\t\treturn( FALSE );\n\n\treturn( defbrowser_rebuild_test( tool, text ) );\n}\n\nstatic Tool *\ndefbrowser_get_selected( Defbrowser *defbrowser )\n{\n\tGtkTreeSelection *selection = gtk_tree_view_get_selection( \n\t\tGTK_TREE_VIEW( defbrowser->tree ) );\n\tGtkTreeIter iter;\n\tGtkTreeModel *model;\n\tTool *tool; \n\n        if( gtk_tree_selection_get_selected( selection, &model, &iter ) ) {\n\t\tgtk_tree_model_get( model, &iter, \n\t\t\tTOOL_POINTER_COLUMN, &tool, -1 );\n\n\t\treturn( tool );\n        }\n\n\treturn( NULL );\n}\n\nstatic gboolean\ndefbrowser_activate_selected( Defbrowser *defbrowser )\n{\n\tTool *tool;\n\n        if( (tool = defbrowser_get_selected( defbrowser )) )\n\t\tif( !program_select( defbrowser->program, MODEL( tool ) ) )\n\t\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic void\ndefbrowser_selection_changed_cb( GtkTreeSelection *select, \n\tDefbrowser *defbrowser )\n{\n\tif( !defbrowser_activate_selected( defbrowser ) )\n\t\tiwindow_alert( GTK_WIDGET( defbrowser ), \n\t\t\tGTK_MESSAGE_ERROR );\n}\n\nstatic void\ndefbrowser_init( Defbrowser *defbrowser )\n{\n\tGtkCellRenderer *renderer;\n\tGtkTreeViewColumn *column;\n\tGtkWidget *label;\n\tGtkWidget *swin;\n\tGtkTreeSelection *select;\n\n\tdefbrowser->top = gtk_hbox_new( FALSE, 12 );\n\tdefbrowser->entry = gtk_entry_new();\n        gtk_signal_connect( GTK_OBJECT( defbrowser->entry ), \"changed\", \n\t\tGTK_SIGNAL_FUNC( defbrowser_entry_changed_cb ), \n\t\tdefbrowser );\n\tgtk_box_pack_end( GTK_BOX( defbrowser->top ), \n\t\tdefbrowser->entry, FALSE, FALSE, 2 );\n\tlabel = gtk_image_new_from_stock( GTK_STOCK_FIND, GTK_ICON_SIZE_MENU );\n\tgtk_box_pack_end( GTK_BOX( defbrowser->top ), \n\t\tlabel, FALSE, FALSE, 0 );\n        gtk_box_pack_start( GTK_BOX( defbrowser ), \n\t\tdefbrowser->top, FALSE, FALSE, 2 );\n\tgtk_widget_show_all( defbrowser->top );\n\n\tdefbrowser->store = gtk_list_store_new( N_COLUMNS, \n\t\tG_TYPE_STRING, \n\t\tG_TYPE_STRING,\n\t\tG_TYPE_POINTER,\n\t\tG_TYPE_POINTER );\n\n\tdefbrowser->filter = gtk_tree_model_filter_new( \n\t\tGTK_TREE_MODEL( defbrowser->store ), NULL );\n\tgtk_tree_model_filter_set_visible_func( \n\t\tGTK_TREE_MODEL_FILTER( defbrowser->filter ), \n\t\tdefbrowser_visible_func, defbrowser, NULL );\n\n\tdefbrowser->tree = gtk_tree_view_new_with_model( \n\t\tGTK_TREE_MODEL( defbrowser->filter ) );\n\tgtk_tree_view_set_rules_hint( GTK_TREE_VIEW( defbrowser->tree ),\n\t\tTRUE );\n\tgtk_tree_view_set_headers_visible( GTK_TREE_VIEW( defbrowser->tree ), \n\t\tFALSE );\n\n\trenderer = gtk_cell_renderer_text_new();\n\tcolumn = gtk_tree_view_column_new_with_attributes( _( \"Name\" ),\n\t\trenderer, \"text\", NAME_COLUMN, NULL );\n\tgtk_tree_view_append_column( GTK_TREE_VIEW( defbrowser->tree ), \n\t\tcolumn );\n\n\trenderer = gtk_cell_renderer_text_new();\n\tcolumn = gtk_tree_view_column_new_with_attributes( _( \"Tooltip\" ),\n\t\trenderer, \"text\", TOOLTIP_COLUMN, NULL );\n\tgtk_tree_view_append_column( GTK_TREE_VIEW( defbrowser->tree ), \n\t\tcolumn );\n\n\tselect = gtk_tree_view_get_selection( \n\t\tGTK_TREE_VIEW( defbrowser->tree ) );\n\tgtk_tree_selection_set_mode( select, GTK_SELECTION_SINGLE );\n\tg_signal_connect( G_OBJECT( select ), \"changed\",\n\t\tG_CALLBACK( defbrowser_selection_changed_cb ), defbrowser );\n\n\tswin = gtk_scrolled_window_new( NULL, NULL );\n        gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ),\n\t\tGTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );\n\tgtk_container_add( GTK_CONTAINER( swin ), defbrowser->tree );\n\n        gtk_box_pack_start( GTK_BOX( defbrowser ), swin, TRUE, TRUE, 2 );\n\tgtk_widget_show_all( swin );\n}\n\nGtkType\ndefbrowser_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Defbrowser\",\n\t\t\tsizeof( Defbrowser ),\n\t\t\tsizeof( DefbrowserClass ),\n\t\t\t(GtkClassInitFunc) defbrowser_class_init,\n\t\t\t(GtkObjectInitFunc) defbrowser_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_VOBJECT, &info );\n\t}\n\n\treturn( type );\n}\n\nvoid\ndefbrowser_set_program( Defbrowser *defbrowser, Program *program )\n{\n\tg_assert( !defbrowser->program );\n\n#ifdef DEBUG\n\tprintf( \"defbrowser_set_program:\\n\" );\n#endif /*DEBUG*/\n\n\tdefbrowser->program = program;\n}\n\nDefbrowser *\ndefbrowser_new( void )\n{\n\tDefbrowser *defbrowser = gtk_type_new( TYPE_DEFBROWSER );\n\n\treturn( defbrowser );\n}\n\n/* Find the 'natural' width of the browser.\n */\nint \ndefbrowser_get_width( Defbrowser *defbrowser )\n{\n\tif( defbrowser->top )\n\t\treturn( defbrowser->top->requisition.width );\n\telse\n\t\treturn( 200 );\n}\n\n/* Set the filter string.\n */\nvoid\ndefbrowser_set_filter( Defbrowser *defbrowser, const char *filter )\n{\n\tgtk_entry_set_text( GTK_ENTRY( defbrowser->entry ), filter );\n}\n"
  },
  {
    "path": "src/defbrowser.h",
    "content": "/* Def browser\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_DEFBROWSER (defbrowser_get_type())\n#define DEFBROWSER( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_DEFBROWSER, Defbrowser ))\n#define DEFBROWSER_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_DEFBROWSER, DefbrowserClass ))\n#define IS_DEFBROWSER( obj ) \\\n\t(GTK_CHECK_TYPE( (obj), TYPE_DEFBROWSER ))\n#define IS_DEFBROWSER_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_DEFBROWSER ))\n\ntypedef struct _Defbrowser {\n\tvObject parent_object;\n\n\tProgram *program;\t\t/* Program whose kits we explore */\n\n\tGtkListStore *store;\t\t/* Model for list view */\n\tGtkTreeModel *filter;\t\t/* After filtering with search box */\n\tGtkWidget *tree;\t\t/* Displayed tree */\n\tGtkWidget *entry;\t\t/* Search widget */\n\tGtkWidget *top;\t\t\t/* hbox for top bar */\n} Defbrowser;\n\ntypedef struct _DefbrowserClass {\n\tvObjectClass parent_class;\n\n} DefbrowserClass;\n\nGtkType defbrowser_get_type( void );\nvoid defbrowser_set_program( Defbrowser *defbrowser, Program *program );\nDefbrowser *defbrowser_new( void );\nint defbrowser_get_width( Defbrowser *defbrowser );\nvoid defbrowser_set_filter( Defbrowser *defbrowser, const char *filter );\n\n"
  },
  {
    "path": "src/doubleclick.c",
    "content": "/* ip: display VASARI format files.\n * \n * doubleclick.c: separate single and double clicks on a widget\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif /*HAVE_UNISTD_H*/\n#include <string.h>\n\n#include <gtk/gtk.h>\n#include <gdk/gdkkeysyms.h>\n\n#include <vips/vips.h>\n#include <vips/vips7compat.h>\n#include <vips/util.h>\n\n#include \"doubleclick.h\"\n\n#define FREEFI( F, S ) { if( S ) { (void) F( S ); (S) = 0; } }\n\n/* For debugging.\n#define DEBUG\n */\n\n/* The struct we hold our private stuff inside.\n */\ntypedef struct doubleclick_info {\n\tGtkWidget *wid;\t\t/* Widget we are attached to */\n\tguint click;\t\t/* Timer for click determination */\n\tgboolean dsingle;\t/* Do single click on first click of double */\n\tGdkEvent event;\t\t/* Copy of last event for clients */\n\n\tDoubleclickFunc single;\t/* Callback for single click */\n\tvoid *clients;\t\t/* Client data for single */\n\tDoubleclickFunc dub;\t/* Callback for double click */\n\tvoid *clientd;\t\t/* Client data for double */\n} Doubleclick; \n\n/* Allocate and free clicks.\n */\nstatic Doubleclick *\ndoubleclick_new()\n{\n\tDoubleclick *click;\n\n\tif( !(click = IM_NEW( NULL, Doubleclick )) )\n\t\treturn( NULL );\n\n\tclick->wid = NULL;\n\tclick->click = 0;\n\tclick->dsingle = FALSE;\n\tclick->single = NULL;\n\tclick->dub = NULL;\n\n\treturn( click );\n}\n\nvoid\ndoubleclick_free( Doubleclick *click )\n{\n\tim_free( click );\n}\n\n/* Timer callback for multiclick detection.\n */\nstatic gboolean\ndoubleclick_time_cb( Doubleclick *click )\n{\n#ifdef DEBUG\n\tg_message( \"doubleclick: timeout\" );\n#endif /*DEBUG*/\n\n\tclick->click = 0;\n\n\t/* There has been no second click before the timeout: we do a single\n\t * click. If st->dsingle is set though, we have already delivered the\n\t * single-click event, so don't bother.\n\t */\n\tif( !click->dsingle && click->single ) {\n#ifdef DEBUG\n\t\tg_message( \"doubleclick: timeout - calling single\" );\n#endif /*DEBUG*/\n\t\tclick->single( click->wid, &click->event, click->clients );\n\t}\n\n\t/* Stop timer.\n\t */\n\treturn( FALSE );\n}\n\n/* There has been an event. Is it single or double?\n */\nstatic gboolean\ndoubleclick_trigger_cb( GtkWidget *wid, GdkEvent *ev, Doubleclick *click )\n{\n\tgboolean handled = FALSE;\n\n\t/* Make sure we have a button 1 press.\n\t */\n\tif( ev->type != GDK_BUTTON_PRESS || ev->button.button != 1 )\n\t\treturn( handled );\n\n\t/* Note event for client.\n\t */\n\tclick->event = *ev;\n\n\tif( click->click ) {\n\t\t/* There is a timeout pending - ie. there was a click\n\t\t * recently. This must be the second part of a double click.\n\t\t * Cancel the timeout and do a double click action.\n\t\t */\n\t\tFREEFI( g_source_remove, click->click );\n\t\tif( click->dub ) {\n#ifdef DEBUG\n\t\t\tg_message( \"doubleclick: seen double\" );\n#endif /*DEBUG*/\n\t\t\tclick->dub( click->wid, &click->event, click->clientd ); \n\t\t\thandled = TRUE;\n\t\t}\n\t}\n\telse {\n#ifdef DEBUG\n\t\tg_message( \"doubleclick: starting timer\" );\n#endif /*DEBUG*/\n\t\t/* No previous click. This may be either. Start a timeout to\n\t\t * help us decide.\n\t\t *\n\t\t * We aren't supposed to look at double_click_time, but\n\t\t * there's no access method, I think.\n\t\t */\n\t\tclick->click = g_timeout_add( \n\t\t\tgtk_widget_get_display( wid )->double_click_time, \n\t\t\t(GSourceFunc) doubleclick_time_cb, click );\n\n\t\t/* If do-single-on-double is set, we can trigger a\n\t\t * single-click now.\n\t\t */\n\t\tif( click->dsingle && click->single ) {\n\t\t\tclick->single( click->wid, &click->event, \n\t\t\t\tclick->clients ); \n\t\t\thandled = TRUE;\n\t\t}\n\t}\n\n\treturn( handled );\n}\n\n/* Destroy a doubleclick_info.\n */\n/*ARGSUSED*/\nstatic void\ndoubleclick_destroy_cb( GtkWidget *wid, Doubleclick *click )\n{\n#ifdef DEBUG\n\tg_message( \"doubleclick: destroyed\" );\n#endif /*DEBUG*/\n\n\tif( click->click ) {\n\t\t/* Don't trigger a single-click, even though there was one\n\t\t * recently, since our widget is being destroyed.\n\t\t */\n\t\tFREEFI( g_source_remove, click->click );\n\t}\n\n\tdoubleclick_free( click );\n}\n\nstatic void\ndoubleclick_realize_cb( GtkWidget *wid )\n{\n\tgtk_widget_add_events( wid, GDK_BUTTON_PRESS_MASK );\n}\n\n/* Attach callbacks to a widget.\n */\nvoid\ndoubleclick_add( GtkWidget *wid, gboolean dsingle,\n\tDoubleclickFunc single, void *clients,\n\tDoubleclickFunc dub, void *clientd )\n{\n\tDoubleclick *click = doubleclick_new();\n\n\t/* Complete fields.\n\t */\n\tclick->wid = wid;\n\tclick->dsingle = dsingle;\n\n\tclick->single = single;\n\tclick->dub = dub;\n\tclick->clients = clients;\n\tclick->clientd = clientd;\n\n\t/* Add callbacks.\n\t */\n\tgtk_signal_connect( GTK_OBJECT( wid ), \"destroy\", \n\t\tGTK_SIGNAL_FUNC( doubleclick_destroy_cb ), click );\n\tgtk_signal_connect( GTK_OBJECT( wid ), \"event\", \n\t\tGTK_SIGNAL_FUNC( doubleclick_trigger_cb ), click );\n\tgtk_signal_connect( GTK_OBJECT( wid ), \"realize\", \n\t\tGTK_SIGNAL_FUNC( doubleclick_realize_cb ), NULL );\n}\n"
  },
  {
    "path": "src/doubleclick.h",
    "content": "/* Declarations for doubleclick determiner.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\ntypedef void (*DoubleclickFunc)( GtkWidget *, GdkEvent *, void * );\n#define DOUBLECLICK_FUNC( fn ) ((DoubleclickFunc) (fn))\n\nvoid doubleclick_add( GtkWidget *wid, gboolean dsingle,\n\tDoubleclickFunc single, void *clients,\n\tDoubleclickFunc dub, void *clientd );\n"
  },
  {
    "path": "src/dummy.c",
    "content": "int poop () {}\n"
  },
  {
    "path": "src/dump.c",
    "content": "/* Prettyprint various things for debugging.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* A lot of this file is just for debugging. Uncomment to enable all the\n * debugging code.\n#define DEBUG\n */\n\n/* Dump a binary operator.\n */\nchar *\ndecode_BinOp( BinOp op )\n{\n\tswitch( op ) {\n\tcase BI_NONE:\t\treturn( \"(none)\" );\n\tcase BI_ADD:\t\treturn( \"+\" );\n\tcase BI_SUB:\t\treturn( \"-\" );\n\tcase BI_POW:\t\treturn( \"**\" );\n\tcase BI_REM:\t\treturn( \"%\" );\n\tcase BI_LSHIFT:\t\treturn( \"<<\" );\n\tcase BI_RSHIFT:\t\treturn( \">>\" );\n\tcase BI_SELECT:\t\treturn( \"?\" );\n\tcase BI_DIV:\t\treturn( \"/\" );\n\tcase BI_JOIN:\t\treturn( \"++\" );\n\tcase BI_COMMA:\t\treturn( \",\" );\n\tcase BI_DOT:\t\treturn( \".\" );\n\tcase BI_MUL:\t\treturn( \"*\" );\n\tcase BI_LAND:\t\treturn( \"&&\" );\n\tcase BI_LOR:\t\treturn( \"||\" );\n\tcase BI_BAND:\t\treturn( \"&\" );\n\tcase BI_BOR:\t\treturn( \"|\" );\n\tcase BI_EOR:\t\treturn( \"^\" );\n\tcase BI_EQ:\t\treturn( \"==\" );\n\tcase BI_NOTEQ:\t\treturn( \"!=\" );\n\tcase BI_PEQ:\t\treturn( \"===\" );\n\tcase BI_PNOTEQ:\t\treturn( \"!==\" );\n\tcase BI_LESS:\t\treturn( \"<\" );\n\tcase BI_LESSEQ:\t\treturn( \"<=\" );\n\tcase BI_MORE:\t\treturn( \">\" );\n\tcase BI_MOREEQ:\t\treturn( \">=\" );\n\tcase BI_IF:\t\treturn( \"if_then_else\" );\n\tcase BI_CONS:\t\treturn( \":\" );\n\n\tdefault:\n\t\tg_assert( FALSE );\n\n\t\t/* Keep gcc happy.\n\t\t */\n\t\treturn( NULL );\n\t}\n}\n\n/* Dump a unary operator.\n */\nchar *\ndecode_UnOp( UnOp op )\n{\n\tswitch( op ) {\n\tcase UN_NONE:\t\treturn( \"(none)\" );\n\tcase UN_CSCHAR:\t\treturn( \"(signed char)\" );\n\tcase UN_CUCHAR:\t\treturn( \"(unsigned char)\" );\n\tcase UN_CSSHORT:\treturn( \"(signed short)\" );\n\tcase UN_CUSHORT:\treturn( \"(unsigned short)\" );\n\tcase UN_CSINT:\t\treturn( \"(signed int)\" );\n\tcase UN_CUINT:\t\treturn( \"(unsigned int)\" );\n\tcase UN_CFLOAT:\t\treturn( \"(float)\" );\n\tcase UN_CDOUBLE:\treturn( \"(double)\" );\n\tcase UN_CCOMPLEX:\treturn( \"(complex)\" );\n\tcase UN_CDCOMPLEX:\treturn( \"(double complex)\" );\n\tcase UN_MINUS:\t\treturn( \"-\" );\n\tcase UN_NEG:\t\treturn( \"!\" );\n\tcase UN_COMPLEMENT:\treturn( \"~\" );\n\tcase UN_PLUS:\t\treturn( \"+\" );\n\n\tdefault:\n\t\tg_assert( FALSE );\n\n\t\t/* Keep gcc happy.\n\t\t */\n\t\treturn( NULL );\n\t}\n}\n\n/* Decode a node tag.\n */\nchar *\ndecode_NodeType( NodeType tag )\n{\n\tswitch( tag ) {\n\tcase TAG_APPL:\t\treturn( \"TAG_APPL\" );\n\tcase TAG_CONS:\t\treturn( \"TAG_CONS\" );\n\tcase TAG_FREE:\t\treturn( \"TAG_FREE\" );\n\tcase TAG_DOUBLE:\treturn( \"TAG_DOUBLE\" );\n\tcase TAG_COMPLEX:\treturn( \"TAG_COMPLEX\" );\n\tcase TAG_CLASS:\t\treturn( \"TAG_CLASS\" );\n\tcase TAG_GEN:\t\treturn( \"TAG_GEN\" );\n\tcase TAG_FILE:\t\treturn( \"TAG_FILE\" );\n\tcase TAG_SHARED:\treturn( \"TAG_SHARED\" );\n\tcase TAG_REFERENCE:\treturn( \"TAG_REFERENCE\" );\n\n\tdefault:\n\t\tg_assert( FALSE );\n\n\t\t/* Keep gcc happy.\n\t\t */\n\t\treturn( NULL );\n\t}\n}\n\n/* Decode a CombinatorType.\n */\nchar *\ndecode_CombinatorType( CombinatorType comb ) \n{\n\tswitch( comb ) {\n        case COMB_S: \t\treturn( \"S\" );\n        case COMB_SL: \t\treturn( \"Sl\" );\n        case COMB_SR: \t\treturn( \"Sr\" );\n\tcase COMB_I:\t\treturn( \"I\" );\n\tcase COMB_K:\t\treturn( \"K\" );\n\tcase COMB_GEN:\t\treturn( \"G\" );\n\tdefault:\n\t\tg_assert( FALSE );\n\n\t\t/* Keep gcc happy.\n\t\t */\n\t\treturn( NULL );\n\t}\n}\n\n/* Decode a symbol type.\n */\nchar *\ndecode_SymbolType( SymbolType t )\n{\t\n\tswitch( t ) {\n\tcase SYM_VALUE:\t\treturn( \"SYM_VALUE\" );\n\tcase SYM_PARAM:\t\treturn( \"SYM_PARAM\" );\n\tcase SYM_ZOMBIE:\treturn( \"SYM_ZOMBIE\" );\n\tcase SYM_WORKSPACE:\treturn( \"SYM_WORKSPACE\" );\n\tcase SYM_WORKSPACEROOT:\treturn( \"SYM_WORKSPACEROOT\" );\n\tcase SYM_ROOT:\t\treturn( \"SYM_ROOT\" );\n\tcase SYM_EXTERNAL:\treturn( \"SYM_EXTERNAL\" );\n\tcase SYM_BUILTIN:\treturn( \"SYM_BUILTIN\" );\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t\treturn( NULL );\n\t}\n}\n\n/* Decode a symbol type into something users might like to see.\n */\nchar *\ndecode_SymbolType_user( SymbolType t )\n{\t\n\tswitch( t ) {\n\tcase SYM_VALUE:\t\treturn( _( \"value\" ) );\n\tcase SYM_PARAM:\t\treturn( _( \"parameter\" ) );\n\tcase SYM_ZOMBIE:\treturn( _( \"zombie\" ) );\n\tcase SYM_WORKSPACE:\treturn( _( \"workspace\" ) );\n\tcase SYM_WORKSPACEROOT:\treturn( _( \"workspace root\" ) );\n\tcase SYM_ROOT:\t\treturn( _( \"root symbol\" ) );\n\tcase SYM_EXTERNAL:\treturn( _( \"external symbol\" ) );\n\tcase SYM_BUILTIN:\treturn( _( \"built-in symbol\" ) );\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t\treturn( NULL );\n\t}\n}\n\n/* From here on, just used for debugging.\n */\n#ifdef DEBUG\n\n#warning \"DEBUG on in dump.c\"\n\n/* Do a tiny dump of a symbol. Just a few characters.\n */\nvoid *\ndump_tiny( Symbol *sym )\n{\n\tchar txt[100];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tprintf( \"(%p) \", sym );\n\tsymbol_qualified_name( sym, &buf );\n\tif( sym->dirty )\n\t\tprintf( \"*\" );\n\tprintf( \"%s %s; \", \n\t\tdecode_SymbolType( sym->type ), vips_buf_all( &buf ) );\n\n\treturn( NULL );\n}\n\n/* Dump a expr, tiny.\n */\nstatic void *\ndump_expr_tiny( Expr *expr )\n{\n\tprintf( \"(expr->sym->name = \" );\n\tsymbol_name_print( expr->sym );\n\tprintf( \") \" );\n\n\treturn( NULL );\n}\n\n/* Dump a expr info.\n */\nvoid\ndump_expr( Expr *expr )\n{\n\tSymbol *sym = expr->sym;\n\n\tprintf( \"expr (%p)->sym->name = \\\"%s\\\"\\n\", \n\t\texpr, IOBJECT( sym )->name );\n\tif( expr->row )\n\t\tprintf( \"%s->row = (set)\\n\", IOBJECT( sym )->name ); \n\n\tif( expr->compile ) {\n\t\tprintf( \"%s->compile:\\n\", IOBJECT( sym )->name );\n\t\tdump_compile( expr->compile );\n\t}\n\n\tif( sym->dirty ) \n\t\tprintf( \"<symbol is dirty ... can't print root>\\n\" );\n\telse if( !PEISNOVAL( &expr->root ) ) {\n\t\tprintf( \"%s->expr->root = \", IOBJECT( sym )->name );\n\t\tpgraph( &expr->root );\n\t}\n\n\tif( expr->err )\n\t\tprintf( \"%s->expr->err = %s\\n\", \n\t\t\tIOBJECT( sym )->name, bool_to_char( expr->err ) );\n\tif( expr->error_top )\n\t\tprintf( \"%s->expr->error_top = \\\"%s\\\"\\n\", \n\t\t\tIOBJECT( sym )->name, NN( expr->error_top ) );\n\tif( expr->error_sub )\n\t\tprintf( \"%s->expr->error_sub = \\\"%s\\\"\\n\", \n\t\t\tIOBJECT( sym )->name, NN( expr->error_sub ) );\n}\n\n/* Dump a compile, tiny.\n */\nstatic void *\ndump_compile_tiny( Compile *compile )\n{\n\tprintf( \"(compile->sym->name = \" );\n\tsymbol_name_print( compile->sym );\n\tprintf( \") \" );\n\n\treturn( NULL );\n}\n\n/* Dump a compile.\n */\nvoid\ndump_compile( Compile *compile )\n{\n\tSymbol *sym = compile->sym;\n\n\tprintf( \"compile (%p)->sym->name = \\\"%s\\\"\\n\", \n\t\tcompile, IOBJECT( sym )->name );\n\n#ifdef VERBOSE\n\tprintf( \"%s->class = %s\\n\", \n\t\tIOBJECT( sym )->name, bool_to_char( compile->is_klass ) );\n\tprintf( \"%s->super = %s\\n\", \n\t\tIOBJECT( sym )->name, bool_to_char( compile->has_super ) );\n\n\tprintf( \"%s->compile->text = \\\"%s\\\"\\n\", \n\t\tIOBJECT( sym )->name, NN( compile->text ) );\n\tprintf( \"%s->compile->prhstext = \\\"%s\\\"\\n\", \n\t\tIOBJECT( sym )->name, NN( compile->prhstext ) );\n\tprintf( \"%s->compile->rhstext = \\\"%s\\\"\\n\", \n\t\tIOBJECT( sym )->name, NN( compile->rhstext ) );\n#endif /*VERBOSE*/\n\n\tif( compile->tree ) {\n\t\tprintf( \"%s->compile->tree = \\n\", IOBJECT( sym )->name ); \n\t\t(void) dump_tree( compile->tree ); \n\t}\n#ifdef VERBOSE\n\tprintf( \"%s->compile->treefrag = %d pointers\\n\", IOBJECT( sym )->name,\n\t\tg_slist_length( compile->treefrag ) );\n#endif /*VERBOSE*/\n\n\tif( icontainer_get_n_children( ICONTAINER( compile ) ) > 0 ) {\n\t\tprintf( \"%s->compile->children =\\n\", \n\t\t\tIOBJECT( sym )->name );\n\t\t(void) icontainer_map( ICONTAINER( compile ), \n\t\t\t(icontainer_map_fn) dump_symbol, NULL, NULL );\n\t}\n\n#ifdef VERBOSE\n{\n\tchar txt[100];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tprintf( \"%s->compile->nparam = %d\\n\", \n\t\tIOBJECT( sym )->name, compile->nparam );\n\tprintf( \"%s->compile->param = \", IOBJECT( sym )->name );\n\t(void) slist_map( compile->param, (SListMapFn) dump_tiny, NULL );\n\tprintf( \"\\n\" );\n\tprintf( \"%s->compile->nsecret = %d\\n\", \n\t\tIOBJECT( sym )->name, compile->nsecret );\n\tprintf( \"%s->compile->secret = \", IOBJECT( sym )->name );\n\t(void) slist_map( compile->secret, (SListMapFn) dump_tiny, NULL );\n\tprintf( \"\\n\" );\n\tprintf( \"%s->compile->this = \", IOBJECT( sym )->name );\n\tif( compile->this )\n\t\tdump_tiny( compile->this );\n\telse\n\t\tprintf( \"(null)\" );\n\tprintf( \"\\n\" );\n\tprintf( \"%s->compile->super = \", IOBJECT( sym )->name );\n\tif( compile->super )\n\t\tdump_tiny( compile->super );\n\telse\n\t\tprintf( \"(null)\" );\n\tprintf( \"\\n\" );\n\tprintf( \"%s->compile->children = \", IOBJECT( sym )->name );\n\t(void) slist_map( compile->children, (SListMapFn) dump_tiny, NULL );\n\tprintf( \"\\n\" );\n\n\tgraph_element( compile->heap, &buf, &compile->base, FALSE );\n\tprintf( \"%s->compile->base = %s\\n\", \n\t\tIOBJECT( sym )->name, vips_buf_all( &buf ) );\n\tif( compile->heap )\n\t\tiobject_dump( IOBJECT( compile->heap ) );\n}\n#endif /*VERBOSE*/\n}\n\n/* Print a full symbol and all it's children. \n */\nvoid *\ndump_symbol( Symbol *sym )\n{\t\n\tprintf( \"\\n\\nsym->name = \" );\n\t(void) dump_tiny( sym );\n\tprintf( \"\\n\" );\n\n#ifdef VERBOSE\n\tprintf( \"%s->patch = %d pointers\\n\", IOBJECT( sym )->name,\n\t\tg_slist_length( sym->patch ) );\n#endif /*VERBOSE*/\n\n\tif( sym->expr ) \n\t\tdump_expr( sym->expr );\n\n#ifdef VERBOSE\n\tprintf( \"%s->base = \", IOBJECT( sym )->name );\n\tif( !sym->dirty ) {\n\t\tPElement root;\n\n\t\tPEPOINTE( &root, &sym->base );\n\t\tpgraph( &root );\n\t}\n\telse\n\t\tprintf( \"<sym is dirty ... can't print>\" );\n\tprintf( \"\\n\" );\n\n\tprintf( \"%s->dirty = %s\\n\", \n\t\tIOBJECT( sym )->name, bool_to_char( sym->dirty ) );\n\tprintf( \"%s->parents = \", IOBJECT( sym )->name );\n\t(void) slist_map( sym->parents, (SListMapFn) dump_compile_tiny, NULL );\n\tprintf( \"\\n\" );\n\n\t/* Prints topchildren and topparents.\n\t */\n\tdump_links( sym );\n\tprintf( \"%s->ndirtychildren = %d\\n\", \n\t\tIOBJECT( sym )->name, sym->ndirtychildren );\n\tprintf( \"%s->leaf = %s\\n\", \n\t\tIOBJECT( sym )->name, bool_to_char( sym->leaf ) );\n\n\tprintf( \"%s->tool = kit \", IOBJECT( sym )->name );\n\tif( sym->tool )\n\t\tdump_kit( sym->tool->kit );\n\telse\n\t\tprintf( \"<NULL>\\n\" );\n#endif /*VERBOSE*/\n\n\treturn( NULL );\n}\n\n/* Pretty print the whole of the symbol table.\n */\nvoid\ndump_symbol_table( void )\n{\t\n\t(void) icontainer_map( ICONTAINER( symbol_root->expr->compile ), \n\t\t(icontainer_map_fn) dump_symbol, NULL, NULL );\n}\n\n/* Tiny dump a tool.\n */\nstatic void *\ndump_tiny_tool( Tool *tool )\n{\n\tswitch( tool->type ) {\n\tcase TOOL_SEP:\n\t\tprintf( \"<separator> \" );\n\t\tbreak;\n\n\tcase TOOL_DIA:\n\t\tprintf( \"<dialog \\\"%s\\\"> \", FILEMODEL( tool )->filename );\n\t\tbreak;\n\t\n\tcase TOOL_SYM:\n\t\tdump_tiny( tool->sym );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( NULL );\n}\n\n/* Print out the syms in a kit.\n */\nvoid *\ndump_kit( Toolkit *kit )\n{\n\tprintf( \"kit->name = %s; \", IOBJECT( kit )->name );\n\tprintf( \"%s->tools = \", IOBJECT( kit )->name );\n\ticontainer_map( ICONTAINER( kit ), \n\t\t(icontainer_map_fn) dump_tiny_tool, NULL, NULL );\n\tprintf( \"\\n\" );\n\n\treturn( NULL );\n}\n\n/* Easy find-a-symbol for gdb.\n */\nSymbol *\nsym( char *name )\n{\t\n\treturn( compile_lookup( symbol_root->expr->compile, name ) );\n}\n\n/* Print from a name.\n */\nvoid \npsym( char *name )\n{\t\n\tSymbol *s;\n\n\tif( (s = sym( name )) )\n\t\t(void) dump_symbol( s );\n\telse\n\t\tprintf( \"Symbol \\\"%s\\\" not found\\n\", name );\n}\n\n/* Print scrap of graph.\n */\nvoid \npgraph( PElement *graph )\n{\t\n\tchar txt[10240];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_pelement( reduce_context->heap, &buf, graph, TRUE );\n\tprintf( \"%s\\n\", vips_buf_all( &buf ) );\n}\n\n/* Print symbol value from name.\n */\nvoid \npsymv( char *name )\n{\t\n\tSymbol *s;\n\n\tif( (s = sym( name )) ) {\n\t\tchar txt[1024];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\tgraph_pelement( reduce_context->heap, \n\t\t\t&buf, &s->expr->root, TRUE );\n\t\tprintf( \"%s = %s\\n\", name, vips_buf_all( &buf ) );\n\t}\n}\n\n/* Pretty-print an element.\n */\nstatic void\nprint_element( int nsp, EType type, void *arg )\n{\n\tswitch( type ) {\n\tcase ELEMENT_NOVAL:\n\t\tprintf( \"no value (%d)\\n\", GPOINTER_TO_INT( arg ) );\n\t\tbreak;\n\n\tcase ELEMENT_NODE:\n\t\tprintf( \"node ->\\n\" );\n\t\tgraph_heap( nsp + 1, arg );\n\t\tbreak;\n\n\tcase ELEMENT_SYMBOL:\n\t\tprintf( \"symbol \\\"%s\\\"\", IOBJECT( arg )->name );\n\t\tbreak;\n\n\tcase ELEMENT_SYMREF:\n\t\tprintf( \"symref \\\"%s\\\"\", IOBJECT( arg )->name );\n\t\tbreak;\n\n\tcase ELEMENT_COMPILEREF:\n\t\tprintf( \"compileref \" );\n\t\tcompile_name_print( COMPILE( arg ) );\n\t\tbreak;\n\n\tcase ELEMENT_CONSTRUCTOR:\n\t\tprintf( \"constructor \\\"%s\\\"\", IOBJECT( arg )->name );\n\t\tbreak;\n\n\tcase ELEMENT_CHAR:\n\t\tprintf( \"char \\\"%c\\\"\", GPOINTER_TO_UINT( arg ) );\n\t\tbreak;\n\n\tcase ELEMENT_BOOL:\n\t\tprintf( \"bool \\\"%s\\\"\", bool_to_char(\n\t\t\t(gboolean) GPOINTER_TO_UINT( arg ) ) );\n\t\tbreak;\n\n\tcase ELEMENT_BINOP:\n\t\tprintf( \"binop \\\"%s\\\"\", decode_BinOp( (BinOp)arg ) );\n\t\tbreak;\n\n\tcase ELEMENT_UNOP:\n\t\tprintf( \"unop \\\"%s\\\"\", decode_UnOp( (UnOp)arg ) );\n\t\tbreak;\n\n\tcase ELEMENT_COMB:\n\t\tprintf( \"combinator \\\"%s\\\"\", \n\t\t\tdecode_CombinatorType( (CombinatorType)arg ) );\n\t\tbreak;\n\n\tcase ELEMENT_TAG:\n\t\tprintf( \"tag \\\"%s\\\"\", (char*)arg ); \n\t\tbreak;\n\n\tcase ELEMENT_MANAGED:\n\t\tprintf( \"Managed* %p\", arg ); \n\t\tbreak;\n\n\tcase ELEMENT_ELIST:\n\t\tprintf( \"empty-list []\" ); \n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n}\n\n/* Pretty-print a heap graph.\n */\nvoid \ngraph_heap( int nsp, HeapNode *hn )\n{\n\tif( !hn )\n\t\treturn;\n\n\tprintf( \"%s\", spc( nsp ) );\n\tprintf( \"Node: \" );\n\n\tprintf( \"serial = %d, \", hn->flgs & FLAG_SERIAL );\n\n\tif( hn->flgs & FLAG_PRINT )\n\t\tprintf( \"print, \" );\n\telse\n\t\tprintf( \"noprint, \" );\n\n\tif( hn->flgs & FLAG_DEBUG )\n\t\tprintf( \"debug, \" );\n\telse\n\t\tprintf( \"nodebug, \" );\n\n\tif( hn->flgs & FLAG_MARK )\n\t\tprintf( \"marked, \" );\n\telse\n\t\tprintf( \"notmarked, \" );\n\n\tprintf( \"%s \", decode_NodeType( hn->type ) );\n\n\tswitch( hn->type ) {\n\tcase TAG_APPL:\n\tcase TAG_CONS:\n\t\tprintf( \"\\n\" );\n\t\tprintf( \"%s\", spc( nsp ) );\n\t\tprintf( \"left:  \" );\n\t\tprint_element( nsp, hn->ltype, hn->body.ptrs.left );\n\n\t\tprintf( \"\\n\" );\n\t\tprintf( \"%s\", spc( nsp ) );\n\t\tprintf( \"right: \" );\n\t\tprint_element( nsp, hn->rtype, hn->body.ptrs.right );\n\n\t\tprintf( \"\\n\" );\n\n\t\tbreak;\n\n\tcase TAG_DOUBLE:\n\t\tprintf( \"real \\\"%g\\\"\\n\", hn->body.num );\n\t\tbreak;\n\n\tcase TAG_CLASS:\n\t\tprintf( \"instance-of-class \\\"%s\\\"\\n\",\n\t\t\tIOBJECT( hn->body.ptrs.left )->name );\n\t\tprintf( \" secrets=(\" );\n\t\tprint_element( nsp, \n\t\t\tGETRIGHT( hn )->ltype, \n\t\t\tGETRIGHT( hn )->body.ptrs.left );\n\t\tprintf( \") members=(\" );\n\t\tprint_element( nsp, \n\t\t\tGETRIGHT( hn )->rtype, \n\t\t\tGETRIGHT( hn )->body.ptrs.right );\n\t\tprintf( \")\\n\" );\n\t\tbreak;\n\n\tcase TAG_COMPLEX:\n\t\tprintf( \"complex \\\"(%g,%g)\\\"\\n\", \n\t\t\tGETLEFT( hn )->body.num, GETRIGHT( hn )->body.num );\n\t\tbreak;\n\n\tcase TAG_GEN:\n\t\tprintf( \"list generator start=%g next=%g final=%g\\n\", \n\t\t\tGETLEFT( hn )->body.num, \n\t\t\tGETLEFT( GETRIGHT( hn ) )->body.num, \n\t\t\tGETRIGHT( GETRIGHT( hn ) )->body.num );\n\t\tbreak;\n\n\tcase TAG_FILE:\n\t\tprintf( \"list generator file=%s\\n\", \n\t\t\tMANAGEDFILE( GETLEFT( hn ) )->file->fname );\n\t\tbreak;\n\n\tcase TAG_FREE:\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n}\n\n/* Pretty-print a const.\n */\nstatic void\ndump_parseconst( ParseConst *pc )\n{\n\tswitch( pc->type ) {\n\tcase PARSE_CONST_NUM:\n\t\tprintf( \"%G\", pc->val.num );\n\t\tbreak;\n\n\tcase PARSE_CONST_COMPLEX:\n\t\tprintf( \"%Gj\", pc->val.num );\n\n\tcase PARSE_CONST_STR:\n\t\tprintf( \"\\\"%s\\\"\", pc->val.str );\n\t\tbreak;\n\n\tcase PARSE_CONST_BOOL:\n\t\tprintf( \"%s\", bool_to_char( pc->val.bool ) );\n\t\tbreak;\n\n\tcase PARSE_CONST_CHAR:\n\t\tprintf( \"'%c'\", pc->val.ch );\n\t\tbreak;\n\n\tcase PARSE_CONST_ELIST:\n\t\tprintf( \"[]\" );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n}\n\n/* Dump a parse tree. \n */\nvoid *\ndump_tree( ParseNode *n )\n{\n\tswitch( n->type ) {\n\tcase NODE_NONE:\n\t\tprintf( \"node->type == NODE_NONE\\n\" );\n\t\tbreak;\n\n\tcase NODE_APPLY:\n\t\tprintf( \"Function application\\n\" );\n\t\tprintf( \"LHS = \" );\n\t\t(void) dump_tree( n->arg1 );\n\t\tprintf( \"RHS = \" );\n\t\t(void) dump_tree( n->arg2 );\n\t\tbreak;\n\n\tcase NODE_CLASS:\n\t\tprintf( \"Class: \" );\n\t\t(void) dump_compile_tiny( n->klass );\n\t\tprintf( \"\\n\" );\n\t\tbreak;\n\n\tcase NODE_LEAF:\n\t\tprintf( \"Leaf symbol (%p): \", n->leaf );\n\t\t(void) dump_tiny( n->leaf );\n\t\tprintf( \"\\n\" );\n\t\tbreak;\n\n\tcase NODE_TAG:\n\t\tprintf( \"Tag: %s\\n\", n->tag );\n\t\tbreak;\n\n\tcase NODE_BINOP:\n\t\tprintf( \"Binary operator %s\\n\", decode_BinOp( n->biop ) );\n\t\tprintf( \"Left expression:\\n\" );\n\t\t(void) dump_tree( n->arg1 );\n\t\tprintf( \"Right expression:\\n\" );\n\t\t(void) dump_tree( n->arg2 );\n\t\tbreak;\n\n\tcase NODE_UOP:\n\t\tprintf( \"Unary operator %s\\n\", decode_UnOp( n->uop ) );\n\t\tprintf( \"Arg expression:\\n\" );\n\t\t(void) dump_tree( n->arg1 );\n\t\tbreak;\n\n\tcase NODE_CONST:\n\t\tprintf( \"Constant \" );\n\t\tdump_parseconst( &n->con );\n\t\tprintf( \"\\n\" );\n\t\tbreak;\n\n\tcase NODE_GENERATOR:\n\t\tprintf( \"List generator\\n\" );\n\t\tprintf( \"Start:\\n\" );\n\t\t(void) dump_tree( n->arg1 );\n\t\tif( n->arg2 ) {\n\t\t\tprintf( \"Next:\\n\" );\n\t\t\t(void) dump_tree( n->arg2 );\n\t\t}\n\t\tif( n->arg3 ) {\n\t\t\tprintf( \"End:\\n\" );\n\t\t\t(void) dump_tree( n->arg3 );\n\t\t}\n\t\tbreak;\n\n\tcase NODE_COMPOSE:\n\t\tprintf( \"Function compose\\n\" );\n\t\tprintf( \"Left:\\n\" );\n\t\t(void) dump_tree( n->arg1 );\n\t\tprintf( \"Right:\\n\" );\n\t\t(void) dump_tree( n->arg2 );\n\t\tbreak;\n\n\tcase NODE_LISTCONST:\n\tcase NODE_SUPER:\n\t\tif( n->type == NODE_LISTCONST )\n\t\t\tprintf( \"List constant\\n\" );\n\t\telse\n\t\t\tprintf( \"Superclass construct\\n\" );\n\n\t\tprintf( \"***[\\n\" );\n\t\tslist_map_rev( n->elist, (SListMapFn) dump_tree, NULL );\n\t\tprintf( \"***]\\n\" );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\ndump_link_expr( LinkExpr *le )\n{\n\tdump_expr_tiny( le->expr );\n\tprintf( \" count = %d ; \", le->count );\n\n\treturn( NULL );\n}\n\nvoid *\ndump_link( Link *link )\n{\n\tprintf( \"link->parent = \" );\n\tsymbol_name_print( link->parent );\n\tif( link->parent->dirty )\n\t\tprintf( \"(dirty)\" );\n\tprintf( \"\\n\" );\n\n\tprintf( \"link->child = \" );\n\tsymbol_name_print( link->child );\n\tif( link->child->dirty )\n\t\tprintf( \"(dirty)\" );\n\tprintf( \"\\n\" );\n\n\tprintf( \"link->serial = %d\\n\", link->serial );\n\n\tprintf( \"link->static_links = \" );\n\tslist_map( link->static_links, (SListMapFn) dump_link_expr, NULL );\n\tprintf( \"\\n\" );\n\tprintf( \"link->dynamic_links = \" );\n\tslist_map( link->dynamic_links, (SListMapFn) dump_link_expr, NULL );\n\tprintf( \"\\n\" );\n\n\treturn( NULL );\n}\n\nvoid\ndump_links( Symbol *sym )\n{\n\tsymbol_name_print( sym );\n\tprintf( \"->topchildren = \\n\" );\n\tslist_map( sym->topchildren, (SListMapFn) dump_link, NULL );\n\n\tsymbol_name_print( sym );\n\tprintf( \"->topparents = \\n\" );\n\tslist_map( sym->topparents, (SListMapFn) dump_link, NULL );\n}\n\nvoid \ndump_symbol_heap( Symbol *sym )\n{\n\tprintf( \"symbol \" );\n\tsymbol_name_print( sym );\n\tprintf( \"has graph:\\n\" );\n\tif( sym->expr ) \n\t\tpgraph( &sym->expr->root );\n\tprintf( \"\\n\" );\n}\n\n#endif /*DEBUG*/\n"
  },
  {
    "path": "src/dump.h",
    "content": "/* Decls for dump.c\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\nchar *decode_BinOp( BinOp op );\nchar *decode_UnOp( UnOp op );\nchar *decode_NodeType( NodeType tag );\nchar *decode_CombinatorType( CombinatorType comb );\nchar *decode_SymbolType( SymbolType t );\nchar *decode_SymbolType_user( SymbolType t );\n\nvoid *dump_tiny( Symbol *sym );\nvoid *dump_symbol( Symbol *sym );\nvoid dump_expr( Expr *expr );\nvoid dump_compile( Compile *compile );\nvoid dump_symbol_table( void );\nvoid *dump_kit( Toolkit *kit );\nSymbol *sym( char *name );\nvoid psym( char *name );\nvoid psymv( char *name );\nvoid pgraph( PElement *graph );\n\nvoid graph_heap( int nsp, HeapNode *hn );\nvoid graph_test( Heap *heap );\n\nvoid *dump_tree( ParseNode *n );\n\nvoid dump_links( Symbol *sym );\nvoid *dump_link( Link *link );\n\nvoid dump_symbol_heap( Symbol *sym );\n"
  },
  {
    "path": "src/editview.c",
    "content": "/* a view of a text thingy\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GraphicviewClass *parent_class = NULL;\n\nstatic void\neditview_link( View *view, Model *model, View *parent )\n{\n\tEditview *editview = EDITVIEW( view );\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\tif( GRAPHICVIEW( view )->sview )\n\t\tgtk_size_group_add_widget( GRAPHICVIEW( view )->sview->group,   \n\t\t\teditview->label );\n}\n\nstatic void \neditview_refresh( vObject *vobject )\n{\n\tEditview *editview = EDITVIEW( vobject );\n\n#ifdef DEBUG\n\tprintf( \"editview_refresh:\\n\" );\n#endif /*DEBUG*/\n\n\tif( vobject->iobject->caption )\n\t\tset_glabel( editview->label, _( \"%s:\" ), \n\t\t\tvobject->iobject->caption );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\neditview_class_init( EditviewClass *class )\n{\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = editview_refresh;\n\n\tview_class->link = editview_link;\n}\n\n/* Detect cancel in a text field.\n */\nstatic gboolean\neditview_event_cb( GtkWidget *widget, GdkEvent *ev, Editview *editview )\n{\n\tgboolean handled;\n\n\thandled = FALSE;\n\n        if( ev->key.keyval == GDK_Escape ) {\n\t\thandled = TRUE;\n\n\t\t/* Zap model value back into edit box.\n\t\t */\n\t\tvobject_refresh_queue( VOBJECT( editview ) );\n\t}\n\n        return( handled );\n}\n\nstatic void\neditview_activate_cb( GtkWidget *wid, Editview *editview )\n{\n    \tExpr *expr = HEAPMODEL( VOBJECT( editview )->iobject )->row->expr;\n\n\t/* If we've been changed, we'll be on the scannable list ... just\n\t * recomp.\n\t */\n\tsymbol_recalculate_all();\n\n\tif( expr->err ) {\n\t\texpr_error_get( expr );\n\t\tiwindow_alert( wid, GTK_MESSAGE_ERROR );\n\t}\n}\n\nstatic void\neditview_init( Editview *editview )\n{\n\tGtkWidget *hbox;\n\n\tgtk_container_set_border_width( GTK_CONTAINER( editview ), 2 );\n\n\thbox = gtk_hbox_new( FALSE, 12 );\n        gtk_box_pack_start( GTK_BOX( editview ), hbox, TRUE, FALSE, 0 );\n\n        editview->label = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( editview->label ), 0, 0.5 );\n\tgtk_box_pack_start( GTK_BOX( hbox ), editview->label, FALSE, FALSE, 2 );\n\n        editview->text = gtk_entry_new();\n\tgtk_box_pack_start( GTK_BOX( hbox ), editview->text, TRUE, TRUE, 0 );\n        set_tooltip( editview->text, _( \"Escape to cancel edit, \"\n                \"press Return to accept edit and recalculate\" ) );\n        gtk_signal_connect_object( GTK_OBJECT( editview->text ), \"changed\",\n                GTK_SIGNAL_FUNC( view_changed_cb ), GTK_OBJECT( editview ) );\n        gtk_signal_connect( GTK_OBJECT( editview->text ), \"activate\",\n                GTK_SIGNAL_FUNC( editview_activate_cb ), editview );\n        gtk_signal_connect( GTK_OBJECT( editview->text ), \"event\",\n                GTK_SIGNAL_FUNC( editview_event_cb ), editview );\n\n        gtk_widget_show_all( hbox );\n}\n\nGtkType\neditview_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Editview\",\n\t\t\tsizeof( Editview ),\n\t\t\tsizeof( EditviewClass ),\n\t\t\t(GtkClassInitFunc) editview_class_init,\n\t\t\t(GtkObjectInitFunc) editview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_GRAPHICVIEW, &info );\n\t}\n\n\treturn( type );\n}\n\nvoid\neditview_set_entry( Editview *editview, const char *fmt, ... )\n{\n\tva_list ap;\n\tchar buf[1000];\n\n\tva_start( ap, fmt );\n\t(void) im_vsnprintf( buf, 1000, fmt, ap );\n\tva_end( ap );\n\n\t/* Make sure we don't trigger \"changed\" when we zap in the\n\t * text.\n\t */\n\tgtk_signal_handler_block_by_data( \n\t\tGTK_OBJECT( editview->text ), editview );\n\tset_gentry( editview->text, \"%s\", buf );\n\tgtk_signal_handler_unblock_by_data( \n\t\tGTK_OBJECT( editview->text ), editview );\n}\n"
  },
  {
    "path": "src/editview.h",
    "content": "/* abstract base class for text editable view widgets\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_EDITVIEW (editview_get_type())\n#define EDITVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_EDITVIEW, Editview ))\n#define EDITVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_EDITVIEW, EditviewClass ))\n#define IS_EDITVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_EDITVIEW ))\n#define IS_EDITVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_EDITVIEW ))\n\ntypedef struct _Editview {\n\tGraphicview parent_object;\n\n\t/* Widgets.\n\t */\n        GtkWidget *label;\t\t/* Display caption here */\n        GtkWidget *text;\t\t/* Edit value here */\n} Editview;\n\ntypedef struct _EditviewClass {\n\tGraphicviewClass parent_class;\n\n\t/* My methods.\n\t */\n} EditviewClass;\n\nGtkType editview_get_type( void );\nvoid editview_set_entry( Editview *editview, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\n"
  },
  {
    "path": "src/error.c",
    "content": "/* ierror window\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic LogClass *parent_class = NULL;\n\nstatic void *\nierror_print( Expr *expr, iError *ierror, gboolean *found )\n{\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\texpr_error_print( expr, &buf );\n\tlog_text( LOG( ierror ), vips_buf_all( &buf ) );\n\t*found = TRUE;\n\n\treturn( NULL );\n}\n\nstatic void\nierror_show_all( iError *ierror )\n{\n\tgboolean found;\n\n\tfound = FALSE;\n\tslist_map2( expr_error_all,\n\t\t(SListMap2Fn) ierror_print, ierror, &found );\n\tif( !found ) {\n\t\tlog_text( LOG( ierror ), _( \"No ierrors found.\" ) );\n\t\tlog_text( LOG( ierror ), \"\\n\" );\n\t}\n}\n\nstatic void\nierror_show_all_action_cb( GtkAction *action, iError *ierror )\n{\n\tierror_show_all( ierror );\n}\n\nstatic void *\nunresolved_print_tool( Tool *tool, iError *ierror, gboolean *found )\n{\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\ttool_linkreport_tool( tool, &buf, found );\n\tlog_text( LOG( ierror ), vips_buf_all( &buf ) );\n\n\treturn( NULL );\n}\n\nstatic void *\nunresolved_print( Toolkit *kit, iError *ierror, gboolean *found )\n{\n\ttoolkit_map( kit, (tool_map_fn) unresolved_print_tool, ierror, found );\n\n\treturn( NULL );\n}\n\nstatic void\nunresolved_show_all( iError *ierror )\n{\n\tgboolean found;\n\n\tfound = FALSE;\n\t(void) toolkitgroup_map( ierror->kitg,\n\t\t(toolkit_map_fn) unresolved_print, ierror, &found );\n\tif( !found ) {\n\t\tlog_text( LOG( ierror ), _( \"No unresolved symbols found.\" ) );\n\t\tlog_text( LOG( ierror ), \"\\n\" );\n\t}\n}\n\nstatic void\nunresolved_show_all_action_cb( GtkAction *action, iError *ierror )\n{\n\tunresolved_show_all( ierror );\n}\n\n/* Our actions.\n */\nstatic GtkActionEntry ierror_actions[] = {\n\t{ \"Clear\", \n\t\tNULL, N_( \"_Clear\" ), NULL, \n\t\tN_( \"Clear ierror window\" ), \n\t\tG_CALLBACK( log_clear_action_cb ) },\n\n\t{ \"iErrors\", \n\t\tNULL, N_( \"List _iErrors\" ), NULL, \n\t\tN_( \"Search for all ierrors\" ), \n\t\tG_CALLBACK( ierror_show_all_action_cb ) },\n\n\t{ \"Unresolved\", \n\t\tNULL, N_( \"List _Unresolved\" ), NULL, \n\t\tN_( \"Search for all unresolved references\" ), \n\t\tG_CALLBACK( unresolved_show_all_action_cb ) }\n};\n\nstatic const char *ierror_menubar_ui_description =\n\"<ui>\"\n\"  <menubar name='iErrorMenubar'>\"\n\"    <menu action='FileMenu'>\"\n\"      <menuitem action='Clear'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Close'/>\"\n\"      <menuitem action='Quit'/>\"\n\"    </menu>\"\n\"    <menu action='ViewMenu'>\"\n\"      <menuitem action='iErrors'/>\"\n\"      <menuitem action='Unresolved'/>\"\n\"    </menu>\"\n\"    <menu action='HelpMenu'>\"\n\"      <menuitem action='Guide'/>\"\n\"      <menuitem action='About'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Homepage'/>\"\n\"    </menu>\"\n\"  </menubar>\"\n\"</ui>\";\n\nstatic void\nierror_class_init( iErrorClass *class )\n{\n\tLogClass *log_class = (LogClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tlog_class->actions = ierror_actions;\n\tlog_class->n_actions = IM_NUMBER( ierror_actions );\n\tlog_class->action_name = \"iErrorActions\";\n\tlog_class->ui_description = ierror_menubar_ui_description;\n\tlog_class->menu_bar_name = \"/iErrorMenubar\";\n}\n\nstatic void\nierror_init( iError *ierror )\n{\n}\n\nGtkType\nierror_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"iError\",\n\t\t\tsizeof( iError ),\n\t\t\tsizeof( iErrorClass ),\n\t\t\t(GtkClassInitFunc) ierror_class_init,\n\t\t\t(GtkObjectInitFunc) ierror_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_LOG, &info );\n\t}\n\n\treturn( type );\n}\n\nstatic void\nierror_link( iError *ierror, Toolkitgroup *kitg )\n{\n\tierror->kitg = kitg;\n\n\tdestroy_if_destroyed( G_OBJECT( ierror ), \n\t\tG_OBJECT( kitg ), (DestroyFn) gtk_widget_destroy );\n        iwindow_set_title( IWINDOW( ierror ), \n\t\t_( \"iError - %s\" ), IOBJECT( kitg )->name );\n\tgtk_window_set_default_size( GTK_WINDOW( ierror ), 640, 480 );\n\tiwindow_set_size_prefs( IWINDOW( ierror ), \n\t\t\"IERROR_WIDTH\", \"IERROR_HEIGHT\" );\n\tiwindow_build( IWINDOW( ierror ) );\n}\n\niError *\nierror_new( Toolkitgroup *kitg )\n{\n\tiError *ierror = gtk_type_new( TYPE_IERROR );\n\n\tierror_link( ierror, kitg );\n\tierror_show_all( ierror );\n\tunresolved_show_all( ierror );\n\n\treturn( ierror );\n}\n"
  },
  {
    "path": "src/error.h",
    "content": "/* Decls for ierror.c ... show all ierrors\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_IERROR (ierror_get_type())\n#define IERROR( obj ) (GTK_CHECK_CAST( (obj), TYPE_IERROR, iError ))\n#define IERROR_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_IERROR, iErrorClass ))\n#define IS_IERROR( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IERROR ))\n#define IS_IERROR_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_IERROR ))\n\nstruct _iError {\n\tLog parent_class;\n\n\tToolkitgroup *kitg;\t/* Where we search for link ierrors */\n};\n\ntypedef struct _iErrorClass {\n\tLogClass parent_class;\n\n\t/* My methods.\n\t */\n} iErrorClass;\n\nGtkType ierror_get_type( void );\niError *ierror_new( Toolkitgroup *kitg );\n\n"
  },
  {
    "path": "src/expr.c",
    "content": "/* Expressions!\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* Trace error_set()/_clear().\n#define DEBUG_ERROR\n */\n\n/* Trace expr_clone() \n#define DEBUG_CLONE\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* Our signals. \n */\nenum {\n\tSIG_NEW_VALUE,\t\t/* new value for root */\n\tSIG_LAST\n};\n\nstatic iContainerClass *parent_class = NULL;\n\nstatic guint expr_signals[SIG_LAST] = { 0 };\n\n/* Set of expressions containing errors.\n */\nGSList *expr_error_all = NULL;\n\nvoid *\nexpr_error_print( Expr *expr, VipsBuf *buf )\n{\n\tg_assert( expr->err );\n\n\tvips_buf_appendf( buf, _( \"error in \\\"%s\\\"\" ), \n\t\tIOBJECT( expr->sym )->name );\n\tif( expr->sym->tool ) \n\t\ttool_error( expr->sym->tool, buf );\n\telse if( expr->row ) {\n\t\tWorkspace *ws = expr->row->ws;\n\t\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\n\t\tvips_buf_appendf( buf, \" (\" );\n\t\trow_qualified_name( expr->row, buf );\n\t\tif( FILEMODEL( wsg )->filename )\n\t\t\tvips_buf_appendf( buf, \" - %s\", \n\t\t\t\tFILEMODEL( wsg )->filename );\n\t\tvips_buf_appendf( buf, \")\" );\n\t}\n\n\t/* Don't show error_top, it's just a summary of error_sub.\n\t */\n\tvips_buf_appendf( buf, \": %s\\n\", expr->error_sub );\n\n\treturn( NULL );\n}\n\nstatic Expr *\nexpr_map_all_sub( Symbol *sym, map_expr_fn fn, void *a )\n{\n\tif( !sym->expr )\n\t\treturn( NULL );\n\telse \n\t\treturn( expr_map_all( sym->expr, fn, a ) );\n}\n\n/* Apply a function to a expr ... and any local exprs.\n */\nExpr *\nexpr_map_all( Expr *expr, map_expr_fn fn, void *a )\n{\n\tExpr *res;\n\n\t/* Apply to this expr.\n\t */\n\tif( (res = fn( expr, a, NULL )) )\n\t\treturn( res );\n\n\t/* And over any locals.\n\t */\n\tif( expr->compile && (res = (Expr *) \n\t\ticontainer_map( ICONTAINER( expr->compile ), \n\t\t\t(icontainer_map_fn) expr_map_all_sub, \n\t\t\t(void *) fn, a )) )\n\t\treturn( res );\n\n\treturn( NULL );\n}\n\nvoid *\nexpr_name_print( Expr *expr )\n{\n\tprintf( \"expr(%p) \", expr );\n\tsymbol_name_print( expr->sym );\n\n\tif( expr->row ) {\n\t\tprintf( \"(row \" );\n\t\trow_name_print( expr->row );\n\t\tprintf( \") \" );\n\t}\n\n\treturn( NULL );\n}\n\nvoid\nexpr_name( Expr *expr, VipsBuf *buf )\n{\n\tif( expr->row ) \n\t\trow_qualified_name( expr->row, buf );\n\telse\n\t\tsymbol_qualified_name( expr->sym, buf );\n}\n\nExpr *\nexpr_get_parent( Expr *expr )\n{\n\tSymbol *sym_parent = symbol_get_parent( expr->sym );\n\n\tif( !sym_parent )\n\t\treturn( NULL );\n\n\treturn( sym_parent->expr );\n}\n\n/* Find the enclosing expr in the dynamic scope hierarchy.\n */\nstatic Expr *\nexpr_get_parent_dynamic( Expr *expr )\n{\n\tRow *row;\n\n\tif( !expr->row )\n\t\treturn( expr_get_parent( expr ) );\n\telse if( (row = HEAPMODEL( expr->row )->row) )\n\t\t/* Enclosing row expr.\n\t\t */\n\t\treturn( row->expr );\n\telse {\n\t\t/* Enclosing workspace expr.\n\t\t */\n\t\tWorkspace *ws = expr->row->top_col->ws;\n\n\t\treturn( ws->sym->expr );\n\t}\n}\n\n/* Look back up to find the root expr.\n */\nExpr *\nexpr_get_root( Expr *expr )\n{\n\tif( is_top( expr->sym ) )\n\t\treturn( expr );\n\telse\n\t\treturn( expr_get_root( expr_get_parent( expr ) ) );\n}\n\n/* Look back up to find the root expr using the dynamic hierarchy (if it's\n * there).\n */\nExpr *\nexpr_get_root_dynamic( Expr *expr )\n{\n\tExpr *parent;\n\n\tif( is_top( expr->sym ) )\n\t\treturn( expr );\n\telse if( expr->row && expr->row->top_row && expr->row->top_row->expr )\n\t\treturn( expr->row->top_row->expr );\n\telse if( (parent = expr_get_parent_dynamic( expr )) )\n\t\treturn( expr_get_root_dynamic( parent ) );\n\telse\n\t\treturn( NULL ); \n}\n\n/* Is an expr part of a row, including enclosing exprs. \n *\n * For example, row A1 could be \"[x::x<-A2]\", that would be expanded to \n * something like \n * \"$lcomp0 {$lcomp0 = foldr $f0 [] A2 {$f0 x $sofar = x : $sofar}}\"\n * Now, row A1 depends on A2, but expr A1 will not ... it's $lcomp0, the local\n * expr of A1, that will get called for expr_dirty.\n *\n * Return NULL for expr is not a row and has no enclosing rows.\n */\nstatic Row *\nexpr_get_row( Expr *expr )\n{\n\tif( expr->row )\n\t\treturn( expr->row );\n\telse if( is_top( expr->sym ) )\n\t\treturn( NULL );\n\telse\n\t\treturn( expr_get_row( expr_get_parent( expr ) ) );\n}\n\nvoid \nexpr_new_value( Expr *expr )\n{\n#ifdef DEBUG\n{\n\tPElement *root = &expr->root;\n\n\tprintf( \"expr_new_value: \" );\n\tsymbol_name_print( expr->sym );\n\tprintf( \": \" );\n\tgraph_pointer( root );\n}\n#endif /*DEBUG*/\n\n\tg_signal_emit( G_OBJECT( expr ), expr_signals[SIG_NEW_VALUE], 0 );\n}\n\n/* An expr has lost a value.\n */\nvoid\nexpr_value_destroy( Expr *expr )\n{\n\t/* Break ImageInfo link (if any).\n\t */\n\tif( expr->imageinfo )\n\t\timageinfo_expr_remove( expr, expr->imageinfo );\n}\n\n/* Clean up an expr, ready to have a new def parsed into it.\n */\nvoid *\nexpr_strip( Expr *expr )\n{\n\texpr_error_clear( expr );\n\n\t/* Break top links we're part of.\n\t */\n\tif( slist_map( expr->static_links, \n\t\t(SListMapFn) link_expr_destroy, NULL ) )\n\t\treturn( expr );\n\tif( slist_map( expr->dynamic_links, \n\t\t(SListMapFn) link_expr_destroy, NULL ) )\n\t\treturn( expr );\n\tg_assert( !expr->static_links );\n\tg_assert( !expr->dynamic_links );\n\n\t/* Junk error stuff. \n\t */\n\tIM_FREE( expr->error_top );\n\tIM_FREE( expr->error_sub );\n\n\t/* Unref the compile.\n\t */\n\tif( expr->compile )\n\t\t(void) compile_expr_link_break( expr->compile, expr );\n\n\treturn( NULL );\n}\n\nstatic void \nexpr_dispose( GObject *gobject )\n{\n\tExpr *expr = EXPR( gobject );\n\tSymbol *sym = expr->sym;\n\n#ifdef DEBUG\n\tprintf( \"expr_dispose: \" );\n\texpr_name_print( expr );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\texpr_strip( expr );\n\n\t/* Break the value link.\n\t */\n\texpr_value_destroy( expr );\n\n\t/* Unlink from symbol.\n\t */\n\tif( sym->expr == expr )\n\t\tsym->expr = NULL;\n\n\tif( expr->row ) {\n\t\tRow *row = expr->row;\n\n\t\t/* If this is the sym for a top row, kill the row too.\n\t\t * Otherwise just break the link and wait for the next row\n\t\t * refresh to do the kill for us.\n\t\t */\n\t\tif( row == row->top_row ) {\n\t\t\tIDESTROY( row );\n\t\t}\n\t\telse {\n\t\t\trow->expr = NULL;\n\t\t\trow->sym = NULL;\n\n\t\t\texpr->row = NULL;\n\n\t\t\t/* Make sure we will re-parse and compile any text\n\t\t\t * with this sym that might have been modified from\n\t\t\t * the default.\n\t\t\t */\n\t\t\tif( row->child_rhs && row->child_rhs->itext ) {\n\t\t\t\tiText *itext = ITEXT( row->child_rhs->itext );\n\n\t\t\t\tif( itext->edited )\n\t\t\t\t\theapmodel_set_modified( \n\t\t\t\t\t\tHEAPMODEL( itext ), TRUE );\n\t\t\t}\n\t\t}\n\t}\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\nexpr_info( iObject *iobject, VipsBuf *buf )\n{\n\tExpr *expr = EXPR( iobject );\n\n\tif( expr->err ) {\n\t\tvips_buf_appends( buf, _( \"Error\" ) );\n\t\tvips_buf_appendf( buf, \": %s\\n%s\\n\", \n\t\t\texpr->error_top, expr->error_sub );\n\t}\n}\n\nstatic void\nexpr_real_new_value( Expr *expr )\n{\n\tPElement *root = &expr->root;\n\n\texpr_value_destroy( expr );\n\tif( PEISIMAGE( root ) && PEGETII( root ) ) \n\t\timageinfo_expr_add( PEGETII( root ), expr );\n\n\t/* If this is the main expr for this symbol, signal new value there\n\t * too.\n\t */\n\tif( expr->sym->expr == expr )\n\t\tsymbol_new_value( expr->sym );\n}\n\nstatic void\nexpr_class_init( ExprClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\texpr_signals[SIG_NEW_VALUE] = g_signal_new( \"new_value\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ExprClass, new_value ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\n\t/* Init methods.\n\t */\n\tgobject_class->dispose = expr_dispose;\n\n\tiobject_class->info = expr_info;\n\n\tclass->new_value = expr_real_new_value;\n\n\t/* Static init.\n\t */\n}\n\nstatic void\nexpr_init( Expr *expr )\n{\n\texpr->sym = NULL;\n\texpr->row = NULL;\n\texpr->compile = NULL;\n\n\texpr->static_links = NULL;\n\texpr->dynamic_links = NULL;\n\n\texpr->imageinfo = NULL;\n\n\texpr->err = FALSE;\n\texpr->error_top = NULL;\n\texpr->error_sub = NULL;\n}\n\nGType\nexpr_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ExprClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) expr_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Expr ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) expr_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_ICONTAINER, \n\t\t\t\"Expr\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nExpr *\nexpr_new( Symbol *sym )\n{\n\tExpr *expr;\n\n\texpr = EXPR( g_object_new( TYPE_EXPR, NULL ) );\n\n\texpr->sym = sym;\n\tPEPOINTE( &expr->root, &sym->base );\n\ticontainer_child_add( ICONTAINER( sym ), ICONTAINER( expr ), -1 );\n\n#ifdef DEBUG\n\tprintf( \"expr_new: \" );\n\texpr_name_print( expr );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\treturn( expr );\n}\n\n\n/* Clone an existing expr. \n */\nExpr *\nexpr_clone( Symbol *sym )\n{\n\tExpr *expr;\n\n\tif( sym->expr && sym->expr->compile ) {\n\t\t/* Make a new expr, share the compile.\n\t\t */\n                expr = expr_new( sym );\n\t\tcompile_expr_link_make( sym->expr->compile, expr );\n\t}\n\telse {\n\t\t/* No existing expr to copy, make a bare one for the\n\t\t * row, at the same scope level as sym.\n\t\t */\n                expr = expr_new( sym );\n\t}\n\n\treturn( expr );\n}\n\n/* Mark an expression as containing an error, save the error buffers.\n */\nvoid *\nexpr_error_set( Expr *expr )\n{\n\t/* Was not in error? Add to error set.\n\t */\n\tif( !expr->err ) {\n#ifdef DEBUG_ERROR\n\t\tprintf( \"expr_error_set: error in \" );\n\t\tsymbol_name_print( expr->sym );\n\t\tprintf( \": %s %s\\n\", error_get_top(), error_get_sub() );\n#endif /*DEBUG_ERROR*/\n\n\t\tIM_SETSTR( expr->error_top, error_get_top() );\n\t\tIM_SETSTR( expr->error_sub, error_get_sub() );\n\n\t\t/* Zap the value of the expr ... it may contain pointers to\n\t\t * dead stuff.\n\t\t */\n\t\tPEPUTP( &expr->root, ELEMENT_NOVAL, (void *) 99 );\n\n\t\texpr_error_all = g_slist_prepend( expr_error_all, expr );\n\t\texpr->err = TRUE;\n\t\tif( expr->row )\n\t\t\trow_error_set( expr->row );\n\n\t\t/* If this is the value of a top-level sym, note state\n\t\t * change on symbol.\n\t\t */\n\t\tif( is_top( expr->sym ) && expr->sym->expr == expr )\n\t\t\tsymbol_state_change( expr->sym );\n\t}\n\n\treturn( NULL );\n}\n\n/* Extract the error from an expression.\n */\nvoid\nexpr_error_get( Expr *expr )\n{\n\tif( !expr->err )\n\t\terror_clear();\n\telse {\n\t\tg_assert( expr->error_top );\n\t\tg_assert( expr->error_sub );\n\n\t\terror_top( \"%s\", expr->error_top );\n\t\terror_sub( \"%s\", expr->error_sub );\n\t}\n}\n\n/* Clear error state.\n */\nvoid\nexpr_error_clear( Expr *expr )\n{\n\tif( expr->err ) {\n#ifdef DEBUG_ERROR\n\t\tprintf( \"expr_error_clear: \" );\n\t\tsymbol_name_print( expr->sym );\n\t\tprintf( \"\\n\"  );\n#endif /*DEBUG_ERROR*/\n\n\t\texpr->err = FALSE;\n\t\texpr_error_all = g_slist_remove( expr_error_all, expr );\n\t\tif( expr->row )\n\t\t\trow_error_clear( expr->row );\n\n\t\tif( is_top( expr->sym ) && expr->sym->expr == expr )\n\t\t\tsymbol_state_change( expr->sym );\n\t}\n}\n\n/* Mark an expr dirty.\n *\n * Two cases: if expr has a row, this is part of a display. Use the row\n * stuff to mark this expr dirty. Then use symbol_dirty() to mark on from the\n * root of this row.\n *\n * Case two: this must be an expr inside a top-level ... just\n * symbol_dirty() on from that top level.\n *\n * FIXME ... we should be able to scrap this expr_get_root() ... we want the\n * 'parent' field in the Link we are probably being called from.\n */\nvoid *\nexpr_dirty( Expr *expr, int serial )\n{\n\tRow *row;\n\n#ifdef DEBUG\n\tprintf( \"expr_dirty: \" );\n\tsymbol_name_print( expr->sym );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( (row = expr_get_row( expr )) &&\n\t\trow->top_row->sym ) {\n\t\tSymbol *top_sym = row->top_row->sym;\n\n\t\trow_dirty( row, TRUE );\n\t\tsymbol_dirty( top_sym, serial );\n\t}\n\telse\n\t\tsymbol_dirty( expr_get_root( expr )->sym, serial );\n\n\treturn( NULL );\n}\n\nvoid *\nexpr_dirty_intrans( Expr *expr, int serial )\n{\n\tif( expr->row &&\n\t\texpr->row->top_row->sym ) {\n\t\trow_dirty_intrans( expr->row, TRUE );\n\t\tsymbol_dirty( expr->row->top_row->sym, serial );\n\t}\n\telse\n\t\tsymbol_dirty_intrans( expr->sym, serial );\n\n\treturn( NULL );\n}\n\nvoid\nexpr_tip_sub( Expr *expr, VipsBuf *buf )\n{\n\tCompile *compile = expr->compile;\n\n\tif( is_top( expr->sym ) ) {\n\t\tvips_buf_appends( buf, _( \"top level\" ) );\n\t\tvips_buf_appends( buf, \" \" );\n\t}\n\n\tif( compile && \n\t\tis_class( compile ) ) {\n\t\tvips_buf_appends( buf, _( \"class\" ) );\n\t\tvips_buf_appends( buf, \" \" );\n\t\tif( compile->nparam == 0 ) {\n\t\t\tvips_buf_appends( buf, _( \"instance\" ) );\n\t\t\tvips_buf_appends( buf, \" \" );\n\t\t}\n\t\telse {\n\t\t\tvips_buf_appends( buf, _( \"definition\" ) );\n\t\t\tvips_buf_appends( buf, \" \" );\n\t\t}\n\n\t\tvips_buf_appendf( buf, \"\\\"%s\\\"\", IOBJECT( expr->sym )->name );\n\t}\n\telse if( expr->sym->type == SYM_PARAM )\n\t\tvips_buf_appendf( buf, _( \"parameter \\\"%s\\\"\" ), \n\t\t\tIOBJECT( expr->sym )->name );\n\telse if( compile ) {\n\t\tif( is_member( expr->sym ) ) {\n\t\t\tvips_buf_appends( buf, _( \"member\" ) );\n\t\t\tvips_buf_appends( buf, \" \" );\n\t\t}\n\n\t\tif( compile->nparam == 0 ) {\n\t\t\tvips_buf_appends( buf, _( \"value\" ) );\n\t\t\tvips_buf_appends( buf, \" \" );\n\t\t}\n\t\telse {\n\t\t\tvips_buf_appends( buf, _( \"function\" ) );\n\t\t\tvips_buf_appends( buf, \" \" );\n\t\t}\n\n\t\tvips_buf_appendf( buf, \"\\\"%s\\\"\", IOBJECT( expr->sym )->name );\n\t}\n\n\tif( !is_top( expr->sym ) ) {\n\t\tvips_buf_appends( buf, \" \" );\n\t\tvips_buf_appends( buf, _( \"of\" ) );\n\t\tvips_buf_appends( buf, \" \" );\n\t\texpr_tip_sub( expr_get_parent( expr ), buf );\n\t}\n}\n\n/* Look at an expr, make a tooltip.\n */\nvoid\nexpr_tip( Expr *expr, VipsBuf *buf )\n{\n\texpr_name( expr, buf ); \n\tvips_buf_appends( buf, \": \" );\n\texpr_tip_sub( expr, buf );\n}\n\n/* Bind unresolved refs in an expr. Bind for every enclosing dynamic scope.\n */\nvoid\nexpr_resolve( Expr *expr )\n{\n\tExpr *top = symbol_root->expr;\n\tExpr *i;\n\n#ifdef DEBUG\n\tprintf( \"expr_resolve: \" );\n\texpr_name_print( expr );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tfor( i = expr; i != top; i = expr_get_parent_dynamic( i ) ) \n\t\t/* May try to resolve out through a parameter.\n\t\t */\n\t\tif( i->compile )\n\t\t\tcompile_resolve_dynamic( expr->compile, i->compile );\n}\n"
  },
  {
    "path": "src/expr.h",
    "content": "/* Expressions.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_EXPR (expr_get_type())\n#define EXPR( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_EXPR, Expr ))\n#define EXPR_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_EXPR, ExprClass))\n#define IS_EXPR( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_EXPR ))\n#define IS_EXPR_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_EXPR ))\n#define EXPR_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_EXPR, ExprClass ))\n\n/* What we track to parse and compile some text. Can have several \n * of these for a symbol, all with different values.\n */\nstruct _Expr {\n\t/* We don't contain anything, but we are contained by Symbol, so we\n\t * need to be an iContainer subclass.\n\t */\n\tiContainer parent_object;\n\n\tSymbol *sym;\t\t/* We are an expr for this symbol, scopewise */\n\tRow *row;\t\t/* (optional) we have this display */\n\n\tCompile *compile;\t/* Our compiled code */\n\n\tGSList *static_links;\t/* Static LinkExprs which reference us */\n\tGSList *dynamic_links;\t/* Dynamic LinkExprs which reference us */\n\n\tPElement root;\t\t/* Pointer to value of this expr */\n\n\t/* Are we recorded as having an Imageinfo as a value? Use this to\n\t * unlink us from the last ii we were linked to.\n\t */\n\tImageinfo *imageinfo;\n\n\tgboolean err;\t\t/* TRUE if there is an error in this expr */\n\tchar *error_top;\n\tchar *error_sub;\n};\n\ntypedef struct _ExprClass {\n\tiContainerClass parent_class;\n\n\t/* \n\n\t\tnew_value\texpr has been recalced and root points to a\n\t\t\t\tnew piece of graph\n\n\t */\n\n\tvoid (*new_value)( Expr *expr );\n} ExprClass;\n\nextern GSList *expr_error_all;\n\nvoid *expr_error_print( Expr *expr, VipsBuf *buf );\n\ntypedef void *(*map_expr_fn)( Expr *, void *, void * );\nExpr *expr_map_all( Expr *expr, map_expr_fn fn, void *a );\n\nvoid *expr_name_print( Expr *expr );\nvoid expr_name( Expr *expr, VipsBuf *buf );\n\nExpr *expr_get_parent( Expr *expr );\nExpr *expr_get_root( Expr *expr );\nExpr *expr_get_root_dynamic( Expr *expr );\n\nGType expr_get_type( void );\nvoid *expr_strip( Expr *expr );\nExpr *expr_new( Symbol *sym );\nExpr *expr_clone( Symbol *sym );\n\n/* Set and clear error state.\n */\nvoid *expr_error_set( Expr *expr );\nvoid expr_error_clear( Expr *expr );\nvoid expr_error_get( Expr *expr );\n\nvoid expr_link_make( Expr *expr, Symbol *child );\nvoid *expr_link_break( Expr *expr, Symbol *child );\nvoid *expr_dirty( Expr *expr, int serial );\nvoid *expr_dirty_intrans( Expr *expr, int serial );\n\nvoid expr_tip( Expr *expr, VipsBuf *buf );\n\nvoid expr_new_value( Expr *expr );\n\nvoid expr_resolve( Expr *expr );\n"
  },
  {
    "path": "src/expression.c",
    "content": "/* an editable expression\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ClassmodelClass *parent_class = NULL;\n\n/* Sub fn. of below.\n */\nstatic void *\nexpression_get_itext_sub( Row *row )\n{\n\tModel *itext;\n\n\t/*\n\n\t\tFIXME ... yuk, map + strcmp\n\n\t\tcould make subcolumn indexed by symbol name? probably not\n\t\tworth it\n\n\t */\n\tif( row->sym && \n\t\tstrcmp( IOBJECT( row->sym )->name, MEMBER_EXPR ) == 0 &&\n\t\trow->child_rhs && \n\t\t(itext = row->child_rhs->itext) )\n\t\t\treturn( itext );\n\n\treturn( NULL );\n}\n\n/* Look down our RHS and try to grab the itext for our MEMBER_EXPR.\n * Expressionview presents this as the editable formula.\n *\n * We can't call the editable member \"value\", since this imples (elsewhere in\n * nip anway) an unboxed value. Our editable member could also be boxed .. so\n * have a different name of reduce confusion a little. Also means we can\n * define an Expression which inherits from expr.\n */\niText *\nexpression_get_itext( Expression *expression )\n{\n\tRow *row = HEAPMODEL( expression )->row;\n\n\tif( row->child_rhs && row->child_rhs->scol ) \n\t\treturn( (iText *) subcolumn_map( \n\t\t\tSUBCOLUMN( row->child_rhs->scol ),\n\t\t\t(row_map_fn) expression_get_itext_sub, \n\t\t\tNULL, NULL ) );\n\n\treturn( NULL );\n}\n\nstatic View *\nexpression_view_new( Model *model, View *parent )\n{\n\treturn( expressionview_new() );\n}\n\nstatic xmlNode *\nexpression_save( Model *model, xmlNode *xnode )\n{\n\txmlNode *xthis;\n\n\tif( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )\n\t\treturn( NULL );\n\n\tif( !set_sprop( xthis, \"caption\", IOBJECT( model )->caption ) )\n\t\treturn( NULL );\n\n\treturn( xthis );\n}\n\nstatic gboolean\nexpression_load( Model *model, \n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\tchar caption[MAX_STRSIZE];\n\n\tg_assert( IS_RHS( parent ) );\n\n\tif( get_sprop( xnode, \"caption\", caption, MAX_STRSIZE ) ) \n\t\tiobject_set( IOBJECT( model ), NULL, caption );\n\n\treturn( MODEL_CLASS( parent_class )->load( model, \n\t\tstate, parent, xnode ) );\n}\n\n/* Update Expression from heap.\n */\nstatic gboolean\nexpression_class_get( Classmodel *classmodel, PElement *root )\n{\n\tchar caption[MAX_STRSIZE];\n\n#ifdef DEBUG\n\tprintf( \"expression_class_get: \" );\n\trow_name_print( HEAPMODEL( classmodel )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( !class_get_member_string( root, MEMBER_CAPTION, \n\t\tcaption, MAX_STRSIZE ) )\n\t\treturn( FALSE );\n\tiobject_set( IOBJECT( classmodel ), NULL, caption );\n\n\treturn( TRUE );\n}\n\nstatic void\nexpression_class_init( ExpressionClass *class )\n{\n\tModelClass *model_class = (ModelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tmodel_class->view_new = expression_view_new;\n\tmodel_class->save = expression_save;\n\tmodel_class->load = expression_load;\n\n\tclassmodel_class->class_get = expression_class_get;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\nexpression_init( Expression *expression )\n{\n\tiobject_set( IOBJECT( expression ), CLASS_EXPRESSION, NULL );\n}\n\nGType\nexpression_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ExpressionClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) expression_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Expression ),\n\t\t\t32,             /* n_pexpressionlocs */\n\t\t\t(GInstanceInitFunc) expression_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"Expression\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/expression.h",
    "content": "/* an editable expression in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_EXPRESSION (expression_get_type())\n#define EXPRESSION( obj ) (GTK_CHECK_CAST( (obj), TYPE_EXPRESSION, Expression ))\n#define EXPRESSION_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_EXPRESSION, ExpressionClass ))\n#define IS_EXPRESSION( obj ) (GTK_CHECK_TYPE( (obj), TYPE_EXPRESSION ))\n#define IS_EXPRESSION_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_EXPRESSION ))\n\nstruct _Expression {\n\tClassmodel parent_class;\n\n\t/* We don't have a model for the expression: instead we just grab the\n\t * value/formula from our MEMBER_VALUE itext. Much simpler.\n\t */\n};\n\ntypedef struct _ExpressionClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} ExpressionClass;\n\nGType expression_get_type( void );\n\niText *expression_get_itext( Expression *expression );\n\n"
  },
  {
    "path": "src/expressionview.c",
    "content": "/* a view of a text thingy\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GraphicviewClass *parent_class = NULL;\n\n/* Re-read the text in a tally entry. \n */\nstatic void *\nexpressionview_scan( View *view )\n{\n\tExpressionview *expressionview = EXPRESSIONVIEW( view );\n\tExpression *expression = EXPRESSION( \n\t\tVOBJECT( expressionview )->iobject );\n\tiText *itext = expression_get_itext( expression );\n\n#ifdef DEBUG\n{\n\tRow *row = HEAPMODEL( expression )->row;\n\n\tprintf( \"expressionview_scan: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n}\n#endif /*DEBUG*/\n\n\tif( itext &&\n\t\tformula_scan( expressionview->formula ) &&\n\t\titext_set_formula( itext, expressionview->formula->expr ) ) {\n\t\titext_set_edited( itext, TRUE );\n\n\t\t/* ... make sure MEMBER_VALUE gets marked dirty too.\n\t\t */\n\t\texpr_dirty( HEAPMODEL( itext )->row->expr, \n\t\t\tlink_serial_new() );\n\t}\n\n\treturn( VIEW_CLASS( parent_class )->scan( view ) );\n}\n\nvoid\nexpressionview_activate_cb( GtkWidget *wid, Expressionview *expressionview )\n{\n\tExpression *expression = \n\t\tEXPRESSION( VOBJECT( expressionview )->iobject );\n\tRow *row = HEAPMODEL( expression )->row;\n\n\t/* Reset edits on this row and all children.\n\t */\n\t(void) icontainer_map_all( ICONTAINER( row ),\n\t\t(icontainer_map_fn) heapmodel_clear_edited, NULL );\n\n\t/* Make sure we scan this text, even if it's not been edited.\n\t */\n\tview_scannable_register( VIEW( expressionview ) );\n\n\tworkspace_set_modified( row->ws, TRUE );\n\n\tsymbol_recalculate_all();\n}\n\nstatic void \nexpressionview_refresh( vObject *vobject )\n{\n\tExpressionview *expressionview = EXPRESSIONVIEW( vobject );\n\tExpression *expression = \n\t\tEXPRESSION( VOBJECT( expressionview )->iobject );\n\tiText *itext = expression_get_itext( expression );\n\tRow *row = HEAPMODEL( expression )->row;\n\n#ifdef DEBUG\n\tprintf( \"expressionview_refresh: \" );\n\trow_name_print( row );\n\tprintf( \" (%p)\\n\", vobject );\n#endif /*DEBUG*/\n\n\tformula_set_edit( expressionview->formula, \n\t\trow->ws->mode == WORKSPACE_MODE_FORMULA );\n\tif( itext ) \n\t\tformula_set_value_expr( expressionview->formula,\n\t\t\tvips_buf_all( &itext->value ), itext->formula );\n\tif( vobject->iobject->caption )\n\t\tformula_set_caption( expressionview->formula,\n\t\t\tvobject->iobject->caption );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void \nexpressionview_set_edit( Expressionview *expressionview, gboolean edit )\n{\n\tformula_set_edit( expressionview->formula, edit );\n\n\tif( edit ) \n\t\tview_resettable_register( VIEW( expressionview ) );\n}\n\nstatic void\nexpressionview_link( View *view, Model *model, View *parent )\n{\n\tExpressionview *expressionview = EXPRESSIONVIEW( view );\n\tExpression *expression = EXPRESSION( model );\n\tRow *row = HEAPMODEL( expression )->row;\n\n#ifdef DEBUG\n\tprintf( \"expressionview_link: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\tif( GRAPHICVIEW( view )->sview )\n\t\tgtk_size_group_add_widget( GRAPHICVIEW( view )->sview->group,   \n\t\t\texpressionview->formula->left_label );\n\n\t/* Edit mode defaults to edit mode for workspace.\n\t */\n        expressionview_set_edit( expressionview, \n\t\trow->ws->mode == WORKSPACE_MODE_FORMULA );\n}\n\n/* Reset edit mode ... go back to whatever is set for this ws.\n */\nstatic void \nexpressionview_reset( View *view )\n{\n\tExpressionview *expressionview = EXPRESSIONVIEW( view );\n\tExpression *expression = \n\t\tEXPRESSION( VOBJECT( expressionview )->iobject );\n\tRow *row = HEAPMODEL( expression )->row;\n\n\texpressionview_set_edit( expressionview, \n\t\trow->ws->mode == WORKSPACE_MODE_FORMULA );\n}\n\nstatic void\nexpressionview_class_init( ExpressionviewClass *class )\n{\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = expressionview_refresh;\n\n\tview_class->link = expressionview_link;\n\tview_class->reset = expressionview_reset;\n\tview_class->scan = expressionview_scan;\n}\n\nstatic void\nexpressionview_init( Expressionview *expressionview )\n{\n\texpressionview->formula = formula_new();\n        gtk_signal_connect_object( GTK_OBJECT( expressionview->formula ), \n\t\t\"changed\", \n\t\tGTK_SIGNAL_FUNC( view_changed_cb ), \n\t\tGTK_OBJECT( expressionview ) );\n        gtk_signal_connect( GTK_OBJECT( expressionview->formula ), \"activate\",\n                GTK_SIGNAL_FUNC( expressionview_activate_cb ), expressionview );\n        gtk_box_pack_start( GTK_BOX( expressionview ), \n\t\tGTK_WIDGET( expressionview->formula ), TRUE, FALSE, 0 );\n        gtk_widget_show( GTK_WIDGET( expressionview->formula ) );\n}\n\nGtkType\nexpressionview_get_type( void )\n{\n\tstatic GtkType expressionview_type = 0;\n\n\tif( !expressionview_type ) {\n\t\tstatic const GtkTypeInfo expressionview_info = {\n\t\t\t\"Expressionview\",\n\t\t\tsizeof( Expressionview ),\n\t\t\tsizeof( ExpressionviewClass ),\n\t\t\t(GtkClassInitFunc) expressionview_class_init,\n\t\t\t(GtkObjectInitFunc) expressionview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\texpressionview_type = gtk_type_unique( TYPE_GRAPHICVIEW, \n\t\t\t&expressionview_info );\n\t}\n\n\treturn( expressionview_type );\n}\n\nView *\nexpressionview_new( void )\n{\n\tExpressionview *expressionview = gtk_type_new( TYPE_EXPRESSIONVIEW );\n\n\treturn( VIEW( expressionview ) );\n}\n"
  },
  {
    "path": "src/expressionview.h",
    "content": "/* a textview button in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_EXPRESSIONVIEW (expressionview_get_type())\n#define EXPRESSIONVIEW( obj ) (GTK_CHECK_CAST( (obj), \\\n\tTYPE_EXPRESSIONVIEW, Expressionview ))\n#define EXPRESSIONVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_EXPRESSIONVIEW, ExpressionviewClass ))\n#define IS_EXPRESSIONVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_EXPRESSIONVIEW ))\n#define IS_EXPRESSIONVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_EXPRESSIONVIEW ))\n\ntypedef struct _Expressionview {\n\tGraphicview parent_object;\n\n        Formula *formula;\n} Expressionview;\n\ntypedef struct _ExpressionviewClass {\n\tGraphicviewClass parent_class;\n\n\t/* My methods.\n\t */\n} ExpressionviewClass;\n\nGtkType expressionview_get_type( void );\nView *expressionview_new( void );\n"
  },
  {
    "path": "src/filemodel.c",
    "content": "/* abstract base class for things which form the filemodel half of a \n * filemodel/view pair\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n/* Don't compress save files.\n\n \tFIXME ... some prebuilt libxml2s on win32 don't support libz\n\tcompression, so don't turn this off\n\n */\n#define DEBUG_SAVEFILE\n\n#include \"ip.h\"\n\nstatic ModelClass *parent_class = NULL;\n\nstatic GSList *filemodel_registered = NULL;\n\n/* Register a file model. Registered models are part of the \"xxx has been\n * modified, save before quit?\" check.\n */\nvoid \nfilemodel_register( Filemodel *filemodel )\n{\n\tif( !filemodel->registered ) {\n\t\tfilemodel->registered = TRUE;\n\t\tfilemodel_registered = g_slist_prepend( filemodel_registered, \n\t\t\tfilemodel );\n\n#ifdef DEBUG\n\t\tprintf( \"filemodel_register: %s \\\"%s\\\" (%p)\\n\",\n\t\t\tG_OBJECT_TYPE_NAME( filemodel ),\n\t\t\tIOBJECT( filemodel )->name,\n\t\t\tfilemodel );\n#endif /*DEBUG*/\n\t}\n}\n\nvoid \nfilemodel_unregister( Filemodel *filemodel )\n{\n\tif( filemodel->registered ) {\n\t\tfilemodel->registered = FALSE;\n\t\tfilemodel_registered = g_slist_remove( filemodel_registered, \n\t\t\tfilemodel );\n\n#ifdef DEBUG\n\t\tprintf( \"filemodel_unregister: %s \\\"%s\\\" (%p)\\n\",\n\t\t\tG_OBJECT_TYPE_NAME( filemodel ),\n\t\t\tIOBJECT( filemodel )->name,\n\t\t\tfilemodel );\n#endif /*DEBUG*/\n\t}\n}\n\n/* Trigger the top_load method for a filemodel.\n */\nvoid *\nfilemodel_top_load( Filemodel *filemodel, \n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\tFilemodelClass *filemodel_class = FILEMODEL_GET_CLASS( filemodel );\n\n\tif( filemodel_class->top_load ) {\n\t\tif( !filemodel_class->top_load( filemodel, state, \n\t\t\tparent, xnode ) )\n\t\t\treturn( filemodel );\n\t}\n\telse {\n\t\terror_top( _( \"Not implemented.\" ) );\n\t\terror_sub( _( \"_%s() not implemented for class \\\"%s\\\".\" ), \n\t\t\t\"top_load\",\n\t\t\tG_OBJECT_CLASS_NAME( filemodel_class ) );\n\n\t\treturn( filemodel );\n\t}\n\n\treturn( NULL );\n}\n\n/* Trigger the set_modified method for a filemodel.\n */\nvoid \nfilemodel_set_modified( Filemodel *filemodel, gboolean modified )\n{\n\tFilemodelClass *filemodel_class = FILEMODEL_GET_CLASS( filemodel );\n\n\tif( filemodel_class->set_modified ) \n\t\tfilemodel_class->set_modified( filemodel, modified );\n}\n\nvoid \nfilemodel_set_window_hint( Filemodel *filemodel, iWindow *iwnd )\n{\n\t/* This can be called repeatedly if objects are moved between windows.\n\t */\n\tfilemodel->window_hint = iwnd;\n}\n\niWindow * \nfilemodel_get_window_hint( Filemodel *filemodel )\n{\n\tif( filemodel->window_hint )\n\t\treturn( filemodel->window_hint );\n\telse\n\t\treturn( IWINDOW( mainw_pick_one() ) );\n}\n\ngboolean\nfilemodel_top_save( Filemodel *filemodel, const char *filename )\n{\n\tFilemodelClass *filemodel_class = FILEMODEL_GET_CLASS( filemodel );\n\n\tif( filemodel_class->top_save ) {\n\t\tchar *old_filename; \n\t\tint result;\n\n\t\t/* We must always have the new filename in the save file or\n\t\t * auto path rewriting will get confused on reload.\n\t\t *\n\t\t * Equally, we must not change the filename on the model, in\n\t\t * case this save is not something initiated by the user, for\n\t\t * example, an auto-backup of the workspace.\n\t\t *\n\t\t * Save and restore the filename. Our caller must set the\n\t\t * final filename, if required (after save-as, for example).\n\t\t */\n\t\told_filename = g_strdup( filemodel->filename ); \n\t\tfilemodel_set_filename( filemodel, filename );\n\n\t\tresult = filemodel_class->top_save( filemodel, filename );\n\n\t\tfilemodel_set_filename( filemodel, old_filename );\n\t\tg_free( old_filename );\n\n\t\treturn( result ); \n\t}\n\telse {\n\t\terror_top( _( \"Not implemented.\" ) );\n\t\terror_sub( _( \"_%s() not implemented for class \\\"%s\\\".\" ), \n\t\t\t\"top_save\",\n\t\t\tG_OBJECT_CLASS_NAME( filemodel_class ) );\n\n\t\treturn( FALSE );\n\t}\n}\n\nstatic void\nfilemodel_info( iObject *iobject, VipsBuf *buf )\n{\n\tFilemodel *filemodel = FILEMODEL( iobject );\n\n\tIOBJECT_CLASS( parent_class )->info( iobject, buf );\n\n\tvips_buf_appendf( buf, \"filename = \\\"%s\\\"\\n\", \n\t\tNN( filemodel->filename ) );\n\tvips_buf_appendf( buf, \"modified = \\\"%s\\\"\\n\", \n\t\tbool_to_char( filemodel->modified ) );\n\tvips_buf_appendf( buf, \"registered = \\\"%s\\\"\\n\", \n\t\tbool_to_char( filemodel->registered ) );\n\tvips_buf_appendf( buf, \"auto_load = \\\"%s\\\"\\n\", \n\t\tbool_to_char( filemodel->auto_load ) );\n}\n\n/* filename can be NULL for unset.\n */\nvoid\nfilemodel_set_filename( Filemodel *filemodel, const char *filename )\n{\n\tif( filemodel->filename != filename ) {\n\t\tchar buf[FILENAME_MAX];\n\n\t\t/* We want to keep the absolute, compact form of the filename \n\t\t * inside the object so we don't get a dependency on CWD.\n\t\t */\n\t\tif( filename ) {\n\t\t\tim_strncpy( buf, filename, FILENAME_MAX );\n\t\t\tpath_compact( buf );\n\t\t\tfilename = buf;\n\t\t}\n\n\t\tIM_SETSTR( filemodel->filename, filename );\n\t\tiobject_changed( IOBJECT( filemodel ) );\n\t}\n}\n\nstatic void\nfilemodel_finalize( GObject *gobject )\n{\n\tFilemodel *filemodel;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_FILEMODEL( gobject ) );\n\n\tfilemodel = FILEMODEL( gobject );\n\n#ifdef DEBUG\n\tprintf( \"filemodel_finalize: %s \\\"%s\\\" (%s)\\n\", \n\t\tG_OBJECT_TYPE_NAME( filemodel ), \n\t\tNN( IOBJECT( filemodel )->name ),\n\t\tNN( filemodel->filename ) );\n#endif /*DEBUG*/\n\n\tIM_FREE( filemodel->filename );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\nfilemodel_dispose( GObject *gobject )\n{\n\tFilemodel *filemodel;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_FILEMODEL( gobject ) );\n\n\tfilemodel = FILEMODEL( gobject );\n\n#ifdef DEBUG\n\tprintf( \"filemodel_dispose: %s \\\"%s\\\" (%s)\\n\", \n\t\tG_OBJECT_TYPE_NAME( filemodel ), \n\t\tNN( IOBJECT( filemodel )->name ),\n\t\tNN( filemodel->filename ) );\n#endif /*DEBUG*/\n\n\tfilemodel_unregister( filemodel );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic xmlNode *\nfilemodel_save( Model *model, xmlNode *xnode )\n{\n\tFilemodel *filemodel = FILEMODEL( model );\n\txmlNode *xthis;\n\n\tif( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )\n\t\treturn( NULL );\n\n\tif( !set_sprop( xthis, \"filename\", filemodel->filename ) )\n\t\treturn( NULL );\n\n\treturn( xthis );\n}\n\nstatic gboolean \nfilemodel_load( Model *model,\n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\tFilemodel *filemodel = FILEMODEL( model );\n\n\tchar buf[MAX_STRSIZE];\n\n\tif( get_sprop( xnode, \"filename\", buf, MAX_STRSIZE ) )\n\t\tfilemodel_set_filename( filemodel, buf );\n\n\tif( !MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic gboolean \nfilemodel_real_top_load( Filemodel *filemodel,\n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\treturn( TRUE );\n}\n\nstatic void \nfilemodel_real_set_modified( Filemodel *filemodel, gboolean modified )\n{\n\tif( filemodel->modified != modified ) {\n#ifdef DEBUG\n\t\tprintf( \"filemodel_real_set_modified: %s \\\"%s\\\" (%s) %s\\n\", \n\t\t\tG_OBJECT_TYPE_NAME( filemodel ), \n\t\t\tNN( IOBJECT( filemodel )->name ),\n\t\t\tNN( filemodel->filename ),\n\t\t\tbool_to_char( modified ) );\n#endif /*DEBUG*/\n\n\t\tfilemodel->modified = modified;\n\n\t\tiobject_changed( IOBJECT( filemodel ) );\n\t}\n}\n\nstatic int\nfilemodel_xml_save_format_file( const char *filename, xmlDoc *doc )\n{\n\treturn( xmlSaveFormatFile( filename, doc, 1 ) == -1 ); \n}\n\n/* Save to filemodel->filename.\n */\nstatic gboolean\nfilemodel_top_save_xml( Filemodel *filemodel, const char *filename )\n{\n\txmlDoc *xdoc;\n\tchar namespace[256];\n\n\tif( !(xdoc = xmlNewDoc( (xmlChar *) \"1.0\" )) ) {\n\t\terror_top( _( \"XML library error.\" ) );\n\t\terror_sub( _( \"model_save_filename: xmlNewDoc() failed\" ) );\n\t\treturn( FALSE );\n\t}\n\n#ifndef DEBUG_SAVEFILE\n\txmlSetDocCompressMode( xdoc, 1 );\n#endif /*!DEBUG_SAVEFILE*/\n\n\tim_snprintf( namespace, 256, \"%s/%d.%d.%d\",\n\t\tNAMESPACE, \n\t\tfilemodel->major, filemodel->minor, filemodel->micro );\n\tif( !(xdoc->children = xmlNewDocNode( xdoc, \n\t\tNULL, (xmlChar *) \"root\", NULL )) ||\n\t\t!set_sprop( xdoc->children, \"xmlns\", namespace ) ) {\n\t\terror_top( _( \"XML library error.\" ) );\n\t\terror_sub( _( \"model_save_filename: xmlNewDocNode() failed\" ) );\n\t\txmlFreeDoc( xdoc );\n\t\treturn( FALSE );\n\t}\n\n\tcolumn_set_offset( filemodel->x_off, filemodel->y_off );\n\tif( model_save( MODEL( filemodel ), xdoc->children ) ) {\n\t\txmlFreeDoc( xdoc );\n\t\treturn( FALSE );\n\t}\n\n\tif( calli_string_filename( \n\t\t(calli_string_fn) filemodel_xml_save_format_file, \n\t\t\tfilename, xdoc, NULL, NULL ) ) {\n\t\terror_top( _( \"Save failed.\" ) );\n\t\terror_sub( _( \"Save of %s \\\"%s\\\" to file \\\"%s\\\" failed.\\n%s\" ),\n\t\t\tIOBJECT_GET_CLASS_NAME( filemodel ), \n\t\t\tNN( IOBJECT( filemodel )->name ),\n\t\t\tNN( filename ),\n\t\t\tg_strerror( errno ) );\n\t\txmlFreeDoc( xdoc );\n\n\t\treturn( FALSE );\n\t}\n\n\txmlFreeDoc( xdoc );\n\n\treturn( TRUE );\n}\n\nstatic gboolean\nfilemodel_top_save_text( Filemodel *filemodel, const char *filename )\n{\n\tiOpenFile *of;\n\n\tif( !(of = ifile_open_write( \"%s\", filename )) ) \n\t\treturn( FALSE );\n\n\tcolumn_set_offset( filemodel->x_off, filemodel->y_off );\n\tif( model_save_text( MODEL( filemodel ), of ) ) {\n\t\tifile_close( of );\n\t\treturn( FALSE );\n\t}\n\tifile_close( of );\n\n\treturn( TRUE );\n}\n\nstatic gboolean\nfilemodel_real_top_save( Filemodel *filemodel, const char *filename )\n{\n\tModelClass *model_class = MODEL_GET_CLASS( filemodel );\n\n#ifdef DEBUG\n\tprintf( \"filemodel_real_top_save: save %s \\\"%s\\\" to file \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( filemodel ), \n\t\tNN( IOBJECT( filemodel )->name ),\n\t\tfilename );\n#endif /*DEBUG*/\n\n\tif( model_class->save_text ) {\n\t\tif( !filemodel_top_save_text( filemodel, filename ) )\n\t\t\treturn( FALSE );\n\t}\n\telse if( model_class->save ) {\n\t\tif( !filemodel_top_save_xml( filemodel, filename ) )\n\t\t\treturn( FALSE );\n\t}\n\telse {\n\t\terror_top( _( \"Not implemented.\" ) );\n\t\terror_sub( _( \"filemodel_real_top_save: no save method\" ) );\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic void\nfilemodel_class_init( FilemodelClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tiObjectClass *iobject_class = IOBJECT_CLASS( class );\n\tModelClass *model_class = (ModelClass*) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = filemodel_finalize;\n\tgobject_class->dispose = filemodel_dispose;\n\n\tiobject_class->info = filemodel_info;\n\n\tmodel_class->save = filemodel_save;\n\tmodel_class->load = filemodel_load;\n\t\n\tclass->top_load = filemodel_real_top_load;\n\tclass->set_modified = filemodel_real_set_modified;\n\tclass->top_save = filemodel_real_top_save;\n\n\t/* NULL isn't an allowed value -- this gets overridden by our\n\t * subclasses.\n\t */\n\tclass->filetype = NULL;\n\tclass->filetype_pref = NULL;\n}\n\nstatic void\nfilemodel_init( Filemodel *filemodel )\n{\n\t/* Init our instance fields.\n\t */\n\tfilemodel->filename = NULL;\n\tfilemodel->modified = FALSE;\n\tfilemodel->registered = FALSE;\n\tfilemodel->auto_load = FALSE;\n\tfilemodel->x_off = 0;\n\tfilemodel->y_off = 0;\n\n\t/* Default version.\n\t */\n\tfilemodel->versioned = FALSE;\n\tfilemodel->major = MAJOR_VERSION;\n\tfilemodel->minor = MINOR_VERSION;\n\tfilemodel->micro = MICRO_VERSION;\n\n\tfilemodel->window_hint = NULL;\n}\n\nGtkType\nfilemodel_get_type( void )\n{\n\tstatic GtkType filemodel_type = 0;\n\n\tif( !filemodel_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( FilemodelClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) filemodel_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Filemodel ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) filemodel_init,\n\t\t};\n\n\t\tfilemodel_type = g_type_register_static( TYPE_MODEL, \n\t\t\t\"Filemodel\", &info, 0 );\n\t}\n\n\treturn( filemodel_type );\n}\n\nvoid\nfilemodel_set_offset( Filemodel *filemodel, int x_off, int y_off )\n{\n#ifdef DEBUG\n\tprintf( \"filemodel_set_offset: %s \\\"%s\\\" %d x %d\\n\", \n\t\tG_OBJECT_TYPE_NAME( filemodel ), \n\t\tNN( IOBJECT( filemodel )->name ),\n\t\tx_off, y_off );\n#endif /*DEBUG*/\n\n\tfilemodel->x_off = x_off;\n\tfilemodel->y_off = y_off;\n}\n\nstatic gboolean\nfilemodel_load_all_xml( Filemodel *filemodel, \n\tModel *parent, ModelLoadState *state )\n{\n\txmlNode *xnode;\n\n\t/* Check the root element for type/version compatibility.\n\t */\n\tif( !(xnode = xmlDocGetRootElement( state->xdoc )) ||\n\t\t!xnode->nsDef ||\n\t\t!is_prefix( NAMESPACE, (char *) xnode->nsDef->href ) ) {\n\t\terror_top( _( \"Load failed.\" ) );\n\t\terror_sub( _( \"Can't load XML file \\\"%s\\\", \"\n\t\t\t\"it's not a %s save file.\" ), \n\t\t\tstate->filename, PACKAGE );\n\t\treturn( FALSE );\n\t}\n\tif( sscanf( (char *) xnode->nsDef->href + strlen( NAMESPACE ) + 1, \n\t\t\"%d.%d.%d\",\n\t\t&state->major, &state->minor, &state->micro ) != 3 ) {\n\t\terror_top( _( \"Load failed.\" ) );\n\t\terror_sub( _( \"Can't load XML file \\\"%s\\\", \"\n\t\t\t\"unable to extract version information from \"\n\t\t\t\"namespace.\" ), state->filename );\n\t\treturn( FALSE );\n\t}\n\n#ifdef DEBUG\n\tprintf( \"filemodel_load_all_xml: major = %d, minor = %d, micro = %d\\n\",\n\t\tstate->major, state->minor, state->micro );\n#endif /*DEBUG*/\n\n\tif( filemodel_top_load( filemodel, state, parent, xnode ) ) \n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic gboolean\nfilemodel_load_all_xml_file( Filemodel *filemodel, Model *parent, \n\tconst char *filename, const char *filename_user )\n{\n\tModelLoadState *state;\n\n\tif( !(state = model_loadstate_new( filename, filename_user )) )\n\t\treturn( FALSE );\n\tif( !filemodel_load_all_xml( filemodel, parent, state ) ) {\n\t\tmodel_loadstate_destroy( state );\n\t\treturn( FALSE );\n\t}\n\tmodel_loadstate_destroy( state );\n\n\treturn( TRUE );\n}\n\nstatic gboolean\nfilemodel_load_all_xml_openfile( Filemodel *filemodel, \n\tModel *parent, iOpenFile *of )\n{\n\tModelLoadState *state;\n\n\tif( !(state = model_loadstate_new_openfile( of )) )\n\t\treturn( FALSE );\n\tif( !filemodel_load_all_xml( filemodel, parent, state ) ) {\n\t\tmodel_loadstate_destroy( state );\n\t\treturn( FALSE );\n\t}\n\tmodel_loadstate_destroy( state );\n\n\treturn( TRUE );\n}\n\nstatic gboolean\nfilemodel_load_all_text( Filemodel *filemodel, Model *parent, \n\tconst char *filename, const char *filename_user )\n{\n\tiOpenFile *of;\n\n\tif( !(of = ifile_open_read( \"%s\", filename )) ) \n\t\treturn( FALSE );\n\n\tif( model_load_text( MODEL( filemodel ), parent, of ) ) {\n\t\tifile_close( of );\n\t\treturn( FALSE );\n\t}\n\tifile_close( of );\n\n\treturn( TRUE );\n}\n\n/* Load filename into filemodel ... can mean merge as well as init.\n *\n * We load from @filename. If @filename_user is non-NULL, that's the filename\n * we should record in the model.\n */\ngboolean\nfilemodel_load_all( Filemodel *filemodel, Model *parent, \n\tconst char *filename, const char *filename_user )\n{\n\tModelClass *model_class = MODEL_GET_CLASS( filemodel );\n\tconst char *tname = G_OBJECT_CLASS_NAME( model_class );\n\n#ifdef DEBUG\n\tprintf( \"filemodel_load_all: load file \\\"%s\\\" into parent %s \\\"%s\\\"\\n\", \n\t\tfilename,\n\t\tG_OBJECT_TYPE_NAME( parent ), \n\t\tNN( IOBJECT( parent )->name ) );\n#endif /*DEBUG*/\n\n\tif( model_class->load_text ) {\n\t\tif( !filemodel_load_all_text( filemodel, parent, \n\t\t\tfilename, filename_user ) ) \n\t\t\treturn( FALSE );\n\t}\n\telse if( model_class->load ) {\n\t\tif( !filemodel_load_all_xml_file( filemodel, parent, \n\t\t\tfilename, filename_user ) )\n\t\t\treturn( FALSE );\n\t}\n\telse {\n\t\terror_top( _( \"Not implemented.\" ) );\n\t\terror_sub( _( \"_%s() not implemented for class \\\"%s\\\".\" ), \n\t\t\t\"load\", tname );\n\t\treturn( FALSE );\n\t}\n\n\t/* Don't recomp here, we may be loading a bunch of interdependent\n\t * files.\n\t */\n\n\treturn( TRUE );\n}\n\n/* Load iOpenFile into filemodel ... can mean merge as well as init.\n */\ngboolean\nfilemodel_load_all_openfile( Filemodel *filemodel, Model *parent, \n\tiOpenFile *of )\n{\n\tModelClass *model_class = MODEL_GET_CLASS( filemodel );\n\tconst char *tname = G_OBJECT_CLASS_NAME( model_class );\n\n#ifdef DEBUG\n\tprintf( \"filemodel_load_all_openfile: load \\\"%s\\\" \"\n\t\t\"into parent %s \\\"%s\\\"\\n\", \n\t\tof->fname,\n\t\tG_OBJECT_TYPE_NAME( parent ), \n\t\tNN( IOBJECT( parent )->name ) );\n#endif /*DEBUG*/\n\n\tif( model_class->load_text ) {\n\t\tif( model_load_text( MODEL( filemodel ), parent, of ) ) \n\t\t\treturn( FALSE );\n\t}\n\telse if( model_class->load ) {\n\t\tif( !filemodel_load_all_xml_openfile( filemodel, parent, of ) )\n\t\t\treturn( FALSE );\n\t}\n\telse {\n\t\terror_top( _( \"Not implemented.\" ) );\n\t\terror_sub( _( \"_%s() not implemented for class \\\"%s\\\".\" ), \n\t\t\t\"load\", tname );\n\t\treturn( FALSE );\n\t}\n\n\t/* Don't recomp here, we may be loading a bunch of interdependent\n\t * files.\n\t */\n\n\treturn( TRUE );\n}\n\n/* Interactive stuff ... save first.\n */\n\nstatic void\nfilemodel_inter_saveas_sub_cb( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( iwnd );\n\tFilemodel *filemodel = FILEMODEL( client );\n\tchar *filename;\n\n\tif( (filename = filesel_get_filename( filesel )) ) {\n\t\tif( filemodel_top_save( filemodel, filename ) ) {\n\t\t\tfilemodel_set_filename( filemodel, filename );\n\t\t\tfilemodel_set_modified( filemodel, FALSE );\n\t\t\tnfn( sys, IWINDOW_YES );\n\t\t}\n\t\telse\n\t\t\tnfn( sys, IWINDOW_ERROR );\n\n\t\tg_free( filename );\n\t}\n\telse\n\t\tnfn( sys, IWINDOW_ERROR );\n}\n\nstatic void\nfilemodel_inter_saveas_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tFilemodel *filemodel = FILEMODEL( client );\n\tFilemodelClass *class = FILEMODEL_GET_CLASS( filemodel );\n\n\tFilesel *filesel = FILESEL( filesel_new() );\n\n\t/* Expands to (eg.) \"Save Column A2\".\n\t */\n\tiwindow_set_title( IWINDOW( filesel ), _( \"Save %s %s\" ),\n\t\tIOBJECT_GET_CLASS_NAME( filemodel ), \n\t\tNN( IOBJECT( filemodel )->name ) );\n\tfilesel_set_flags( filesel, FALSE, TRUE );\n\tfilesel_set_filetype( filesel, \n\t\tclass->filetype, \n\t\twatch_int_get( main_watchgroup, class->filetype_pref, 0 ) );\n\tiwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( iwnd ) );\n\tfilesel_set_done( filesel, filemodel_inter_saveas_sub_cb, filemodel );\n\tidialog_set_notify( IDIALOG( filesel ), nfn, sys );\n\tiwindow_build( IWINDOW( filesel ) );\n\tif( filemodel->filename )\n\t\tfilesel_set_filename( filesel, filemodel->filename );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\nvoid\nfilemodel_inter_saveas( iWindow *parent, Filemodel *filemodel )\n{\n\tfilemodel_inter_saveas_cb( parent, filemodel, \n\t\tiwindow_notify_null, NULL );\n}\n\nvoid\nfilemodel_inter_save( iWindow *parent, Filemodel *filemodel )\n{\n\tif( filemodel->filename ) {\n\t\tif( !filemodel_top_save( filemodel, filemodel->filename ) ) \n\t\t\tiwindow_alert( GTK_WIDGET( parent ), \n\t\t\t\tGTK_MESSAGE_ERROR );\n\t\telse \n\t\t\tfilemodel_set_modified( filemodel, FALSE );\n\t}\n\telse \n\t\tfilemodel_inter_saveas( parent, filemodel );\n}\n\n/* Now \"empty\" ... do an 'are you sure' check if modified has been set.\n */\n\nstatic void\nfilemodel_inter_empty_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tFilemodel *filemodel = FILEMODEL( client );\n\n\t(void) model_empty( MODEL( filemodel ) );\n\tfilemodel_set_modified( filemodel, FALSE );\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nfilemodel_inter_savenempty_ok_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tiWindowSusp *susp = iwindow_susp_new( filemodel_inter_empty_cb, \n\t\tiwnd, client, nfn, sys );\n\n\tfilemodel_inter_saveas_cb( iwnd, client, iwindow_susp_comp, susp );\n}\n\nvoid\nfilemodel_inter_savenempty_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tFilemodel *filemodel = FILEMODEL( client );\n\tconst char *tname = IOBJECT_GET_CLASS_NAME( filemodel );\n\n\tif( filemodel->modified ) {\n\t\tif( filemodel->filename )\n\t\t\tbox_savenosave( GTK_WIDGET( iwnd ), \n\t\t\t\tfilemodel_inter_savenempty_ok_cb, \n\t\t\t\tfilemodel_inter_empty_cb, filemodel, \n\t\t\t\tnfn, sys, \n\t\t\t\t_( \"Object has been modified.\" ),\n\t\t\t\t_( \"%s has been modified since you \"\n\t\t\t\t\"loaded it from file \\\"%s\\\".\\n\\n\"\n\t\t\t\t\"Do you want to save your changes?\" ),\n\t\t\t\ttname, \n\t\t\t\tNN( filemodel->filename ) );\n\t\telse\n\t\t\tbox_savenosave( GTK_WIDGET( iwnd ), \n\t\t\t\tfilemodel_inter_savenempty_ok_cb, \n\t\t\t\tfilemodel_inter_empty_cb, filemodel, \n\t\t\t\tnfn, sys, \n\t\t\t\t_( \"Object has been modified.\" ),\n\t\t\t\t_( \"%s has been modified. \"\n\t\t\t\t\"Do you want to save your changes?\" ),\n\t\t\t\ttname );  \n\t}\n\telse\n\t\tfilemodel_inter_empty_cb( NULL, filemodel, nfn, sys );\n}\n\nvoid\nfilemodel_inter_savenempty( iWindow *parent, Filemodel *filemodel )\n{\n\tfilemodel_inter_savenempty_cb( parent, filemodel, \n\t\tiwindow_notify_null, NULL );\n}\n\n/* Now \"close\" ... easy: just savenempty, then destroy.\n */\n\nstatic void\nfilemodel_inter_close_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tFilemodel *filemodel = FILEMODEL( client );\n\n\tiwindow_kill( filemodel_get_window_hint( filemodel ) ); \n\n\tnfn( sys, IWINDOW_YES );\n}\n\nvoid\nfilemodel_inter_savenclose_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tiWindowSusp *susp = iwindow_susp_new( filemodel_inter_close_cb, \n\t\tiwnd, client, nfn, sys );\n\n\tfilemodel_inter_savenempty_cb( iwnd, client, iwindow_susp_comp, susp );\n}\n\nvoid\nfilemodel_inter_savenclose( iWindow *parent, Filemodel *filemodel )\n{\n\tfilemodel_inter_savenclose_cb( parent, filemodel, \n\t\tiwindow_notify_null, NULL );\n}\n\n/* Now \"load\" ... add stuff to a model from a file.\n */\n\nstatic void\nfilemodel_inter_load_cb( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( iwnd );\n\tFilemodel *filemodel = FILEMODEL( client );\n\tiContainer *parent = ICONTAINER( filemodel )->parent;\n\tchar *filename;\n\n\tif( (filename = filesel_get_filename( filesel )) ) {\n\t\tfilemodel_set_filename( filemodel, filename );\n\n\t\tif( filemodel_load_all( filemodel, MODEL( parent ), \n\t\t\tfilename, NULL ) ) \n\t\t\tnfn( sys, IWINDOW_YES );\n\t\telse\n\t\t\tnfn( sys, IWINDOW_ERROR );\n\n\t\tg_free( filename );\n\t}\n\telse\n\t\tnfn( sys, IWINDOW_ERROR );\n}\n\nstatic void\nfilemodel_inter_loadas_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tFilemodel *filemodel = FILEMODEL( client );\n\tFilemodelClass *class = FILEMODEL_GET_CLASS( filemodel );\n\n\tFilesel *filesel = FILESEL( filesel_new() );\n\n\tiwindow_set_title( IWINDOW( filesel ), \"Load %s\",\n\t\tIOBJECT_GET_CLASS_NAME( filemodel ) );\n\tfilesel_set_flags( filesel, FALSE, TRUE );\n\tfilesel_set_filetype( filesel, \n\t\tclass->filetype, \n\t\twatch_int_get( main_watchgroup, class->filetype_pref, 0 ) );\n\tiwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( iwnd ) );\n\tfilesel_set_done( filesel, filemodel_inter_load_cb, filemodel );\n\tidialog_set_notify( IDIALOG( filesel ), nfn, sys );\n\tiwindow_build( IWINDOW( filesel ) );\n\tif( filemodel->filename )\n\t\tfilesel_set_filename( filesel, filemodel->filename );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\nvoid\nfilemodel_inter_loadas( iWindow *parent, Filemodel *filemodel )\n{\n\tfilemodel_inter_loadas_cb( parent, filemodel, \n\t\tiwindow_notify_null, NULL );\n}\n\n/* Finally \"replace\" ... empty, then load.\n */\n\nstatic void\nfilemodel_inter_replace_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tiWindowSusp *susp = iwindow_susp_new( filemodel_inter_loadas_cb, \n\t\tiwnd, client, nfn, sys );\n\n\tfilemodel_inter_savenempty_cb( iwnd, client, iwindow_susp_comp, susp );\n}\n\nvoid\nfilemodel_inter_replace( iWindow *parent, Filemodel *filemodel )\n{\n\tfilemodel_inter_replace_cb( parent, filemodel, \n\t\tiwindow_notify_null, NULL );\n}\n\n/* Close all registered filemodels.\n */\n\n/* The first registered, modified filemodel the user hasn't said \"ok!!! ffs\"\n * to.\n */\nstatic Filemodel *\nfilemodel_inter_close_get_filemodel( void )\n{\n\tGSList *p;\n\n\tfor( p = filemodel_registered; p; p = p->next ) {\n\t\tFilemodel *filemodel = FILEMODEL( p->data );\n\n\t\tif( filemodel->modified )\n\t\t\treturn( filemodel );\n\t}\n\n\treturn( NULL );\n}\n\nvoid\nfilemodel_inter_close_registered_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tFilemodel *filemodel; \n\n\tif( (filemodel = filemodel_inter_close_get_filemodel()) ) { \n\t\tiWindowSusp *susp = iwindow_susp_new( \n\t\t\tfilemodel_inter_close_registered_cb, \n\t\t\tiwnd, client, nfn, sys );\n\n\t\tfilemodel_inter_savenclose_cb( \n\t\t\tfilemodel_get_window_hint( filemodel ), filemodel, \n\t\t\tiwindow_susp_comp, susp );\n\t}\n\telse\n\t\tnfn( sys, IWINDOW_YES );\n}\n\n/* Mark something as having been loaded (or made) during startup. If we loaded\n * from one of the system areas, zap the filename so that we will save to the\n * user's area on changes.\n */\nvoid\nfilemodel_set_auto_load( Filemodel *filemodel )\n{\n\tfilemodel->auto_load = TRUE;\n\n\t/* \n\n\t\tFIXME ... not very futureproof\n\n\t */\n\tif( filemodel->filename && \n\t\tstrstr( filemodel->filename, \n\t\t\t\"share\" G_DIR_SEPARATOR_S PACKAGE ) ) {\n\t\tchar *p = strrchr( filemodel->filename, G_DIR_SEPARATOR );\n\t\tchar buf[FILENAME_MAX];\n\n\t\tg_assert( p );\n\n\t\tim_snprintf( buf, FILENAME_MAX, \"$SAVEDIR\" G_DIR_SEPARATOR_S\n\t\t\t\"start\" G_DIR_SEPARATOR_S \"%s\", p + 1 );\n\t\tfilemodel_set_filename( filemodel, buf );\n\t}\n}\n"
  },
  {
    "path": "src/filemodel.h",
    "content": "/* abstract base class for things which are loaded or saved from files\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define FILEMODEL_LOAD_STATE( obj ) ((FilemodelLoadState *) obj)\n\n#define TYPE_FILEMODEL (filemodel_get_type())\n#define FILEMODEL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_FILEMODEL, Filemodel ))\n#define FILEMODEL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_FILEMODEL, FilemodelClass))\n#define IS_FILEMODEL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_FILEMODEL ))\n#define IS_FILEMODEL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_FILEMODEL ))\n#define FILEMODEL_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_FILEMODEL, FilemodelClass ))\n\nstruct _Filemodel {\n\tModel model;\n\n        char *filename;         /* File we read this thing from */\n\tgboolean modified;\t/* Set if modified (and should be saved) */\n\tgboolean registered;\t/* Set if on list of things to save on quit */\n\tgboolean auto_load;\t/* TRUE if loaded from path_start */\n\n\tint x_off, y_off;\t/* Save offset for things below this */\n\n\t/* When we loaded this filemodel, the version numbers we saw in the\n\t * XML file.\n\t */\n\tgboolean versioned;\t/* Set means from a versioned file */\n\tint major;\n\tint minor;\n\tint micro;\n\n\tiWindow *window_hint;\t/* Our views set this as a hint */\n};\n\ntypedef struct _FilemodelClass {\n\tModelClass parent_class;\n\n\t/* \n\n\t\ttop_load\ttop level load function ... controls how the\n\t\t\t\trest of the load happens ... eg. merge,\n\t\t\t\trename, etc.\n\n\t\tset_modified\tset/clear the modified state\n\n\t\ttop_save\ttop level save ... intercept this to override\n\n\t */\n\n\tgboolean (*top_load)( Filemodel *filemodel, \n\t\tModelLoadState *state, Model *parent, xmlNode *xnode );\n\tvoid (*set_modified)( Filemodel *filemodel, gboolean modified );\n\tgboolean (*top_save)( Filemodel *filemodel, const char *filename );\n\n\tFileselFileType **filetype;\n\tconst char *filetype_pref;\n} FilemodelClass;\n\nvoid filemodel_register( Filemodel *filemodel );\nvoid filemodel_unregister( Filemodel *filemodel );\n\nvoid *filemodel_top_load( Filemodel *filemodel, \n\tModelLoadState *state, Model *parent, xmlNode *xnode );\n\nvoid filemodel_set_filename( Filemodel *filemodel, const char *filename );\nvoid filemodel_set_modified( Filemodel *filemodel, gboolean state );\nvoid filemodel_set_window_hint( Filemodel *filemodel, iWindow *iwnd );\niWindow *filemodel_get_window_hint( Filemodel *filemodel );\n\nGType filemodel_get_type( void );\n\nvoid filemodel_set_offset( Filemodel *filemodel, int x_off, int y_off );\ngboolean filemodel_top_save( Filemodel *filemodel, const char *filename );\ngboolean filemodel_load_all( Filemodel *filemodel, Model *parent, \n\tconst char *filename, const char *filename_user );\ngboolean filemodel_load_all_openfile( Filemodel *filemodel, \n\tModel *parent, iOpenFile *of );\n\nvoid filemodel_inter_saveas( iWindow *parent, Filemodel *filemodel );\nvoid filemodel_inter_save( iWindow *parent, Filemodel *filemodel );\nvoid filemodel_inter_savenempty_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys );\nvoid filemodel_inter_savenempty( iWindow *parent, Filemodel *filemodel );\nvoid filemodel_inter_savenclose_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys );\nvoid filemodel_inter_savenclose( iWindow *parent, Filemodel *filemodel );\nvoid filemodel_inter_loadas( iWindow *parent, Filemodel *filemodel );\nvoid filemodel_inter_replace( iWindow *parent, Filemodel *filemodel );\n\nvoid filemodel_inter_close_registered_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys );\n\nvoid filemodel_set_auto_load( Filemodel *filemodel );\n"
  },
  {
    "path": "src/filesel.c",
    "content": "/* ip's file selectors.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#include \"ip.h\"\n\n/* Define for debugging output.\n#define DEBUG\n */\n\n/* TIFF save possibilities. Needs to be kept in sync with the Option in\n * preferences.\n */\ntypedef enum {\n\tTIFF_COMPRESSION_NONE = 0,\t/* No compression */\n\tTIFF_COMPRESSION_LZW,\t\t/* Lempel-Ziv compression */\n\tTIFF_COMPRESSION_DEFLATE,\t/* Zip (deflate) compression */\n\tTIFF_COMPRESSION_PACKBITS,\t/* Packbits compression */\n\tTIFF_COMPRESSION_JPEG,\t\t/* JPEG compression */\n\tTIFF_COMPRESSION_CCITTFAX4\t/* Fax compression */\n} TiffCompression;\n\ntypedef enum {\n\tTIFF_LAYOUT_STRIP = 0,\t\t/* Strip TIFF */\n\tTIFF_LAYOUT_TILE\t\t/* Tiled TIFF */\n} TiffLayout;\n\ntypedef enum {\n\tTIFF_MULTIRES_FLAT = 0,\t\t/* Flat file */\n\tTIFF_MULTIRES_PYRAMID\t\t/* Pyramidal TIFF */\n} TiffMultires;\n\ntypedef enum {\n\tTIFF_FORMAT_MANYBIT = 0,\t/* No bit reduction */\n\tTIFF_FORMAT_ONEBIT\t\t/* Reduce to 1 bit, where poss */\n} TiffFormat;\n\n/* Keep a list of all filesels currently active ... we use this for refresh on\n * new file.\n */\nstatic GSList *filesel_all = NULL;\n\nstatic iDialogClass *parent_class = NULL;\n\n/* For filesels which don't have a suggested filename, track the last dir we\n * went to and use that as the start dir next time.\n */\nstatic char *filesel_last_dir = NULL;\n\nstatic const char *icc_suffs[] = { \".icc\", \".icm\", NULL };\nstatic const char *workspace_suffs[] = { \".ws\", NULL };\nstatic const char *rec_suffs[] = { \".rec\", NULL };\nstatic const char *mor_suffs[] = { \".mor\", NULL };\nstatic const char *con_suffs[] = { \".con\", NULL };\nstatic const char *mat_suffs[] = { \".mat\", NULL };\nstatic const char *def_suffs[] = { \".def\", NULL };\nstatic const char *all_suffs[] = { \"\", NULL };\n\nFileselFileType\n        filesel_wfile_type = \n\t\t{ N_( \"Workspace files (*.ws)\" ), workspace_suffs },\n        filesel_rfile_type = \n\t\t{ N_( \"Recombination matrix files (*.rec)\" ), rec_suffs },\n        filesel_mfile_type = \n\t\t{ N_( \"Morphology matrix files (*.mor)\" ), mor_suffs },\n        filesel_cfile_type = \n\t\t{ N_( \"Convolution matrix files (*.con)\" ), con_suffs },\n        filesel_xfile_type = \n\t\t{ N_( \"Matrix files (*.mat)\" ), mat_suffs },\n        filesel_dfile_type = \n\t\t{ N_( \"Definition files (*.def)\" ), def_suffs },\n        filesel_ifile_type = \n\t\t{ N_( \"ICC profiles (*.icc, *.icm)\" ), icc_suffs },\n        filesel_allfile_type = \n\t\t{ N_( \"All files (*)\" ), all_suffs };\n\nFileselFileType\n        *filesel_type_definition[] = { \n\t\t&filesel_dfile_type, NULL \n\t},\n        *filesel_type_workspace[] = { \n\t\t&filesel_wfile_type, NULL \n\t},\n\n        *filesel_type_matrix[] = { \n\t\t&filesel_xfile_type, &filesel_cfile_type, &filesel_rfile_type, \n\t\t&filesel_mfile_type, NULL \n\t},\n\n\t/* Set during startup.\n\t */\n        **filesel_type_image = NULL,\n        **filesel_type_mainw = NULL,\n        **filesel_type_any = NULL;\n\nstatic void *\nbuild_vips_formats_sub( VipsFormatClass *format, GSList **types )\n{\n\tFileselFileType *type = g_new( FileselFileType, 1 );\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tconst char **i;\n\n\tvips_buf_appendf( &buf, \n\t\t\"%s \", VIPS_OBJECT_CLASS( format )->description );\n\t/* Used as eg. \"VIPS image files (*.v)\"\n\t */\n\tvips_buf_appends( &buf, _( \"image files\" ) );\n\tvips_buf_appends( &buf, \" (\" );\n\tif( *format->suffs )\n\t\tfor( i = format->suffs; *i; i++ ) {\n\t\t\tvips_buf_appendf( &buf, \"*%s\", *i );\n\t\t\tif( i[1] )\n\t\t\t\tvips_buf_appends( &buf, \"; \" );\n\t\t}\n\telse\n\t\t/* No suffix means any allowed.\n\t\t */\n\t\tvips_buf_appendf( &buf, \"*\" );\n\n\tvips_buf_appends( &buf, \")\" );\n\n\ttype->name = g_strdup( vips_buf_all( &buf ) );\n\ttype->suffixes = format->suffs;\n\n\t*types = g_slist_append( *types, type );\n\n\treturn( NULL );\n}\n\n/* Look at the registered VIPS formats, build a file type list. Call from\n * filesel class init.\n */\nstatic FileselFileType **\nbuild_image_file_type( void )\n{\n\tGSList *types;\n\tFileselFileType **type_array;\n\n\ttypes = NULL;\n\tvips_format_map( (VSListMap2Fn) build_vips_formats_sub, &types, NULL );\n\n\ttype_array = (FileselFileType **) slist_to_array( types );\n\tg_slist_free( types );\n\n\treturn( type_array );\n}\n\n/* Combine a NULL-terminated list of FileselFileType arrays into one.\n */\nstatic FileselFileType **\nbuild_file_type_va( FileselFileType **first, ... )\n{\n\tva_list args;\n\tint len;\n\tFileselFileType **i;\n\tFileselFileType **array;\n\tint j;\n\tint k;\n\n\t/* Count total number of items.\n\t */\n\tlen = 0;\n\tva_start( args, first );\n\tfor( i = first; i; i = va_arg( args, FileselFileType ** ) )\n\t\tlen += array_len( (void **) i );\n\tva_end( args );\n\n\t/* Copy and NULL-terminate.\n\t */\n\tarray = g_new( FileselFileType *, len + 1 );\n\tva_start( args, first );\n\tj = 0;\n\tfor( i = first; i; i = va_arg( args, FileselFileType ** ) ) \n\t\tfor( k = 0; i[k]; k++ )\n\t\t\tarray[j++] = i[k];\n\tva_end( args );\n\tarray[j] = NULL;\n\n\treturn( array );\n}\n\n/* Here from main() during startup. We can't just put this in class_init,\n * because we want to be sure this happens early on.\n */\nvoid\nfilesel_startup( void )\n{\n\tfilesel_type_image = build_image_file_type();\n\tfilesel_type_mainw = build_file_type_va( filesel_type_image, \n\t\tfilesel_type_matrix, filesel_type_workspace, NULL );\n\tfilesel_type_any = build_file_type_va( filesel_type_mainw,\n\t\tfilesel_type_definition, NULL );\n}\n\n/* Is a file of type ... just look at the suffix.\n */\ngboolean\nis_file_type( const FileselFileType *type, const char *filename )\n{\n\tconst char **p;\n\tconst char *suf;\n\n\tif( (suf = strrchr( filename, '.' )) ) {\n\t\tfor( p = type->suffixes; *p; p++ )\n\t\t\tif( strcasecmp( suf, *p ) == 0 )\n\t\t\t\treturn( TRUE );\n\t}\n\n\treturn( FALSE );\n}\n\n/* Map TIFF formats to char* for VIPS.\n */\nstatic char *\ndecode_tiff_compression( TiffCompression tc )\n{\n\tswitch( tc ) {\n\tcase TIFF_COMPRESSION_LZW:\treturn( \"lzw\" );\n\tcase TIFF_COMPRESSION_DEFLATE:\treturn( \"deflate\" );\n\tcase TIFF_COMPRESSION_PACKBITS:\treturn( \"packbits\" );\n\tcase TIFF_COMPRESSION_JPEG:\treturn( \"jpeg\" );\n\tcase TIFF_COMPRESSION_CCITTFAX4:return( \"ccittfax4\" );\n\n\tcase TIFF_COMPRESSION_NONE:\n\tdefault:\n\t\treturn( \"none\" );\n\t}\n}\n\nstatic char *\ndecode_tiff_layout( TiffLayout tf )\n{\n\tswitch( tf ) {\n\tcase TIFF_LAYOUT_TILE:\t\treturn( \"tile\" );\n\n\tcase TIFF_LAYOUT_STRIP:\n\tdefault:\n\t\treturn( \"strip\" );\n\t}\n}\n\nstatic char *\ndecode_tiff_multires( TiffMultires tm )\n{\n\tswitch( tm ) {\n\tcase TIFF_MULTIRES_PYRAMID:\treturn( \"pyramid\" );\n\n\tcase TIFF_MULTIRES_FLAT:\n\tdefault:\n\t\treturn( \"flat\" );\n\t}\n}\n\nstatic char *\ndecode_tiff_format( TiffFormat tm )\n{\n\tswitch( tm ) {\n\tcase TIFF_FORMAT_ONEBIT:\treturn( \"onebit\" );\n\n\tcase TIFF_FORMAT_MANYBIT:\n\tdefault:\n\t\treturn( \"manybit\" );\n\t}\n}\n\n/* Make a TIFF save format string.\n */\nstatic void\nfilesel_tiff_mode( char *out )\n{\n\tchar ctype[FILENAME_MAX];\n\tchar ltype[FILENAME_MAX];\n\tchar buf[FILENAME_MAX];\n\n\tstrcpy( ctype, decode_tiff_compression( IP_TIFF_COMPRESSION ) );\n\tif( IP_TIFF_COMPRESSION == TIFF_COMPRESSION_JPEG ) {\n\t\tim_snprintf( buf, FILENAME_MAX, \":%d\", IP_TIFF_JPEG_Q );\n\t\tstrcat( ctype, buf );\n\t}\n\tif( IP_TIFF_COMPRESSION == TIFF_COMPRESSION_DEFLATE ||\n\t\tIP_TIFF_COMPRESSION == TIFF_COMPRESSION_LZW ) {\n\t\tim_snprintf( buf, FILENAME_MAX, \":%d\", IP_TIFF_PREDICTOR + 1 );\n\t\tstrcat( ctype, buf );\n\t}\n\n\tstrcpy( ltype, decode_tiff_layout( IP_TIFF_LAYOUT ) );\n\tif( IP_TIFF_LAYOUT == TIFF_LAYOUT_TILE ) {\n\t\tim_snprintf( buf, FILENAME_MAX, \":%dx%d\", \n\t\t\tIP_TIFF_TILE_WIDTH,\n\t\t\tIP_TIFF_TILE_WIDTH );\n\t\tstrcat( ltype, buf );\n\t}\n\n\tim_snprintf( out, 256, \"%s,%s,%s,%s,,,%s\", \n\t\tctype, ltype, \n\t\tdecode_tiff_multires( IP_TIFF_MULTI_RES ),\n\t\tdecode_tiff_format( IP_TIFF_FORMAT ),\n\t\tIP_TIFF_BIGTIFF ? \"8\" : \"\" );\n}\n\n/* Make a JPEG save format string.\n */\nstatic void\nfilesel_jpeg_mode( char *out )\n{\n\tchar profile[FILENAME_MAX];\n\n\tswitch( IP_JPEG_ICC_PROFILE ) {\n\tcase 0:\n\t\t/* Use embedded profile ... do nothing.\n\t\t */\n\t\tstrcpy( profile, \"\" );\n\n\t\tbreak;\n\n\tcase 1:\n\t{\n\t\t/* Embed from file.\n\t\t */\n\t\tchar buf[FILENAME_MAX];\n\t\tchar buf2[FILENAME_MAX];\n\n\t\tim_strncpy( buf, IP_JPEG_ICC_PROFILE_FILE, FILENAME_MAX );\n\t\texpand_variables( buf, buf2 );\n\t\tnativeize_path( buf2 );\n\t\tim_snprintf( profile, FILENAME_MAX, \",%s\", buf2 );\n\n\t\tbreak;\n\t}\n\n\tcase 2:\n\t\t/* Don't attach a profile.\n\t\t */\n\t\tim_snprintf( profile, FILENAME_MAX, \",none\" );\n\t\tbreak;\n\n\tdefault:\n\t\t/* Again, do nothing.\n\t\t */\n\t\tstrcpy( profile, \"\" );\n\n\t\tbreak;\n\t}\n\n\tim_snprintf( out, 256, \"%d%s\", IP_JPEG_Q, profile );\n}\n\n/* Make a PNG save format string.\n */\nstatic void\nfilesel_png_mode( char *out )\n{\n\tim_snprintf( out, 256, \"%d,%d\", IP_PNG_COMPRESSION, IP_PNG_INTERLACE );\n}\n\n/* Make a PPM save format string.\n */\nstatic void\nfilesel_ppm_mode( char *out )\n{\n\tswitch( IP_PPM_MODE ) {\n\tcase 0:\n\t\tim_snprintf( out, 256, \"binary\" );\n\t\tbreak;\n\n\tdefault:\n\t\tim_snprintf( out, 256, \"ascii\" );\n\t\tbreak;\n\t}\n}\n\n/* Make a CSV save format string.\n */\nstatic void\nfilesel_csv_mode( char *out )\n{\n\t/* We have to escape \":\" and \",\" characters in the separator string.\n\t */\n\tchar separator[256];\n\n\tescape_mode( IP_CSV_SEPARATOR, separator, 256 );\n\n\tim_snprintf( out, 256, \"sep:%s\", separator );\n}\n\ntypedef void (*make_mode_fn)( char *buf );\n\ntypedef struct {\n\tconst char *caption_filter;\t/* nip2 column name for the format */\n\tconst char *name;\t\t/* vips nickname for the format */\n\tmake_mode_fn mode_fn;\t\t/* Build a mode string */\n} FileselMode;\n\nstatic FileselMode filesel_mode_table[] = {\n\t{ \"JPEG\", \"jpeg\", filesel_jpeg_mode },\n\t{ \"PNG\", \"png\", filesel_png_mode },\n\t{ \"TIFF\", \"tiff\", filesel_tiff_mode },\n\t{ \"CSV\", \"csv\", filesel_csv_mode },\n\t{ \"PPM\", \"ppm\", filesel_ppm_mode }\n};\n\nstatic FileselMode *\nfilesel_get_mode( const char *filename )\n{\n\tint i;\n\tVipsFormatClass *format;\n\n\tif( (format = vips_format_for_name( filename )) ) {\n\t\tVipsObjectClass *object_class = VIPS_OBJECT_CLASS( format );\n\n\t\tfor( i = 0; i < IM_NUMBER( filesel_mode_table ); i++ )\n\t\t\tif( strcmp( filesel_mode_table[i].name, \n\t\t\t\tobject_class->nickname ) == 0 ) \n\t\t\t\treturn( &filesel_mode_table[i] );\n\t}\n\telse\n\t\tim_error_clear();\n\n\treturn( NULL );\n}\n\n/* Add our image save settings to the end of a filename. filename must be\n * at least FILENAME_MAX characters in size.\n */\nvoid\nfilesel_add_mode( char *filename )\n{\n\tFileselMode *mode;\n\n\tif( (mode = filesel_get_mode( filename )) ) {\n\t\tchar ext[256];\n\t\tint l = strlen( filename );\n\n\t\tmode->mode_fn( ext );\n\t\tim_snprintf( filename + l, FILENAME_MAX - l, \":%s\", ext );\n\t}\n}\n\nstatic const char *\nfilesel_get_filter( const char *filename )\n{\n\tFileselMode *mode;\n\n\tif( (mode = filesel_get_mode( filename )) ) \n\t\treturn( mode->caption_filter );\n\n\treturn( NULL );\n}\n\nstatic void\nfilesel_destroy( GtkObject *object )\n{\n\tFilesel *filesel;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_FILESEL( object ) );\n\n\tfilesel = FILESEL( object );\n\n\tfilesel_all = g_slist_remove( filesel_all, filesel );\n\tIM_FREEF( g_free, filesel->current_dir );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\n/* Update `space free' label.\n */\nstatic void\nfilesel_space_update( Filesel *filesel, const char *dirname )\n{\n\tdouble sz = find_space( dirname );\n\n\tif( filesel->space ) {\n\t\tif( sz < 0 )\n\t\t\tset_glabel( filesel->space, \n\t\t\t\t_( \"Unable to determine \"\n\t\t\t\t\t\"space free in \\\"%s\\\".\" ), \n\t\t\t\tdirname );\n\t\telse {\n\t\t\tchar txt[MAX_STRSIZE];\n\t\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\t\tvips_buf_append_size( &buf, sz );\n\t\t\tvips_buf_appendf( &buf, \" \" );\n\t\t\t/* Expands to (eg.) '6GB free in \"/pics/tmp\"'\n\t\t\t */\n\t\t\tvips_buf_appendf( &buf, _( \"free in \\\"%s\\\"\" ), dirname );\n\t\t\tset_glabel( filesel->space, \"%s\", vips_buf_all( &buf ) );\n\t\t}\n\t}\n}\n\nstatic void *\nfilesel_add_volume( const char *dir, Filesel *filesel )\n{\n\tchar buf[FILENAME_MAX];\n\n\tim_strncpy( buf, dir, FILENAME_MAX );\n\tpath_expand( buf );\n\n\tgtk_file_chooser_add_shortcut_folder( \n\t\tGTK_FILE_CHOOSER( filesel->chooser ), buf, NULL );\n\n\treturn( NULL );\n}\n\nstatic void\nfilesel_suffix_to_glob( const char *suffix, VipsBuf *patt )\n{\n\tint i;\n\tchar ch;\n\n\tvips_buf_appends( patt, \"*\" );\n\n\tfor( i = 0; (ch = suffix[i]); i++ ) {\n\t\tif( isalpha( ch ) ) {\n\t\t\tvips_buf_appends( patt, \"[\" );\n\t\t\tvips_buf_appendf( patt, \"%c\", toupper( ch ) );\n\t\t\tvips_buf_appendf( patt, \"%c\", tolower( ch ) );\n\t\t\tvips_buf_appends( patt, \"]\" );\n\t\t}\n\t\telse\n\t\t\tvips_buf_appendf( patt, \"%c\", ch );\n\t}\n}\n\n/* Make a shell glob from a filetype.\n */\nvoid\nfilesel_make_patt( FileselFileType *type, VipsBuf *patt )\n{\n\tint i;\n\n\t/* Only use {} braces if there's more than one suffix to match.\n\t */\n\tif( type->suffixes[1] )\n\t\tvips_buf_appends( patt, \"{\" );\n\n\tfor( i = 0; type->suffixes[i]; i++ ) {\n\t\tif( i > 0 )\n\t\t\tvips_buf_appends( patt, \",\" );\n\n\t\tfilesel_suffix_to_glob( type->suffixes[i], patt );\n\t}\n\n\tif( type->suffixes[1] )\n\t\tvips_buf_appends( patt, \"}\" );\n}\n\nstatic char *\nfilesel_get_dir( Filesel *filesel )\n{\n\treturn( gtk_file_chooser_get_current_folder(\n\t\tGTK_FILE_CHOOSER( filesel->chooser ) ) );\n}\n\nstatic void\nfilesel_dir_enter( Filesel *filesel )\n{\n\tchar *dir = filesel_get_dir( filesel );\n\n\tif( !filesel->current_dir || \n\t\t(dir && strcmp( filesel->current_dir, dir ) != 0) ) {\n\t\tfilesel_space_update( filesel, dir );\n\t\tif( !filesel->start_name )\n\t\t\tIM_SETSTR( filesel_last_dir, dir );\n\n\t\tfilesel->current_dir = dir;\n\t\tdir = NULL;\n\t}\n\n\tg_free( dir );\n}\n\n/* New dir entered signal.\n */\nstatic void\nfilesel_current_folder_changed_cb( GtkWidget *widget, gpointer data )\n{\n\tfilesel_dir_enter( FILESEL( data ) );\n}\n\n/* Update file info display.\n */\nstatic void\nfilesel_info_update( Filesel *filesel, const char *name )\n{\n\tif( filesel->info ) {\n\t\tchar txt[MAX_STRSIZE];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\tget_image_info( &buf, name );\n\t\tset_glabel( filesel->info, \"%s\", vips_buf_firstline( &buf ) );\n\t}\n}\n\nint\nfilesel_get_filetype( Filesel *filesel )\n{\n\tint type;\n\tGtkFileFilter *filter;\n\n\ttype = filesel->default_type;\n\n\tif( filesel->chooser &&\n\t\t(filter = gtk_file_chooser_get_filter( \n\t\t\tGTK_FILE_CHOOSER( filesel->chooser ) )) )  {\n\t\tint i;\n\n\t\tfor( i = 0; filesel->filter[i]; i++ ) \n\t\t\tif( filter == filesel->filter[i] )\n\t\t\t\tbreak;\n\t\tg_assert( filesel->filter[i] );\n\n\t\ttype = i;\n\t}\n\n#ifdef DEBUG\n\tprintf( \"filesel_get_filetype: %d\\n\", type ); \n#endif /*DEBUG*/\n\n\treturn( type );\n}\n\n/* Find the index of the type which matches this filename.\n */\nstatic int\nfilesel_find_file_type( FileselFileType **type, const char *filename )\n{\n\tint i, j;\n\n\tfor( i = 0; type[i]; i++ ) \n\t\tfor( j = 0; type[i]->suffixes[j]; j++ ) \n\t\t\tif( is_casepostfix( type[i]->suffixes[j], filename ) )\n\t\t\t\treturn( i );\n\n\treturn( -1 );\n}\n\nstatic void\nfilesel_set_filter( Filesel *filesel, GtkFileFilter *filter )\n{\n#ifdef DEBUG\n\tprintf( \"filesel_set_filter: %p\\n\", filter ); \n#endif /*DEBUG*/\n\n\tg_assert( filter );\n\n\tgtk_file_chooser_set_filter( GTK_FILE_CHOOSER( filesel->chooser ),\n\t\tfilter );\n}\n\nstatic void\nfilesel_set_filetype_from_filename( Filesel *filesel, const char *name )\n{\n\tint type;\n\tint i;\n\tchar *p;\n\n\t/* If we're showing \"all\", any filename is OK, so don't change the file\n\t * type.\n\t */\n\ttype = filesel_get_filetype( filesel );\n\tif( type == filesel->ntypes - 1 )\n\t\treturn;\n\n\t/* If we've not got a sensible filename, don't bother.\n\t */\n\tif( (p = strrchr( name, G_DIR_SEPARATOR )) &&\n\t\tstrspn( p + 1, \" \\n\\t\" ) == strlen( p + 1 ) ) \n\t\treturn;\n\n\tif( (i = filesel_find_file_type( filesel->type, name )) >= 0 )\n\t\tfilesel_set_filter( filesel, filesel->filter[i] );\n\telse\n\t\t/* No match, or no suffix. Set the last type (should be \"All\").\n\t\t */\n\t\tfilesel_set_filter( filesel, \n\t\t\tfilesel->filter[filesel->ntypes - 1] );\n}\n\ngboolean \nfilesel_set_filename( Filesel *filesel, const char *name )\n{\n\tchar buf[FILENAME_MAX];\n\n\tif( !is_valid_filename( name ) ) \n\t\treturn( FALSE );\n\n\tim_strncpy( buf, name, FILENAME_MAX );\n\tpath_expand( buf );\n\n#ifdef DEBUG\n\tprintf( \"filesel_set_filename: %s\\n\", buf ); \n#endif /*DEBUG*/\n\n\t/* set_filename() will only select existing files, we need to be able\n\t * to set any filename (eg. for increment filename), so we have to\n\t * set_current_name() as well.\n\t */\n\tgtk_file_chooser_set_filename( \n\t\tGTK_FILE_CHOOSER( filesel->chooser ), buf );\n\n\tif( filesel->save )\n\t\tgtk_file_chooser_set_current_name(\n\t\t\tGTK_FILE_CHOOSER( filesel->chooser ), \n\t\t\tim_skip_dir( buf ) );\n\n\tfilesel->start_name = TRUE;\n\n\t/* We have to set this after setting the filename.\n\t */\n\tfilesel_set_filetype_from_filename( filesel, buf );\n\n\treturn( TRUE );\n}\n\n/* Read the filename out ... test for sanity.\n */\nchar *\nfilesel_get_filename( Filesel *filesel )\n{\n\tchar *name;\n\tchar tmp[FILENAME_MAX];\n\n\tname = gtk_file_chooser_get_filename(\n\t\tGTK_FILE_CHOOSER( filesel->chooser ) );\n\n#ifdef DEBUG\n\tprintf( \"filesel_get_filename: %s\\n\", name ); \n#endif /*DEBUG*/\n\n\tif( !name ) {\n\t\terror_top( _( \"Bad filename.\" ) );\n\t\terror_sub( _( \"No file selected.\" ) );\n\t\treturn( NULL );\n\t}\n\tif( !is_valid_filename( name ) ) {\n\t\tg_free( name );\n\t\treturn( NULL );\n\t}\n\n\t/* Rewrite to compact form, eg. \"$HOME/fred\".\n\t */\n\tim_strncpy( tmp, name, FILENAME_MAX );\n\tpath_compact( tmp );\n\tg_free( name );\n\n\treturn( g_strdup( tmp ) );\n}\n\n/* Get filename multi ... map over the selected filenames.\n */\nvoid *\nfilesel_map_filename_multi( Filesel *filesel,\n\tFileselMapFn fn, void *a, void *b )\n{\n\tGSList *names = gtk_file_chooser_get_filenames( \n\t\tGTK_FILE_CHOOSER( filesel->chooser ) );\n\tGSList *p;\n\n\tfor( p = names; p; p = p->next ) {\n\t\tchar *filename = (char *) p->data;\n\n\t\tchar tmp[FILENAME_MAX];\n\t\tvoid *res;\n\n\t\tim_strncpy( tmp, filename, FILENAME_MAX );\n\t\tpath_compact( tmp );\n\n\t\tif( (res = fn( filesel, tmp, a, b )) ) {\n\t\t\tIM_FREEF( slist_free_all, names );\n\t\t\treturn( res );\n\t\t}\n\t}\n\tIM_FREEF( slist_free_all, names );\n\n\treturn( NULL );\n}\n\n/* New file selected signal.\n */\nstatic void\nfilesel_selection_changed_cb( GtkWidget *widget, gpointer data )\n{\n\tFilesel *filesel = FILESEL( data );\n        char *filename;\n\n#ifdef DEBUG\n\tprintf( \"filesel_selection_changed_cb: %s\\n\", \n\t\tNN( IWINDOW( filesel )->title ) );\n#endif /*DEBUG*/\n\n\tif( (filename = filesel_get_filename( filesel )) ) {\n#ifdef DEBUG\n\t\tprintf( \"filesel_selection_changed_cb: %s - \\\"%s\\\"\\n\", \n\t\t\tNN( IWINDOW( filesel )->title ), filename );\n#endif /*DEBUG*/\n\n\t\tfilesel_info_update( filesel, filename );\n\t\tg_free( filename );\n\t}\n}\n\nstatic void\nfilesel_file_activated_cb( GtkWidget *widget, gpointer data )\n{\n\tidialog_done_trigger( IDIALOG( data ), 0 );\n}\n\n/* Increment filename on OK.\n */\nstatic void\nfilesel_auto_incr_cb( GtkWidget *tog, Filesel *filesel )\n{\n        filesel->incr = GTK_TOGGLE_BUTTON( tog )->active;\n\n\tif( filesel->incr )\n\t\tidialog_set_pinup( IDIALOG( filesel ), TRUE );\n}\n\nstatic void\nfilesel_update_preview_cb( GtkFileChooser *chooser, Filesel *filesel )\n{\n        char *filename;\n\n\tif( (filename = gtk_file_chooser_get_preview_filename(\n\t\tGTK_FILE_CHOOSER( filesel->chooser ) )) ) {\n\t\tpreview_set_filename( filesel->preview, filename );\n\t\tg_free( filename );\n\t}\n}\n\nstatic GtkFileFilter *\nfile_filter_from_file_type( FileselFileType *type )\n{\n\tGtkFileFilter *filter;\n\tint j;\n\t\n\tfilter = gtk_file_filter_new();\n\tgtk_file_filter_set_name( filter, _( type->name ) );\n\n\tif( type->suffixes[0] )\n\t\tfor( j = 0; type->suffixes[j]; j++ ) {\n\t\t\tchar txt[FILENAME_MAX];\n\t\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\t\tfilesel_suffix_to_glob( type->suffixes[j], &buf );\n\t\t\tgtk_file_filter_add_pattern( filter, \n\t\t\t\tvips_buf_all( &buf ) );\n\t\t}\n\telse\n\t\t/* No suffix list means any suffix allowed.\n\t\t */\n\t\tgtk_file_filter_add_pattern( filter, \"*\" );\n\n\treturn( filter );\n}\n\nstatic void\nfilesel_add_filter( Filesel *filesel, FileselFileType *type, int i )\n{\n\tfilesel->filter[i] = file_filter_from_file_type( type );\n\n#ifdef DEBUG\n\tprintf( \"filesel_add_filter: %p (%d)\\n\", filesel->filter[i], i ); \n#endif /*DEBUG*/\n\n\tgtk_file_chooser_add_filter( GTK_FILE_CHOOSER( filesel->chooser ),\n\t\tfilesel->filter[i] );\n\n\tif( i == filesel->default_type )\n\t\tfilesel_set_filter( filesel, filesel->filter[i] );\n}\n\nstatic void\nfilesel_build( GtkWidget *widget )\n{\n\tFilesel *filesel = FILESEL( widget );\n\tiDialog *idlg = IDIALOG( widget );\n\n\tint i;\n\tFileselFileType *type;\n\tGtkWidget *vb;\n\tGtkWidget *tog;\n\n#ifdef DEBUG\n\tprintf( \"filesel_build: %s\\n\", NN( IWINDOW( filesel )->title ) );\n#endif /*DEBUG*/\n\n\t/* Call all builds in superclasses.\n\t */\n\tif( IWINDOW_CLASS( parent_class )->build )\n\t\tIWINDOW_CLASS( parent_class )->build( widget );\n\n\tfilesel->chooser = gtk_file_chooser_widget_new( filesel->save ? \n\t\t\tGTK_FILE_CHOOSER_ACTION_SAVE :\n\t\t\tGTK_FILE_CHOOSER_ACTION_OPEN );\n\tgtk_file_chooser_set_select_multiple( \n\t\tGTK_FILE_CHOOSER( filesel->chooser ), filesel->multi );\n        gtk_box_pack_start( GTK_BOX( idlg->work ), \n\t\tfilesel->chooser, TRUE, TRUE, 0 );\n\tgtk_widget_show( filesel->chooser );\n\n\t/* Add data path to volumes.\n\t */\n        slist_map( PATH_SEARCH,\n\t\t(SListMapFn) filesel_add_volume, filesel );\n\n\t/* Add all the supported file types. Add \"all\" to the end.\n\t */\n\tfor( i = 0; (type = filesel->type[i]); i++ ) \n\t\tfilesel_add_filter( filesel, type, i );\n\tfilesel_add_filter( filesel, &filesel_allfile_type, i );\n\n        /* Spot changes.\n         */\n        gtk_signal_connect( GTK_OBJECT( filesel->chooser ), \n\t\t\"current-folder-changed\",\n                GTK_SIGNAL_FUNC( filesel_current_folder_changed_cb ), filesel );\n        gtk_signal_connect( GTK_OBJECT( filesel->chooser ), \n\t\t\"selection-changed\",\n                GTK_SIGNAL_FUNC( filesel_selection_changed_cb ), filesel );\n        gtk_signal_connect( GTK_OBJECT( filesel->chooser ), \n\t\t\"file-activated\",\n                GTK_SIGNAL_FUNC( filesel_file_activated_cb ), filesel );\n\n\t/* Pack extra widgets.\n\t */\n        vb = gtk_vbox_new( FALSE, 6 );\n\tgtk_file_chooser_set_extra_widget(\n\t\tGTK_FILE_CHOOSER( filesel->chooser ), vb );\n\tgtk_widget_show( vb );\n\n        /* Space free label. \n         */\n\tif( filesel->save ) {\n\t\tfilesel->space = gtk_label_new( \"\" );\n\t\tgtk_misc_set_alignment( GTK_MISC( filesel->space ), 0, 0.5 );\n\t\tgtk_box_pack_start( GTK_BOX( vb ), \n\t\t\tfilesel->space, FALSE, FALSE, 0 );\n\t\tgtk_widget_show( filesel->space );\n\t}\n\n        /* File info label.\n         */\n\tif( !filesel->save ) {\n\t\tfilesel->info = gtk_label_new( \"\" );\n\t\tgtk_misc_set_alignment( GTK_MISC( filesel->info ), 0, 0.5 );\n\t\tgtk_box_pack_start( GTK_BOX( vb ), \n\t\t\tfilesel->info, FALSE, FALSE, 0 );\n\t\tgtk_widget_show( filesel->info );\n\t}\n\n        /* Auto-increment toggle.\n         */\n\tif( filesel->save ) {\n\t\ttog = gtk_check_button_new_with_label( \n\t\t\t_( \"Increment filename\" ) );\n\t\tgtk_signal_connect( GTK_OBJECT( tog ), \"toggled\",\n\t\t\tGTK_SIGNAL_FUNC( filesel_auto_incr_cb ), filesel );\n\t\tgtk_box_pack_start( GTK_BOX( vb ), tog, FALSE, FALSE, 0 );\n\t\tgtk_widget_show( tog );\n\t\tset_tooltip( tog, \n\t\t\t_( \"After Save, add 1 to the last number in the \"\n\t\t\t\"file name\" ) );\n\t}\n\n        if( filesel->imls ) {\n\t\tfilesel->preview = preview_new();\n\t\tgtk_file_chooser_set_preview_widget(\n\t\t\tGTK_FILE_CHOOSER( filesel->chooser ), \n\t\t\tGTK_WIDGET( filesel->preview ) );\n\t\tgtk_signal_connect( GTK_OBJECT( filesel->chooser ), \n\t\t\t\"update-preview\",\n\t\t\tGTK_SIGNAL_FUNC( filesel_update_preview_cb ), filesel );\n\t\tgtk_widget_show( GTK_WIDGET( filesel->preview ) );\n\t\tgtk_file_chooser_set_preview_widget_active(\n\t\t\tGTK_FILE_CHOOSER( filesel->chooser ), TRUE );\n\t}\n\n\tif( filesel_last_dir ) \n\t\tgtk_file_chooser_set_current_folder(\n\t\t\tGTK_FILE_CHOOSER( filesel->chooser ), \n\t\t\tfilesel_last_dir );\n\n\t/* Save boxes can be much smaller.\n\t */\n\tif( !filesel->save )\n\t\tgtk_window_set_default_size( GTK_WINDOW( filesel ), 600, 500 );\n}\n\nstatic void\nfilesel_class_init( FileselClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tiWindowClass *iwindow_class = (iWindowClass *) class;\n\n\tobject_class->destroy = filesel_destroy;\n\n\tiwindow_class->build = filesel_build;\n\n\tparent_class = g_type_class_peek_parent( class );\n}\n\n/* Increment filename. If there's no number there now, assume zero.\n */\nstatic void\nfilesel_increment_filename( Filesel *filesel )\n{\n        char *filename;\n\n\tif( (filename = filesel_get_filename( filesel )) ) {\n\t\tchar name[FILENAME_MAX];\n\n\t\tim_strncpy( name, filename, FILENAME_MAX );\n\t\tg_free( filename );\n\t\tincrement_filename( name );\n\n\t\t(void) filesel_set_filename( filesel, name );\n\t}\n}\n\nstatic void *\nfilesel_refresh( Filesel *filesel )\n{\n\tchar *dir;\n\n\tif( (dir = gtk_file_chooser_get_current_folder( \n\t\tGTK_FILE_CHOOSER( filesel->chooser ) )) ) { \n\t\tgtk_file_chooser_set_current_folder(\n\t\t\tGTK_FILE_CHOOSER( filesel->chooser ), dir );\n\t\tg_free( dir );\n\t}\n\n        return( NULL );\n}\n\n/* There may be a new file ... ask all fsb's to refresh.\n */\nvoid\nfilesel_refresh_all( void )\n{\n        (void) slist_map( filesel_all, (SListMapFn) filesel_refresh, NULL );\n}\n\nstatic void\nfilesel_init( Filesel *filesel )\n{\n\tint i;\n\n#ifdef DEBUG\n\tprintf( \"filesel_init: %s\\n\", NN( IWINDOW( filesel )->title ) );\n#endif /*DEBUG*/\n\n\tfilesel->chooser = NULL;\n\tfilesel->space = NULL;\n\tfilesel->info = NULL;\n\tfilesel->preview = NULL;\n\tfor( i = 0; i < FILESEL_MAX_FILTERS; i++ )\n\t\tfilesel->filter[i] = NULL;\n\tfilesel->incr = FALSE;\n\tfilesel->imls = FALSE;\n\tfilesel->save = FALSE;\n\tfilesel->multi = FALSE;\n\tfilesel->start_name = FALSE;\n\tfilesel->type = NULL;\n\tfilesel->default_type = 0;\n\tfilesel->type_pref = NULL;\n\tfilesel->current_dir = NULL;\n\tfilesel->done_cb = NULL;\n\tfilesel->client = NULL;\n\n\tidialog_set_callbacks( IDIALOG( filesel ), \n\t\tiwindow_true_cb, NULL, NULL, NULL );\n\tidialog_set_pinup( IDIALOG( filesel ), TRUE );\n\tidialog_set_nosep( IDIALOG( filesel ), TRUE );\n\tidialog_set_button_focus( IDIALOG( filesel ), FALSE );\n\tidialog_set_help_tag( IDIALOG( filesel ), \"sec:loadsave\" );\n\n\tfilesel_all = g_slist_prepend( filesel_all, filesel );\n}\n\nGtkType\nfilesel_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Filesel\",\n\t\t\tsizeof( Filesel ),\n\t\t\tsizeof( FileselClass ),\n\t\t\t(GtkClassInitFunc) filesel_class_init,\n\t\t\t(GtkObjectInitFunc) filesel_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_IDIALOG, &info );\n\t}\n\n\treturn( type );\n}\n\nGtkWidget *\nfilesel_new( void )\n{\n\tFilesel *filesel = (Filesel *) gtk_type_new( TYPE_FILESEL );\n\n\tiwindow_set_size_prefs( IWINDOW( filesel ), \n\t\t\"FILESEL_WINDOW_WIDTH\", \"FILESEL_WINDOW_HEIGHT\" );\n\n\treturn( GTK_WIDGET( filesel ) );\n}\n\nvoid \nfilesel_set_done( Filesel *filesel, iWindowFn done_cb, void *client )\n{\n\tfilesel->done_cb = done_cb;\n\tfilesel->client = client;\n}\n\n/* Back from the user function ... unset the hourglass, and update.\n */\nstatic void\nfilesel_trigger2( void *sys, iWindowResult result )\n{\n\tiWindowSusp *susp = (iWindowSusp *) sys;\n\tFilesel *filesel = FILESEL( susp->client );\n\n\tprogress_end();\n\n\t/* If this is a save, assume that there is now a new file, \n\t * and ask all fsb's to update.\n\t */\n\tif( filesel->save && result != IWINDOW_ERROR )\n\t\tfilesel_refresh_all();\n\n\tif( result != IWINDOW_YES ) {\n\t\t/* Failure ... bomb out.\n\t\t */\n\t\tiwindow_susp_return( susp, result );\n\t\treturn;\n\t}\n\n\t/* Increment the filename, if required.\n\t */\n\tif( filesel->incr ) {\n\t\tfilesel_increment_filename( filesel );\n\t\tfilesel_refresh( filesel );\n\t}\n\n\t/* Success!\n\t */\n\tiwindow_susp_return( susp, result );\n}\n\n/* Start of user done ... shut down our suspension, and set the hglass.\n */\nstatic void\nfilesel_trigger( Filesel *filesel, iWindow *iwnd, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\t/* Suspend the callback for a bit.\n\t */\n\tiWindowSusp *susp = iwindow_susp_new( NULL, iwnd, filesel, nfn, sys );\n\n\t/* If there's a filetype pref, update it.\n\t */\n\tif( filesel->type_pref )\n\t\tprefs_set( filesel->type_pref, \n\t\t\t\"%d\", filesel_get_filetype( filesel ) );\n\n\tprogress_begin();\n\tfilesel->done_cb( IWINDOW( filesel ), \n\t\tfilesel->client, filesel_trigger2, susp );\n}\n\nstatic void\nfilesel_prefs_ok_cb( iWindow *iwnd, void *client,\n\tiWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( client );\n\n\t/* Force a recalc, in case we've changed the autorecalc \n\t * settings. Also does a scan on any widgets.\n\t */\n\tsymbol_recalculate_all_force( TRUE );\n\n\tfilesel_trigger( filesel, iwnd, nfn, sys );\n}\n\nstatic void\nfilesel_prefs( Filesel *filesel, iWindow *iwnd, \n\tconst char *caption_filter, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tPrefs *prefs;\n\n\tif( !(prefs = prefs_new( caption_filter )) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\t/* Expands to (eg.) \"TIFF Save Preferences\".\n\t */\n\tiwindow_set_title( IWINDOW( prefs ), \n\t\t_( \"%s Save Preferences\" ), caption_filter );\n\tiwindow_set_parent( IWINDOW( prefs ), GTK_WIDGET( iwnd ) );\n\tidialog_set_callbacks( IDIALOG( prefs ), \n\t\tiwindow_true_cb, NULL, NULL, filesel );\n\tidialog_add_ok( IDIALOG( prefs ), filesel_prefs_ok_cb, GTK_STOCK_SAVE );\n\tidialog_set_notify( IDIALOG( prefs ), nfn, sys );\n\tiwindow_build( IWINDOW( prefs ) );\n\n\tgtk_widget_show( GTK_WIDGET( prefs ) );\n}\n\n/* We have a filename and it's OK to overwrite. Is it a type for which we have\n * to offer preferences?\n */\nstatic void\nfilesel_yesno_cb( iWindow *iwnd, void *client,\n\tiWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( client );\n\tchar *filename;\n\tconst char *caption_filter;\n\n\tif( filesel->save ) {\n\t\tif( !(filename = filesel_get_filename( filesel )) ) \n\t\t\tnfn( sys, IWINDOW_ERROR );\n\t\telse {\n\t\t\tif( (caption_filter = filesel_get_filter( filename )) ) \n\t\t\t\tfilesel_prefs( filesel, iwnd, caption_filter,\n\t\t\t\t\tnfn, sys );\n\t\t\telse\n\t\t\t\tfilesel_trigger( filesel, iwnd, nfn, sys );\n\n\t\t\tg_free( filename );\n\t\t}\n\t}\n\telse\n\t\tfilesel_trigger( filesel, iwnd, nfn, sys );\n}\n\nstatic void\nfilesel_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( iwnd );\n        char *filename;\n\n#ifdef DEBUG\n\tprintf( \"filesel_done\\n\" );\n#endif /*DEBUG*/\n\n\tif( !(filename = filesel_get_filename( filesel )) ) \n\t\tnfn( sys, IWINDOW_ERROR );\n\telse if( isdir( \"%s\", filename ) ) {\n\t\tnfn( sys, IWINDOW_NO );\n\t}\n\telse {\n\t\t/* File exists and we are saving? Do a yesno before we carry on.\n\t\t */\n\t\tif( filesel->save && existsf( \"%s\", filename ) ) {\n\t\t\tbox_yesno( GTK_WIDGET( filesel ),\n\t\t\t\tfilesel_yesno_cb, iwindow_true_cb, filesel,\n\t\t\t\tnfn, sys,\n\t\t\t\t_( \"Overwrite\" ),\n\t\t\t\t_( \"Overwrite file?\" ),\n\t\t\t\t_( \"File \\\"%s\\\" exists. \"\n\t\t\t\t\"OK to overwrite?\" ), filename );\n\t\t}\n\t\telse\n\t\t\t/* Just call the user function directly.\n\t\t\t */\n\t\t\tfilesel_yesno_cb( iwnd, filesel, nfn, sys );\n\n\t\tg_free( filename );\n\t}\n}\n\nvoid \nfilesel_set_flags( Filesel *filesel, gboolean imls, gboolean save )\n{\n\tfilesel->imls = imls;\n\tfilesel->save = save;\n\n\tidialog_add_ok( IDIALOG( filesel ), filesel_done_cb, \n\t\tsave ? GTK_STOCK_SAVE : GTK_STOCK_OPEN );\n}\n\nvoid \nfilesel_set_filetype( Filesel *filesel, \n\tFileselFileType **type, int default_type )\n{\n\t/* Reset the widget, if it's there.\n\t */\n\tif( filesel->chooser )\n\t\tfilesel_set_filter( filesel, filesel->filter[default_type] );\n\n\tfilesel->type = type;\n\tfilesel->ntypes = array_len( (void **) type );\n\tfilesel->default_type = default_type;\n}\n\nvoid \nfilesel_set_filetype_pref( Filesel *filesel, \n\tconst char *type_pref )\n{\n\tfilesel->type_pref = type_pref;\n}\n\nvoid\nfilesel_set_multi( Filesel *filesel, gboolean multi )\n{\n\tfilesel->multi = multi;\n}\n"
  },
  {
    "path": "src/filesel.h",
    "content": "/* Declarations for ifileselect.c\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n/* How we define a file type. Pass a NULL-terminated array of pointers\n * to these puppies to gtk_file_selection2_set_file_types().\n * gtk_file_selection2_set_file_types() makes a copy of the data itself,\n * so you can free if you want.\n */\ntypedef struct _FileselFileType {\n  /* Descriptive name for this file type. Eg:\n   *\t\"TIFF image file (*.tif; *.tiff)\"\n   */\n  const char *name;\n\n  /* NULL-terminated array of suffixes identifying this \n   * file type. Put the default first. Eg:\n   *\t{ \".tif\", \".tiff\", NULL }, or \n   *\t{ \".htm\", \".html\", NULL }\n   */\n  const char **suffixes;\n} FileselFileType;\n\n/* Basic types.\n */\nextern FileselFileType \n\tfilesel_wfile_type, filesel_rfile_type, \n\tfilesel_mfile_type, filesel_cfile_type, filesel_xfile_type, \n\tfilesel_dfile_type, filesel_ifile_type;\n\n/* Suffix sets we support.\n */\nextern FileselFileType *filesel_type_definition[];\nextern FileselFileType *filesel_type_workspace[];\nextern FileselFileType *filesel_type_matrix[];\nextern FileselFileType **filesel_type_image;\nextern FileselFileType **filesel_type_mainw;\nextern FileselFileType **filesel_type_any;\n\n/* Subclass off gtkfilesel2.c to make one of our fileselectors.\n */\n#define TYPE_FILESEL (filesel_get_type())\n#define FILESEL( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_FILESEL, Filesel ))\n#define FILESEL_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_FILESEL, FileselClass ))\n#define IS_FILESEL( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FILESEL ))\n#define IS_FILESEL_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_FILESEL ))\n\n/* Must be enough. \n */\n#define FILESEL_MAX_FILTERS (100)\n\ntypedef struct _Filesel {\n\tiDialog parent;\n\n        /* Widgets.\n         */\n        GtkWidget *chooser;             /* Filechooser widget */\n        GtkWidget *space;               /* Space available */\n        GtkWidget *info;                /* File info */\n        Preview *preview;\t\t/* Selected file preview */\n\tGtkFileFilter *filter[FILESEL_MAX_FILTERS];\t\n\n\t/* State. \n\t */\n\tgboolean incr;\t\t\t/* True for increment filename */\n\tgboolean imls;\t\t\t/* True if this is image load/save */\n\tgboolean save;\t\t\t/* True if this is a save dialog */\n\tgboolean multi;\t\t\t/* Multiple-select */\n\tgboolean start_name;\t\t/* True if we have a suggested name */\n\n\tFileselFileType **type;\t\t/* Allowable types for this filesel */\n\tint ntypes;\n\tint default_type;\n\tconst char *type_pref;\t\t/* Pref to set on type change */\n\n\t/* Last dir we entered. Used to stop dir_changed being emitted too\n\t * often.\n\t */\n\tchar *current_dir;\n\n\tiWindowFn done_cb;\t\t/* On OK */\n\tvoid *client;\n} Filesel;\n\ntypedef struct _FileselClass {\n\tiDialogClass parent_class;\n\n\t/* My methods.\n\t */\n} FileselClass;\n\nvoid filesel_startup( void );\n\ngboolean is_file_type( const FileselFileType *type, const char *filename );\n\ntypedef void *(*FileselMapFn)( Filesel *, const char *, void *, void * );\n\nvoid filesel_add_mode( char *filename );\n\nGtkType filesel_get_type( void );\nGtkWidget *filesel_new( void );\n\ngboolean filesel_set_filename( Filesel *filesel, const char *name );\nchar *filesel_get_filename( Filesel *filesel );\nvoid *filesel_map_filename_multi( Filesel *filesel,\n\tFileselMapFn fn, void *a, void *b );\n\nvoid filesel_set_done( Filesel *filesel, iWindowFn done_cb, void *client );\nvoid filesel_set_filetype( Filesel *filesel, \n\tFileselFileType **type, int default_type );\nvoid filesel_set_filetype_pref( Filesel *filesel, const char *type_pref );\nint filesel_get_filetype( Filesel *filesel ); \nvoid filesel_make_patt( FileselFileType *type, VipsBuf *patt );\nvoid filesel_set_flags( Filesel *filesel, gboolean imls, gboolean save );\nvoid filesel_set_multi( Filesel *filesel, gboolean multi );\n"
  },
  {
    "path": "src/floatwindow.c",
    "content": "/* abstract base class for floatwindow / plotwindow etc.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic iWindowClass *parent_class = NULL;\n\nstatic void\nfloatwindow_popdown( GtkWidget *widget )\n{\n\tFloatwindow *floatwindow = FLOATWINDOW( widget );\n\tModel *model = floatwindow->model;\n\n#ifdef DEBUG\n\tprintf( \"floatwindow_popdown\\n\" );\n#endif /*DEBUG*/\n\n\t/* We have to note position/size in popdown rather than destroy, since\n\t * the widgets have to all still be extant.\n\t */\n\n\t/* Note position/size for later reuse.\n\t */\n\tmodel->window_width = \n\t\tGTK_WIDGET( floatwindow )->allocation.width;\n\tmodel->window_height = \n\t\tGTK_WIDGET( floatwindow )->allocation.height;\n\tgdk_window_get_root_origin( \n\t\tgtk_widget_get_toplevel( GTK_WIDGET( floatwindow ) )->window, \n\t\t&model->window_x, &model->window_y );\n\n\tIWINDOW_CLASS( parent_class )->popdown( widget );\n}\n\nstatic void\nfloatwindow_build( GtkWidget *widget )\n{\n\tFloatwindow *floatwindow = FLOATWINDOW( widget );\n\tModel *model = floatwindow->model;\n\n\tIWINDOW_CLASS( parent_class )->build( widget );\n\n\t/* Must be set with floatmodel_link before build.\n\t */\n\tg_assert( floatwindow->model );\n\n\t/* Position and size to restore? Come here after parent build, so we\n\t * can override any default settings from there.\n\t */\n\tif( model->window_width != -1 ) {\n\t\tGdkScreen *screen = \n\t\t\tgtk_widget_get_screen( GTK_WIDGET( floatwindow ) );\n\t\tint screen_width = gdk_screen_get_width( screen );\n\t\tint screen_height = gdk_screen_get_height( screen );\n\n\t\t/* We need to clip x/y against the desktop size ... we may be\n\t\t * loading a workspace made on a machine with a big screen on\n\t\t * a machine with a small screen.\n\n\t\t \tFIXME ... we could only clip if the window will be\n\t\t\tcompletely off the screen? ie. ignore\n\t\t\tiimage->window_width etc.\n\n\t\t */\n\n\t\tint window_x = IM_CLIP( 0, model->window_x,\n\t\t\tscreen_width - model->window_width );\n\t\tint window_y = IM_CLIP( 0, model->window_y,\n\t\t\tscreen_height - model->window_height );\n\t\tint window_width = IM_MIN( model->window_width,\n\t\t\tscreen_width );\n\t\tint window_height = IM_MIN( model->window_height,\n\t\t\tscreen_height );\n\n\t\tgtk_widget_set_uposition( GTK_WIDGET( floatwindow ), \n\t\t\twindow_x, window_y );\n\t\tgtk_window_set_default_size( GTK_WINDOW( floatwindow ),\n\t\t\twindow_width, window_height );\n\t}\n}\n\nstatic void\nfloatwindow_class_init( FloatwindowClass *class )\n{\n\tiWindowClass *iwindow_class = (iWindowClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tiwindow_class->build = floatwindow_build;\n\tiwindow_class->popdown = floatwindow_popdown;\n\n\t/* Hmm, this rather negates the point of this class. If we make plot\n\t * and image windows transient for the main window, we don't get\n\t * maximise buttons :-( (on gnome and win anyway).\n\t *\n\t * Keep this class around for now, maybe it'll still be useful.\n\t */\n\tiwindow_class->transient = FALSE;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n}\n\nstatic void\nfloatwindow_init( Floatwindow *floatwindow )\n{\n\tfloatwindow->model = NULL;\n}\n\nGType\nfloatwindow_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( FloatwindowClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) floatwindow_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Floatwindow ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) floatwindow_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_IWINDOW, \n\t\t\t\"Floatwindow\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nvoid\nfloatwindow_link( Floatwindow *floatwindow, Model *model )\n{\n\tfloatwindow->model = model;\n\tdestroy_if_destroyed( G_OBJECT( floatwindow ), \n\t\tG_OBJECT( model ), (DestroyFn) gtk_widget_destroy );\n}\n"
  },
  {
    "path": "src/floatwindow.h",
    "content": "/* abstract base class for imageview / plotwindow etc.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_FLOATWINDOW (floatwindow_get_type())\n#define FLOATWINDOW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_FLOATWINDOW, Floatwindow ))\n#define FLOATWINDOW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_FLOATWINDOW, FloatwindowClass ))\n#define IS_FLOATWINDOW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FLOATWINDOW ))\n#define IS_FLOATWINDOW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_FLOATWINDOW ))\n\ntypedef struct _Floatwindow {\n\tiWindow parent_class;\n\n\t/* Model stuff here.\n\t */\n\tModel *model;\n} Floatwindow;\n\ntypedef struct _FloatwindowClass {\n\tiWindowClass parent_class;\n\n\t/* My methods.\n\t */\n} FloatwindowClass;\n\nGtkType floatwindow_get_type( void );\nvoid floatwindow_link( Floatwindow *floatwindow, Model *model );\n"
  },
  {
    "path": "src/fontname.c",
    "content": "/* an input fontname ... put/get methods\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic void\nfontname_finalize( GObject *gobject )\n{\n\tFontname *fontname = FONTNAME( gobject );\n\n\tIM_FREE( fontname->value );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic View *\nfontname_view_new( Model *model, View *parent )\n{\n\treturn( fontnameview_new() );\n}\n\n/* Members of fontname we automate.\n */\nstatic ClassmodelMember fontname_members[] = {\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_CAPTION, \"caption\", N_( \"Caption\" ),\n\t\tG_STRUCT_OFFSET( iObject, caption ) },\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_VALUE, \"value\", N_( \"Value\" ),\n\t\tG_STRUCT_OFFSET( Fontname, value ) }\n};\n\nstatic void\nfontname_class_init( FontnameClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = fontname_finalize;\n\n\tmodel_class->view_new = fontname_view_new;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n\n\tclassmodel_class->members = fontname_members;\n\tclassmodel_class->n_members = IM_NUMBER( fontname_members );\n}\n\nstatic void\nfontname_init( Fontname *fontname )\n{\n\t/* Overridden later. Just something sensible.\n\t */\n\tfontname->value = NULL;\n\tIM_SETSTR( fontname->value, \"Sans\" );\n\n\tiobject_set( IOBJECT( fontname ), CLASS_FONTNAME, NULL );\n}\n\nGType\nfontname_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( FontnameClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) fontname_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Fontname ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) fontname_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"Fontname\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/fontname.h",
    "content": "/* a fontname in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_FONTNAME (fontname_get_type())\n#define FONTNAME( obj ) (GTK_CHECK_CAST( (obj), TYPE_FONTNAME, Fontname ))\n#define FONTNAME_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_FONTNAME, FontnameClass ))\n#define IS_FONTNAME( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FONTNAME ))\n#define IS_FONTNAME_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_FONTNAME ))\n\ntypedef struct _Fontname {\n\tClassmodel model;\n\n\tchar *value;\n} Fontname;\n\ntypedef struct _FontnameClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} FontnameClass;\n\nGType fontname_get_type( void );\n"
  },
  {
    "path": "src/fontnameview.c",
    "content": "/* run the display for an arrow in a workspace \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GraphicviewClass *parent_class = NULL;\n\nstatic void\nfontnameview_link( View *view, Model *model, View *parent )\n{\n\tFontnameview *fontnameview = FONTNAMEVIEW( view );\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\tif( GRAPHICVIEW( view )->sview )\n\t\tgtk_size_group_add_widget( GRAPHICVIEW( view )->sview->group,   \n\t\t\tfontnameview->label );\n}\n\nstatic void \nfontnameview_refresh( vObject *vobject )\n{\n\tFontnameview *fontnameview = FONTNAMEVIEW( vobject );\n\tFontname *fontname = FONTNAME( VOBJECT( vobject )->iobject );\n\n#ifdef DEBUG\n\tprintf( \"fontnameview_refresh: \" );\n\trow_name_print( HEAPMODEL( fontname )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( vobject->iobject->caption ) \n\t\tset_glabel( fontnameview->label, _( \"%s:\" ), \n\t\t\tvobject->iobject->caption );\n\tif( fontname->value )\n\t\tfontbutton_set_font_name( fontnameview->fontbutton, \n\t\t\tfontname->value );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\nfontnameview_class_init( FontnameviewClass *class )\n{\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = fontnameview_refresh;\n\n\tview_class->link = fontnameview_link;\n}\n\nstatic void\nfontnameview_changed_cb( Fontbutton *fontbutton, Fontnameview *fontnameview )\n{\n\tFontname *fontname = FONTNAME( VOBJECT( fontnameview )->iobject );\n\tconst char *font_name = fontbutton_get_font_name( fontbutton );\n\n\tif( strcmp( font_name, fontname->value ) != 0 ) {\n\t\tIM_SETSTR( fontname->value, font_name );\n\t\tclassmodel_update( CLASSMODEL( fontname ) );\n\t\tsymbol_recalculate_all();\n\t}\n}\n\nstatic void\nfontnameview_init( Fontnameview *fontnameview )\n{\n\tGtkWidget *hbox;\n\n#ifdef DEBUG\n\tprintf( \"fontnameview_init\\n\" );\n#endif /*DEBUG*/\n\n\thbox = gtk_hbox_new( FALSE, 12 );\n        gtk_box_pack_start( GTK_BOX( fontnameview ), hbox, TRUE, FALSE, 0 );\n\n        fontnameview->label = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( fontnameview->label ), 0, 0.5 );\n        gtk_misc_set_padding( GTK_MISC( fontnameview->label ), 2, 7 );\n\tgtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( fontnameview->label ), \n\t\tFALSE, FALSE, 2 );\n\n        fontnameview->fontbutton = fontbutton_new();\n\tgtk_box_pack_start( GTK_BOX( hbox ), \n\t\tGTK_WIDGET( fontnameview->fontbutton ), TRUE, TRUE, 0 );\n        g_signal_connect( fontnameview->fontbutton, \"changed\",\n                G_CALLBACK( fontnameview_changed_cb ), fontnameview );\n\n        gtk_widget_show_all( GTK_WIDGET( hbox ) );\n}\n\nGtkType\nfontnameview_get_type( void )\n{\n\tstatic GtkType fontnameview_type = 0;\n\n\tif( !fontnameview_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Fontnameview\",\n\t\t\tsizeof( Fontnameview ),\n\t\t\tsizeof( FontnameviewClass ),\n\t\t\t(GtkClassInitFunc) fontnameview_class_init,\n\t\t\t(GtkObjectInitFunc) fontnameview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tfontnameview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info );\n\t}\n\n\treturn( fontnameview_type );\n}\n\nView *\nfontnameview_new( void )\n{\n\tFontnameview *fontnameview = gtk_type_new( TYPE_FONTNAMEVIEW );\n\n\treturn( VIEW( fontnameview ) );\n}\n"
  },
  {
    "path": "src/fontnameview.h",
    "content": "/* a fontname view in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_FONTNAMEVIEW (fontnameview_get_type())\n#define FONTNAMEVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_FONTNAMEVIEW, Fontnameview ))\n#define FONTNAMEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_FONTNAMEVIEW, FontnameviewClass ))\n#define IS_FONTNAMEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FONTNAMEVIEW ))\n#define IS_FONTNAMEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_FONTNAMEVIEW ))\n\ntypedef struct _Fontnameview {\n\tGraphicview parent_object;\n\n\tGtkWidget *label;\n\tFontbutton *fontbutton;\n} Fontnameview;\n\ntypedef struct _FontnameviewClass {\n\tGraphicviewClass parent_class;\n\n\t/* My methods.\n\t */\n} FontnameviewClass;\n\nGtkType fontnameview_get_type( void );\nView *fontnameview_new( void );\n"
  },
  {
    "path": "src/formula.c",
    "content": "/* display a caption/value label pair, on a click display the formula in an\n * entry widget\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* Our signals. \n */\nenum {\n\tEDIT,\t\t\n\tCHANGED,\t\t\n\tACTIVATE,\t\n\tENTER,\t\n\tLEAVE,\t\n\tLAST_SIGNAL\n};\n\nstatic GtkEventBoxClass *parent_class = NULL;\n\nstatic guint formula_signals[LAST_SIGNAL] = { 0 };\n\n/* Formula needing a refresh.\n */\nstatic GSList *formula_refresh_all = NULL;\n\n/* The idle we add if there are any formula needing a refresh.\n */\nstatic gint formula_refresh_idle = 0;\n\n/* Unqueue a refresh.\n */\nstatic void\nformula_refresh_unqueue( Formula *formula )\n{\n\tif( formula->refresh_queued ) {\n\t\tformula_refresh_all = \n\t\t\tg_slist_remove( formula_refresh_all, formula );\n\t\tformula->refresh_queued = FALSE;\n\t\t\n\t\tif( !formula_refresh_all )\n\t\t\tIM_FREEF( g_source_remove, formula_refresh_idle );\n\t}\n}\n\n/* Detect cancel in a text field.\n */\nstatic gboolean\nformula_key_press_event_cb( GtkWidget *widget, GdkEventKey *ev, \n\tFormula *formula )\n{\n\tgboolean handled;\n\n\thandled = FALSE;\n\n        if( ev->keyval == GDK_Escape ) {\n\t\tset_gentry( formula->entry, \"%s\", formula->expr );\n\n\t\t/*\n\n\t\t\tFIXME ... really we want to go back to the edit mode\n\t\t\tset by our environment (eg. if we're in a show_formula\n\t\t\tworkspace, should stay in show formula).\n\n\t\t */\n\t\tformula_set_edit( formula, FALSE );\n\n\t\thandled = TRUE;\n\t}\n\n        return( handled );\n}\n\n/* Activated!\n */\nstatic void\nformula_activate( Formula *formula )\n{\n\tg_signal_emit( G_OBJECT( formula ), formula_signals[ACTIVATE], 0 );\n}\n\nstatic void\nformula_activate_cb( GtkWidget *wid, Formula *formula )\n{\n\tformula_activate( formula );\n}\n\n/* A char has changed in the entry (we will need scanning on activate).\n */\nstatic void\nformula_changed( Formula *formula )\n{\n\tg_signal_emit( G_OBJECT( formula ), formula_signals[CHANGED], 0 );\n}\n\n/* Add an edit box.\n */\nstatic void\nformula_add_edit( Formula *formula )\n{\n        if( formula->entry_frame )\n                return;\n\n\t/* We need to use an alignment since if the left label is hidden we'll\n \t * have nothing to hold us to the right height.\n\t */\n        formula->entry_frame = gtk_alignment_new( 0.5, 0.5, 1, 1 );\n\tgtk_alignment_set_padding( GTK_ALIGNMENT( formula->entry_frame ),\n\t\t3, 3, 2, 2 );\n\tgtk_box_pack_start( GTK_BOX( formula->hbox ), \n\t\tformula->entry_frame, TRUE, TRUE, 0 );\n\n        formula->entry = gtk_entry_new();\n        set_tooltip( formula->entry, _( \"Press Escape to cancel edit, \"\n                \"press Return to accept edit and recalculate\" ) );\n        gtk_signal_connect( GTK_OBJECT( formula->entry ), \"key_press_event\", \n\t\tGTK_SIGNAL_FUNC( formula_key_press_event_cb ), \n\t\tGTK_OBJECT( formula ) );\n        gtk_signal_connect_object( GTK_OBJECT( formula->entry ), \"changed\", \n\t\tGTK_SIGNAL_FUNC( formula_changed ), GTK_OBJECT( formula ) );\n        gtk_signal_connect( GTK_OBJECT( formula->entry ), \"activate\",\n                GTK_SIGNAL_FUNC( formula_activate_cb ), formula );\n\tgtk_container_add( GTK_CONTAINER( formula->entry_frame ), \n\t\tformula->entry );\n\tgtk_widget_show( formula->entry );\n\n\t/* Tell everyone we are in edit mode ... used to add to resettable,\n\t * for example.\n\t */\n\tg_signal_emit( G_OBJECT( formula ), formula_signals[EDIT], 0 );\n}\n\nstatic void \nformula_refresh( Formula *formula )\n{\n#ifdef DEBUG\n\tprintf( \"formula_refresh\\n\" );\n#endif /*DEBUG*/\n\n\t/* Set edit mode.\n\t */\n\tif( formula->edit ) {\n\t\tformula_add_edit( formula );\n                gtk_widget_show( formula->entry_frame );\n                gtk_widget_hide( formula->right_label );\n\t\tformula->changed = FALSE;\n\t}\n\telse {\n                gtk_widget_show( formula->right_label );\n                IM_FREEF( gtk_widget_destroy, formula->entry );\n                IM_FREEF( gtk_widget_destroy, formula->entry_frame );\n\t}\n\n\t/* Don't update the formula display if the user has edited the text ...\n\t * we shouldn't destroy their work.\n\t */\n\tif( formula->entry && formula->expr && !formula->changed ) {\n\t\t/* Make sure we don't trigger \"changed\" when we zap in new\n\t\t * text.\n\t\t */\n\t\tgtk_signal_handler_block_by_data( \n\t\t\tGTK_OBJECT( formula->entry ), formula );\n\t\tset_gentry( formula->entry, \"%s\", formula->expr );\n\t\tgtk_signal_handler_unblock_by_data( \n\t\t\tGTK_OBJECT( formula->entry ), formula );\n\t}\n\n\tif( formula->caption ) {\n\t\tset_glabel( formula->left_label, _( \"%s:\" ), formula->caption );\n                gtk_widget_show( formula->left_label );\n\t}\n\telse\n                gtk_widget_hide( formula->left_label );\n\tif( formula->value ) \n\t\t/* Just display the first line of the formula ... it can be\n\t\t * mutiline for class members, for example.\n\t\t */\n\t\tset_glabel1( formula->right_label, \"%s\", formula->value );\n\n\tif( formula->edit && formula->needs_focus ) {\n\t\tif( formula->expr )\n\t\t\tgtk_editable_select_region( \n\t\t\t\tGTK_EDITABLE( formula->entry ), 0, -1 );\n\t\tgtk_widget_grab_focus( formula->entry );\n\t\tformula->needs_focus = FALSE;\n\t}\n}\n\nstatic gboolean\nformula_refresh_idle_cb( void )\n{\n\tformula_refresh_idle = 0;\n\n\twhile( formula_refresh_all ) {\n\t\tFormula *formula = FORMULA( formula_refresh_all->data );\n\n\t\tformula_refresh_unqueue( formula );\n\t\tformula_refresh( formula );\n\t}\n\n\treturn( FALSE );\n}\n\nstatic void\nformula_refresh_queue( Formula *formula )\n{\n\tif( !formula->refresh_queued ) {\n\t\tformula_refresh_all = \n\t\t\tg_slist_prepend( formula_refresh_all, formula );\n\t\tformula->refresh_queued = TRUE;\n\t\t\n\t\tif( !formula_refresh_idle )\n\t\t\tformula_refresh_idle = g_idle_add( \n\t\t\t\t(GSourceFunc) formula_refresh_idle_cb, NULL );\n\t}\n}\n\nstatic void\nformula_destroy( GtkObject *object )\n{\n\tFormula *formula;\n\n#ifdef DEBUG\n\tprintf( \"formula_destroy\\n\" );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_FORMULA( object ) );\n\n\t/* My instance destroy stuff.\n\t */\n\tformula = FORMULA( object );\n\n\tformula_refresh_unqueue( formula );\n\tIM_FREE( formula->caption );\n\tIM_FREE( formula->value );\n\tIM_FREE( formula->expr );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\n/* Change edit mode.\n */\nvoid \nformula_set_edit( Formula *formula, gboolean edit )\n{\n#ifdef DEBUG\n\tprintf( \"formula_set_edit: %d\\n\", edit );\n#endif /*DEBUG*/\n\n\tif( formula->edit != edit ) {\n\t\tformula->edit = edit;\n\t\tformula_refresh_queue( formula );\n\t}\n\n\t/* Can't have been edited yet, whichever way we're turning edit.\n\t */\n\tformula->changed = FALSE;\n}\n\n/* Grab focus on next refresh.\n */\nvoid \nformula_set_needs_focus( Formula *formula, gboolean needs_focus )\n{\n#ifdef DEBUG\n\tprintf( \"formula_set_needs_focus: %d\\n\", needs_focus );\n#endif /*DEBUG*/\n\n\tif( formula->needs_focus != needs_focus ) {\n\t\tformula->needs_focus = needs_focus;\n\t\tformula_refresh_queue( formula );\n\t}\n}\n\n/* Change sensitive mode.\n */\nvoid \nformula_set_sensitive( Formula *formula, gboolean sensitive )\n{\n#ifdef DEBUG\n\tprintf( \"formula_set_sensitive: %d\\n\", sensitive );\n#endif /*DEBUG*/\n\n\tif( formula->sensitive != sensitive ) {\n\t\tformula->sensitive = sensitive;\n\n\t\tif( !formula->sensitive )\n\t\t\tformula_set_edit( formula, FALSE );\n\n\t\tformula_refresh_queue( formula );\n\t}\n}\n\n/* Re-read the text. TRUE if we saw a change.\n */\ngboolean\nformula_scan( Formula *formula )\n{\n\tgboolean changed;\n\n#ifdef DEBUG\n\tprintf( \"formula_scan\\n\" );\n#endif /*DEBUG*/\n\n\tchanged = FALSE;\n\n\t/* Should be in edit mode.\n\t */\n\tif( formula->edit && \n\t\tformula->entry && \n\t\tGTK_WIDGET_VISIBLE( formula->entry ) ) {\n\t\tconst char *expr;\n\n\t\t/* There should be some edited text.\n\t\t */\n\t\texpr = gtk_entry_get_text( GTK_ENTRY( formula->entry ) );\n\t\tif( expr && \n\t\t\tstrspn( expr, WHITESPACE ) != strlen( expr ) ) {\n\t\t\tIM_SETSTR( formula->expr, expr );\n\t\t\tchanged = TRUE;\n\t\t}\n\n                formula_set_edit( formula, FALSE );\n\t}\n\n\treturn( changed );\n}\n\nstatic gboolean\nformula_enter_notify_event( GtkWidget *widget, GdkEventCrossing *event )\n{\n\tGtkWidget *event_widget;\n\n\tevent_widget = gtk_get_event_widget( (GdkEvent *) event );\n\n\tif( event_widget == widget && event->detail != GDK_NOTIFY_INFERIOR ) {\n\t\tgtk_widget_set_state( widget, GTK_STATE_PRELIGHT );\n\n\t\t/* Tell people about our highlight change ... used to (eg.) set \n\t\t * flash help.\n\t\t */\n\t\tg_signal_emit( G_OBJECT( widget ), formula_signals[ENTER], 0 );\n\t}\n\n\treturn( FALSE );\n}\n\nstatic gboolean\nformula_leave_notify_event( GtkWidget *widget, GdkEventCrossing *event )\n{\n\tGtkWidget *event_widget;\n\n\tevent_widget = gtk_get_event_widget( (GdkEvent *) event );\n\n\tif( event_widget == widget && event->detail != GDK_NOTIFY_INFERIOR ) {\n\t\tgtk_widget_set_state( widget, GTK_STATE_NORMAL );\n\n\t\t/* Tell people about our highlight change ... used to (eg.) set \n\t\t * flash help.\n\t\t */\n\t\tg_signal_emit( G_OBJECT( widget ), formula_signals[LEAVE], 0 );\n\t}\n\n\treturn( FALSE );\n}\n\n/* Event in us somewhere.\n */\nstatic gboolean\nformula_button_press_event( GtkWidget *widget, GdkEventButton *event )\n{\n\tgboolean handled = FALSE;\n\n\tif( event->type == GDK_BUTTON_PRESS ) {\n\t\tFormula *formula = FORMULA( widget );\n\n\t\tif( event->button == 1 && formula->sensitive ) {\n\t\t\tif( !formula->edit ) {\n\t\t\t\tformula_set_edit( formula, TRUE );\n\t\t\t\tformula_set_needs_focus( formula, TRUE );\n\t\t\t}\n\n\t\t\thandled = TRUE;\n\t\t}\n\t}\n\n\treturn( handled );\n}       \n\nstatic void\nformula_real_changed( Formula *formula )\n{\n#ifdef DEBUG\n\tprintf( \"formula_real_changed\\n\" );\n#endif /*DEBUG*/\n\n\tformula->changed = TRUE;\n}\n\nstatic void\nformula_class_init( FormulaClass *class )\n{\n\tGtkObjectClass *gobject_class = (GtkObjectClass *) class;\n\tGtkWidgetClass *widget_class = (GtkWidgetClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->destroy = formula_destroy;\n\n\twidget_class->enter_notify_event = formula_enter_notify_event;\n\twidget_class->leave_notify_event = formula_leave_notify_event;\n\twidget_class->button_press_event = formula_button_press_event;\n\n\t/* Create signals.\n\t */\n\tformula_signals[EDIT] = g_signal_new( \"edit\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( FormulaClass, changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\tformula_signals[CHANGED] = g_signal_new( \"changed\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( FormulaClass, changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\tformula_signals[ACTIVATE] = g_signal_new( \"activate\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( FormulaClass, activate ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\tformula_signals[ENTER] = g_signal_new( \"enter\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( FormulaClass, enter ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\tformula_signals[LEAVE] = g_signal_new( \"leave\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( FormulaClass, leave ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\n\t/* Init methods.\n\t */\n\tclass->changed = formula_real_changed;\n}\n\nstatic void\nformula_init( Formula *formula )\n{\n\t/* How annoying! To avoid vertical resizes on edit/view toggles we\n\t * need to add differing amounts of padding to the label depending on\n\t * the theme.\n\n\t  \tFIXME ... get this from the style somehow\n\n\t */\n#ifdef OS_WIN32\n\t/* with either wimp theme or gtk default.\n\t */\n\tconst int vpadding = 7;\n#else /*!OS_WIN32*/\n\t/* clearlooks\n\t */\n\tconst int vpadding = 8;\n#endif /*OS_WIN32*/\n\n\tformula->caption = NULL;\n\tformula->value = NULL;\n\tformula->expr = NULL;\n\tformula->edit = FALSE;\n\tformula->sensitive = TRUE;\n\tformula->changed = FALSE;\n\tformula->refresh_queued = FALSE;\n\tformula->needs_focus = FALSE;\n\n\tformula->entry_frame = NULL;\n\n\tgtk_widget_add_events( GTK_WIDGET( formula ), \n\t\tGDK_POINTER_MOTION_HINT_MASK ); \n\n\tformula->hbox = gtk_hbox_new( FALSE, 12 );\n\tgtk_container_add( GTK_CONTAINER( formula ), formula->hbox );\n        gtk_widget_show( formula->hbox );\n\n        formula->left_label = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( formula->left_label ), 0, 0.5 );\n        gtk_misc_set_padding( GTK_MISC( formula->left_label ), 2, vpadding );\n\tgtk_box_pack_start( GTK_BOX( formula->hbox ), \n\t\tformula->left_label, FALSE, FALSE, 2 );\n        gtk_widget_show( formula->left_label );\n\n        formula->right_label = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( formula->right_label ), 0, 0.5 );\n        gtk_misc_set_padding( GTK_MISC( formula->right_label ), 7, vpadding );\n\tgtk_box_pack_start( GTK_BOX( formula->hbox ), \n\t\tformula->right_label, TRUE, TRUE, 0 );\n        gtk_widget_show( formula->right_label );\n}\n\nGtkType\nformula_get_type( void )\n{\n\tstatic GtkType formula_type = 0;\n\n\tif( !formula_type ) {\n\t\tstatic const GtkTypeInfo formula_info = {\n\t\t\t\"Formula\",\n\t\t\tsizeof( Formula ),\n\t\t\tsizeof( FormulaClass ),\n\t\t\t(GtkClassInitFunc) formula_class_init,\n\t\t\t(GtkObjectInitFunc) formula_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tformula_type = gtk_type_unique( GTK_TYPE_EVENT_BOX, \n\t\t\t&formula_info );\n\t}\n\n\treturn( formula_type );\n}\n\nFormula *\nformula_new( void )\n{\n\tFormula *formula = gtk_type_new( TYPE_FORMULA );\n\n\treturn( formula );\n}\n\nvoid\nformula_set_caption( Formula *formula, const char *caption )\n{\n\tif( !caption && formula->caption ) {\n\t\tIM_FREE( formula->caption );\n\t\tformula_refresh_queue( formula );\n\t}\n\telse if( caption && (!formula->caption || \n\t\tstrcmp( caption, formula->caption ) != 0) ) {\n\t\tIM_SETSTR( formula->caption, caption );\n\t\tformula_refresh_queue( formula );\n\t}\n}\n\nvoid\nformula_set_value_expr( Formula *formula, const char *value, const char *expr )\n{\n#ifdef DEBUG\n\tprintf( \"formula_set_value_expr: value=\\\"%s\\\", expr=\\\"%s\\\"\\n\",\n\t\tvalue, expr );\n#endif /*DEBUG*/\n\n\tif( value && (!formula->value || \n\t\tstrcmp( value, formula->value ) != 0) ) {\n\t\tIM_SETSTR( formula->value, value );\n\t\tformula_refresh_queue( formula );\n\t}\n\n\tif( expr && (!formula->expr || \n\t\tstrcmp( expr, formula->expr ) != 0) ) {\n\t\tIM_SETSTR( formula->expr, expr );\n\t\tformula_refresh_queue( formula );\n\t}\n}\n"
  },
  {
    "path": "src/formula.h",
    "content": "/* display a caption/value label pair, on a click display the formula\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_FORMULA (formula_get_type())\n#define FORMULA( obj ) (GTK_CHECK_CAST( (obj), \\\n\tTYPE_FORMULA, Formula ))\n#define FORMULA_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_FORMULA, FormulaClass ))\n#define IS_FORMULA( obj ) (GTK_CHECK_TYPE( (obj), TYPE_FORMULA ))\n#define IS_FORMULA_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_FORMULA ))\n\ntypedef struct _Formula {\n\tGtkEventBox parent_object;\n\n\t/* State.\n\t */\n\tchar *caption;\n\tchar *value;\n\tchar *expr;\n        gboolean edit;              \t/* In edit mode */\n        gboolean sensitive;            \t/* Flick to edit on click */\n        gboolean changed;            \t/* ->entry changed since we set it */\n\tgboolean refresh_queued;\t/* Awaiting refresh */\n\tgboolean needs_focus;\t\t/* Grab focus on refresh */\n\n\t/* Widgets.\n\t */\n\tGtkWidget *hbox;\t\t/* Container for our stuff */\n        GtkWidget *left_label;\t\t/* Caption label */\n        GtkWidget *right_label;\t\t/* Display value here */\n        GtkWidget *entry_frame;\t\t/* Frame edit text with this */\n        GtkWidget *entry;\t\t/* Edit formula here */\n} Formula;\n\ntypedef struct _FormulaClass {\n\tGtkEventBoxClass parent_class;\n\n\t/* My methods.\n\t */\n\tvoid (*edit)( Formula * );\t/* Formula has flicked to edit mode */\n\tvoid (*changed)( Formula * );\t/* Formula change */\n\tvoid (*activate)( Formula * );\t/* Pressed \"Enter\" key in formula */\n\tvoid (*enter)( Formula * );\t/* Highlight change */\n\tvoid (*leave)( Formula * );\t/* on eg. mouse enter/exit */\n} FormulaClass;\n\nvoid formula_set_edit( Formula *formula, gboolean edit );\nvoid formula_set_sensitive( Formula *formula, gboolean sensitive );\nvoid formula_set_needs_focus( Formula *formula, gboolean needs_focus );\ngboolean formula_scan( Formula *formula );\n\nGType formula_get_type( void );\nFormula *formula_new( void );\n\nvoid formula_set_caption( Formula *formula, const char *caption );\nvoid formula_set_value_expr( Formula *formula,\n\tconst char *value, const char *expr );\n"
  },
  {
    "path": "src/graphicview.c",
    "content": "/* run the display for a graphic in a workspace \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\nstatic void\ngraphicview_link( View *view, Model *model, View *parent )\n{\n\tGraphicview *graphicview = GRAPHICVIEW( view );\n\tView *v;\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\t/* Find the enclosing subcolumnview.\n\t */\n\tfor( v = parent; v && !IS_SUBCOLUMNVIEW( v ); v = v->parent )\n\t\t;\n\tif( v )\n\t\tgraphicview->sview = SUBCOLUMNVIEW( v );\n}\n\nstatic void\ngraphicview_class_init( GraphicviewClass *class )\n{\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tview_class->link = graphicview_link;\n}\n\nstatic void\ngraphicview_init( Graphicview *graphicview )\n{\n\tgraphicview->sview = NULL;\n}\n\nGtkType\ngraphicview_get_type( void )\n{\n\tstatic GtkType graphicview_type = 0;\n\n\tif( !graphicview_type ) {\n\t\tstatic const GtkTypeInfo sinfo = {\n\t\t\t\"Graphicview\",\n\t\t\tsizeof( Graphicview ),\n\t\t\tsizeof( GraphicviewClass ),\n\t\t\t(GtkClassInitFunc) graphicview_class_init,\n\t\t\t(GtkObjectInitFunc) graphicview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tgraphicview_type = gtk_type_unique( TYPE_VIEW, &sinfo );\n\t}\n\n\treturn( graphicview_type );\n}\n"
  },
  {
    "path": "src/graphicview.h",
    "content": "/* abstract base class for graphic views, ie. things we can display as part of\n * the graphic component of a rhsview\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_GRAPHICVIEW (graphicview_get_type())\n#define GRAPHICVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_GRAPHICVIEW, Graphicview ))\n#define GRAPHICVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_GRAPHICVIEW, GraphicviewClass ))\n#define IS_GRAPHICVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_GRAPHICVIEW ))\n#define IS_GRAPHICVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_GRAPHICVIEW ))\n\ntypedef struct _Graphicview {\n\tView view;\n\n\t/* My instance vars.\n\t */\n\tSubcolumnview *sview;\t\t/* Enclosing subc. */\n} Graphicview;\n\ntypedef struct _GraphicviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} GraphicviewClass;\n\nGtkType graphicview_get_type( void );\n"
  },
  {
    "path": "src/graphwindow.c",
    "content": "/* display workspaces with graphviz\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n\n   \tTODO\n\n\tDon't generate DOT in a file, build the graph ourselves. We'd need \n\tsome sort of graph hash thing to avoid relayouts. Or perhaps a \n\tworkspace hash? A hash by column?\n\n\tAfter layout, don't render to a file, instead draw directly to the \n\toutput window with cairo. Copy/paste code from the png:cairo render.\n\tHave some simple culling stuff to only render visible parts of the \n\tgraph.\n\n\tAs well as \"view workspace as graph\", have a \"view column as graph\" \n\titem.\n \n\tDon't show nodes which are not inside this workspace.\n\n\tPossibly add graph editing, or at least edge highlighting as you \n\tmouse.\n\n\tLet columns be collapsed / expanded, and start the view with columns \n\tcollapsed if there's more than 1. This might be easier if columns were \n\tseparate scopes, I suppose.\n\n\tDo we should dynamic dependencies? How about (A2 = untitled.\"A1\") ?\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n#ifdef HAVE_LIBGVC\n\nstatic FloatwindowClass *parent_class = NULL;\n\nstatic int graph_write_cluster_index = 0;\n\nstatic void *\ngraph_write_row_child( Link *link, VipsBuf *buf )\n{\n\tif( link->child->expr && link->child->expr->row ) {\n\t\tvips_buf_appendf( buf, \"\\t\\t%s -> %s;\\n\", \n\t\t\tIOBJECT( link->child )->name,\n\t\t\tIOBJECT( link->parent )->name ); \n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\ngraph_write_row( Row *row, VipsBuf *buf )\n{\n\tif( row->sym )\n\t\tslist_map( row->sym->topchildren, \n\t\t\t(SListMapFn) graph_write_row_child, buf );\n\n\treturn( NULL );\n}\n\nstatic void *\ngraph_write_column( Column *col, VipsBuf *buf )\n{\n\tvips_buf_appendf( buf, \"\\tsubgraph cluster_%d {\\n\", \n\t\tgraph_write_cluster_index++ );\n\tvips_buf_appendf( buf, \"\\t\\tlabel = \\\"%s\", IOBJECT( col )->name );\n\tif( IOBJECT( col )->caption )\n\t\tvips_buf_appendf( buf, \" - %s\", IOBJECT( col )->caption );\n\tvips_buf_appends( buf, \"\\\"\\n\" );\n\n\tvips_buf_appends( buf, \"\\t\\tstyle=filled;\\n\" );\n\tvips_buf_appends( buf, \"\\t\\tcolor=lightgrey;\\n\" );\n\tvips_buf_appends( buf, \"\\t\\tnode [style=filled,color=white];\\n\" );\n\n\t(void) column_map( col, \n\t\t(row_map_fn) graph_write_row, buf, NULL );\n\tvips_buf_appends( buf, \"\\t}\\n\" );\n\n\treturn( NULL );\n}\n\n/* Generate the workspace in dot format.\n */\nstatic void\ngraph_write_dot( Workspace *ws, VipsBuf *buf )\n{\n\tgraph_write_cluster_index = 0;\n\tvips_buf_appends( buf, \"digraph G {\\n\" );\n\tworkspace_map_column( ws, \n\t\t(column_map_fn) graph_write_column, buf );\n\tvips_buf_appends( buf, \"}\\n\" );\n}\n\n/* Print the workspace in dot format. Display with something like:\n * $ dot test1.dot -o test1.png -Tpng:cairo -v\n * $ eog test1.png\n */\nvoid\ngraph_write( Workspace *ws )\n{\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_write_dot( ws, &buf );\n\tprintf( \"%s\", vips_buf_all( &buf ) );\n}\n\nstatic void\ngraphwindow_destroy( GtkObject *object )\n{\n\tGraphwindow *graphwindow;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_GRAPHWINDOW( object ) );\n\n\tgraphwindow = GRAPHWINDOW( object );\n\n#ifdef DEBUG\n\tprintf( \"graphwindow_destroy: %p\\n\", graphwindow );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\tIM_FREE( graphwindow->dot );\n\tIM_FREEF( g_source_remove, graphwindow->layout_timeout );\n\n\tUNREF( graphwindow->imagemodel );\n\n\tIM_FREEF( agclose, graphwindow->graph );\n\tIM_FREEF( gvFreeContext, graphwindow->gvc );\n\n\tFREESID( graphwindow->workspace_changed_sid, \n\t\tFLOATWINDOW( graphwindow )->model );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\ngraphwindow_class_init( GraphwindowClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = graphwindow_destroy;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n}\n\nstatic void\ngraphwindow_init( Graphwindow *graphwindow )\n{\n#ifdef DEBUG\n\tprintf( \"graphwindow_init: %p\\n\", graphwindow );\n#endif /*DEBUG*/\n\n\tgraphwindow->dot = NULL;\n\tgraphwindow->layout_timeout = 0;\n\n\tgraphwindow->gvc = gvContext();\n}\n\nGType\ngraphwindow_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( GraphwindowClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) graphwindow_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Graphwindow ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) graphwindow_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_FLOATWINDOW, \n\t\t\t\"Graphwindow\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\ngraphwindow_refresh_title( Graphwindow *graphwindow )\n{\n\tWorkspace *ws = WORKSPACE( FLOATWINDOW( graphwindow )->model );\n\n\tVipsBuf buf;\n\tchar txt[512];\n\n#ifdef DEBUG\n\tprintf( \"graphwindow_refresh_title\\n\" );\n#endif /*DEBUG*/\n\n\tvips_buf_init_static( &buf, txt, 512 );\n\tif( ws->sym )\n\t\tsymbol_qualified_name( ws->sym, &buf );\n\tiwindow_set_title( IWINDOW( graphwindow ), \"%s\", vips_buf_all( &buf ) );\n}\n\nstatic gboolean\ngraphwindow_build_graph( Graphwindow *graphwindow )\n{\n\tchar tname[FILENAME_MAX];\n\tiOpenFile *of;\n\n\tif( !temp_name( tname, \"dot\" ) ||\n\t\t!(of = ifile_open_write( \"%s\", tname )) )\n\t\treturn( FALSE );\n\tif( !ifile_write( of, \"%s\", graphwindow->dot ) ) {\n\t\tifile_close( of );\n\t\tunlinkf( \"%s\", tname );\n\t\treturn( FALSE );\n\t}\n\tifile_close( of );\n\n\tif( !(of = ifile_open_read( \"%s\", tname )) ) {\n\t\tunlinkf( \"%s\", tname );\n\t\treturn( FALSE );\n\t}\n\n\tIM_FREEF( agclose, graphwindow->graph );\n\n\tgraphwindow->graph = agread( of->fp, NULL );\n\n\tifile_close( of );\n\tunlinkf( \"%s\", tname );\n\n\treturn( TRUE );\n}\n\nstatic gboolean\ngraphwindow_update_image( Graphwindow *graphwindow )\n{\n\tchar tname[FILENAME_MAX];\n\tiOpenFile *of;\n\tImageinfo *ii;\n\n\tif( !temp_name( tname, \"png\" ) ||\n\t\t!(of = ifile_open_write( \"%s\", tname )) )\n\t\treturn( FALSE );\n\n\tgvRender( graphwindow->gvc, graphwindow->graph, \"png:cairo\", of->fp );\n\n\tifile_close( of );\n\n\tif( !(ii = imageinfo_new_input( main_imageinfogroup, \n\t\tGTK_WIDGET( graphwindow ), NULL, tname )) ) {\n\t\tunlinkf( \"%s\", tname );\n\t\treturn( FALSE );\n\t}\n\n\tconversion_set_image( graphwindow->imagemodel->conv, ii );\n\n\tMANAGED_UNREF( ii );\n\n\t/* We can unlink now: the png will have been converted to vips\n\t * format.\n\t */\n\tunlinkf( \"%s\", tname );\n\n\treturn( TRUE );\n}\n\nstatic gboolean\ngraphwindow_layout( Graphwindow *graphwindow )\n{\n\tif( !graphwindow_build_graph( graphwindow ) )\n\t\treturn( FALSE );\n\tgvLayout( graphwindow->gvc, graphwindow->graph, \"dot\" );\n\tif( !graphwindow_update_image( graphwindow ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic gboolean\ngraphwindow_layout_cb( Graphwindow *graphwindow )\n{\n\tWorkspace *ws = WORKSPACE( FLOATWINDOW( graphwindow )->model );\n\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraphwindow->layout_timeout = 0;\n\n\tgraph_write_dot( ws, &buf );\n\tif( !graphwindow->dot ||\n\t\tstrcmp( vips_buf_all( &buf ), graphwindow->dot ) != 0 ) {\n\t\tIM_FREE( graphwindow->dot );\n\t\tgraphwindow->dot = im_strdup( NULL, vips_buf_all( &buf ) );\n\n#ifdef DEBUG\n\t\tprintf( \"graphwindow_changed_cb:\\n%s\\n\", graphwindow->dot );\n#endif /*DEBUG*/\n\n\t\tif( !graphwindow_layout( graphwindow ) )\n\t\t\tiwindow_alert( GTK_WIDGET( graphwindow ), \n\t\t\t\tGTK_MESSAGE_ERROR );\n\t}\n\n\t/* Clear the timeout.\n\t */\n\treturn( FALSE );\n}\n\nstatic void\ngraphwindow_layout_queue( Graphwindow *graphwindow )\n{\n\tIM_FREEF( g_source_remove, graphwindow->layout_timeout );\n\tgraphwindow->layout_timeout = g_timeout_add( 200, \n\t\t(GSourceFunc) graphwindow_layout_cb, graphwindow );\n}\n\n/* The model has changed.\n */\nstatic void\ngraphwindow_changed_cb( Workspace *ws, Graphwindow *graphwindow )\n{\n#ifdef DEBUG\n\tprintf( \"graphwindow_changed_cb: %p\\n\", graphwindow );\n#endif /*DEBUG*/\n\n\tgraphwindow_refresh_title( graphwindow );\n\tgraphwindow_layout_queue( graphwindow );\n}\n\nstatic const char *graphwindow_menubar_ui_description =\n\"<ui>\"\n\"  <menubar name='GraphwindowMenubar'>\"\n\"    <menu action='FileMenu'>\"\n\"      <menuitem action='Close'/>\"\n\"      <menuitem action='Quit'/>\"\n\"    </menu>\"\n\"    <menu action='HelpMenu'>\"\n\"      <menuitem action='Guide'/>\"\n\"      <menuitem action='About'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Homepage'/>\"\n\"    </menu>\"\n\"  </menubar>\"\n\"</ui>\";\n\nstatic void\ngraphwindow_build( Graphwindow *graphwindow, GtkWidget *vbox, Workspace *ws )\n{\n\tiWindow *iwnd = IWINDOW( graphwindow );\n\n\tGError *error;\n\tGtkWidget *mbar;\n\tGtkWidget *frame;\n\n\t/* Make our model.\n\t */\n\tgraphwindow->imagemodel = imagemodel_new( NULL );\n\tg_object_ref( G_OBJECT( graphwindow->imagemodel ) );\n\tiobject_sink( IOBJECT( graphwindow->imagemodel ) );\n\tgraphwindow->workspace_changed_sid = g_signal_connect( \n\t\tG_OBJECT( ws ), \"changed\", \n\t\tG_CALLBACK( graphwindow_changed_cb ), graphwindow );\n\n        /* Make main menu bar\n         */\n\terror = NULL;\n\tif( !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager,\n\t\t\tgraphwindow_menubar_ui_description, -1, &error ) ) {\n\t\tg_message( \"building menus failed: %s\", error->message );\n\t\tg_error_free( error );\n\t\texit( EXIT_FAILURE );\n\t}\n\n\tmbar = gtk_ui_manager_get_widget( iwnd->ui_manager, \n\t\t\"/GraphwindowMenubar\" );\n\tgtk_box_pack_start( GTK_BOX( vbox ), mbar, FALSE, FALSE, 0 );\n        gtk_widget_show( mbar );\n\n\t/* This will set to NULL if we don't have infobar support.\n\t */\n\tif( (iwnd->infobar = infobar_new()) ) \n\t\tgtk_box_pack_start( GTK_BOX( vbox ), \n\t\t\tGTK_WIDGET( iwnd->infobar ), FALSE, FALSE, 0 );\n\n\t/* Graph area. \n\t */\n\tframe = gtk_frame_new( NULL );\n\tgtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_OUT );\n\tgtk_widget_show( frame );\n\tgtk_box_pack_start( GTK_BOX( vbox ), \n\t\tGTK_WIDGET( frame ), TRUE, TRUE, 0 );\n\tgraphwindow->ip = imagepresent_new( graphwindow->imagemodel );\n\tgtk_container_add( GTK_CONTAINER( frame ), \n\t\tGTK_WIDGET( graphwindow->ip ) );\n\tgtk_widget_show( GTK_WIDGET( graphwindow->ip ) );\n}\n\nstatic void\ngraphwindow_link( Graphwindow *graphwindow, Workspace *ws, GtkWidget *parent )\n{\n\tiwindow_set_build( IWINDOW( graphwindow ), \n\t\t(iWindowBuildFn) graphwindow_build, ws, NULL, NULL );\n\tiwindow_set_parent( IWINDOW( graphwindow ), parent );\n\tfloatwindow_link( FLOATWINDOW( graphwindow ), MODEL( ws ) );\n\tiwindow_set_size_prefs( IWINDOW( graphwindow ), \n\t\t\"GRAPH_WINDOW_WIDTH\", \"GRAPH_WINDOW_HEIGHT\" );\n\tiwindow_build( IWINDOW( graphwindow ) );\n\n\t/* Initial \"changed\" on the model to get all views to init.\n\t */\n\tiobject_changed( IOBJECT( ws ) );\n}\n\nGraphwindow *\ngraphwindow_new( Workspace *ws, GtkWidget *parent )\n{\n\tGraphwindow *graphwindow = gtk_type_new( TYPE_GRAPHWINDOW );\n\n\tgraphwindow_link( graphwindow, ws, parent );\n\n\treturn( graphwindow );\n}\n\n#endif /*HAVE_LIBGVC*/\n"
  },
  {
    "path": "src/graphwindow.h",
    "content": "/* display workspaces with graphviz\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_GRAPHWINDOW (graphwindow_get_type())\n#define GRAPHWINDOW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_GRAPHWINDOW, Graphwindow ))\n#define GRAPHWINDOW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_GRAPHWINDOW, GraphwindowClass ))\n#define IS_GRAPHWINDOW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_GRAPHWINDOW ))\n#define IS_GRAPHWINDOW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_GRAPHWINDOW ))\n\nstruct _Graphwindow {\n\tFloatwindow parent_class;\n\n\t/* The last dot graph we generated.\n\t */\n\tchar *dot;\n\n\t/* Regenerate the graph on a timeout to avoid regen on many small \n\t * changes.\n\t */\n\tguint layout_timeout;\n\n\t/* The imagedisplay we make.\n\t */\n\tImagemodel *imagemodel;\n\tImagepresent *ip;\n\n\t/* Watch the ws with this.\n\t */\n\tguint workspace_changed_sid;\n\n#ifdef HAVE_LIBGVC\n\tGVC_t *gvc;\n\tgraph_t *graph;\n#endif /*HAVE_LIBGVC*/\n};\n\ntypedef struct _GraphwindowClass {\n\tFloatwindowClass parent_class;\n\n\t/* My methods.\n\t */\n} GraphwindowClass;\n\nvoid graph_write( Workspace *ws );\n\nGtkType graphwindow_get_type( void );\nGraphwindow *graphwindow_new( Workspace *ws, GtkWidget *parent );\n\n"
  },
  {
    "path": "src/group.c",
    "content": "/* an input group ... put/get methods\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ValueClass *parent_class = NULL;\n\nstatic gboolean\ngroup_save_list( PElement *list, char *filename );\n\n/* Exported, since main.c uses this to save 'main' to a file. @filename is\n * incremented. \n */\ngboolean\ngroup_save_item( PElement *item, char *filename )\n{\n\tgboolean result;\n\tImageinfo *ii;\n\tchar buf[FILENAME_MAX];\n\n\t/* We don't want $VAR etc. in the filename we pass down to the file\n\t * ops.\n\t */\n\tim_strncpy( buf, filename, FILENAME_MAX );\n\tpath_expand( buf ); \n\n\tif( !heap_is_instanceof( CLASS_GROUP, item, &result ) )\n\t\treturn( FALSE );\n\tif( result ) {\n\t\tPElement value;\n\n\t\tif( !class_get_member( item, MEMBER_VALUE, NULL, &value ) ||\n\t\t\t!group_save_list( &value, filename ) )\n\t\t\treturn( FALSE );\n\t}\n\n\tif( !heap_is_instanceof( CLASS_IMAGE, item, &result ) )\n\t\treturn( FALSE );\n\tif( result ) {\n\t\tPElement value;\n\n\t\tfilesel_add_mode( buf );\n\n\t\tif( !class_get_member( item, MEMBER_VALUE, NULL, &value ) || \n\t\t\t!heap_get_image( &value, &ii ) ||\n\t\t\t!imageinfo_write( ii, buf ) )\n\t\t\treturn( FALSE );\n\n\t\tincrement_filename( filename );\n\t}\n\n\tif( !heap_is_instanceof( CLASS_MATRIX, item, &result ) )\n\t\treturn( FALSE );\n\tif( result ) {\n\t\tDOUBLEMASK *dmask;\n\n\t\tif( !(dmask = matrix_ip_to_dmask( item )) )\n\t\t\treturn( FALSE );\n\t\tif( im_write_dmask_name( dmask, buf ) ) {\n\t\t\terror_vips_all();\n\t\t\tIM_FREEF( im_free_dmask, dmask );\n\n\t\t\treturn( FALSE );\n\t\t}\n\t\tIM_FREEF( im_free_dmask, dmask );\n\n\t\tincrement_filename( filename );\n\t}\n\n\tif( PEISIMAGE( item ) ) {\n\t\tfilesel_add_mode( buf );\n\n\t\tif( !heap_get_image( item, &ii ) ||\n\t\t\t!imageinfo_write( ii, buf ) )\n\t\t\treturn( FALSE );\n\n\t\tincrement_filename( filename );\n\t}\n\n\tif( PEISLIST( item ) ) {\n\t\tif( !group_save_list( item, filename ) )\n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic gboolean\ngroup_save_list( PElement *list, char *filename )\n{\n\tint i;\n\tint length;\n\n\tif( (length = heap_list_length( list )) < 0 ) \n\t\treturn( FALSE );\n\n\tfor( i = 0; i < length; i++ ) {\n\t\tPElement item;\n\n\t\tif( !heap_list_index( list, i, &item ) ||\n\t\t\t!group_save_item( &item, filename ) )\n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic gboolean\ngroup_graphic_save( Classmodel *classmodel, \n\tGtkWidget *parent, const char *filename )\n{\n\tGroup *group = GROUP( classmodel );\n\tRow *row = HEAPMODEL( group )->row;\n\tPElement *root = &row->expr->root;\n\tchar buf[FILENAME_MAX];\n\n\t/* We are going to increment the filename ... make sure there's some\n\t * space at the end of the string.\n\t */\n\tim_strncpy( buf, filename, FILENAME_MAX - 5 );\n\n\tif( !group_save_item( root, buf ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic void\ngroup_class_init( GroupClass *class )\n{\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\tclassmodel_class->graphic_save = group_graphic_save;\n\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\ngroup_init( Group *group )\n{\n\tiobject_set( IOBJECT( group ), CLASS_GROUP, NULL );\n}\n\nGType\ngroup_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( GroupClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) group_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Group ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) group_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_VALUE, \n\t\t\t\"Group\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/group.h",
    "content": "/* a group in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_GROUP (group_get_type())\n#define GROUP( obj ) (GTK_CHECK_CAST( (obj), TYPE_GROUP, Group ))\n#define GROUP_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_GROUP, GroupClass ))\n#define IS_GROUP( obj ) (GTK_CHECK_TYPE( (obj), TYPE_GROUP ))\n#define IS_GROUP_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_GROUP ))\n\ntypedef struct _Group {\n\tValue parent_object;\n\n} Group;\n\ntypedef struct _GroupClass {\n\tValueClass parent_class;\n\n\t/* My methods.\n\t */\n} GroupClass;\n\nGType group_get_type( void );\ngboolean group_save_item( PElement *item, char *filename );\n"
  },
  {
    "path": "src/gtkutil.c",
    "content": "/* gtkutil functions.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/*\n#define DEBUG\n */\n\n/* All our tooltips.\n */\nstatic GtkTooltips *our_tooltips = NULL;\n\n/* Set two adjustments together.\n */\nvoid\nadjustments_set_value( GtkAdjustment *hadj, GtkAdjustment *vadj,\n        float hval, float vval )\n{\n        gboolean hchanged = FALSE;\n        gboolean vchanged = FALSE;\n\n        if( hval != hadj->value ) {\n                hadj->value = hval;\n                hchanged = TRUE;\n        }\n        if( vval != vadj->value ) {\n                vadj->value = vval;\n                vchanged = TRUE;\n        }\n\n#ifdef DEBUG\n        if( hchanged )\n                printf( \"adjustments_set_value: hadj = %g\\n\", hval );\n        if( vchanged )\n                printf( \"adjustments_set_value: vadj = %g\\n\", vval );\n#endif /*DEBUG*/\n\n        if( hchanged )\n                gtk_adjustment_value_changed( hadj );\n        if( vchanged )\n                gtk_adjustment_value_changed( vadj );\n}\n\nvoid *\nobject_destroy( void *obj )\n{\n\tgtk_object_destroy( GTK_OBJECT( obj ) );\n\n\treturn( NULL );\n}\n\n/* Like g_free, but return NULL for list maps.\n */\nvoid *\nnull_g_free( void *obj )\n{\n\tg_free( obj );\n\n\treturn( NULL );\n}\n\n/* Set visible/not.\n */\nvoid\nwidget_visible( GtkWidget *widget, gboolean visible )\n{\n\tif( widget && visible )\n\t\tgtk_widget_show( widget );\n\telse if( widget && !visible )\n\t\tgtk_widget_hide( widget );\n}\n\n/* Make a button widget.\n */\nGtkWidget *\nbuild_button( const char *stock_id, GtkSignalFunc cb, gpointer user )\n{\n\tGtkWidget *but;\n\n\tbut = gtk_button_new_from_stock( stock_id );\n\tGTK_WIDGET_SET_FLAGS( but, GTK_CAN_DEFAULT );\n\tgtk_signal_connect( GTK_OBJECT( but ), \"clicked\", cb, user );\n\n\treturn( but );\n}\n\n/* Calculate the bounding box for a string rendered with a widget's default\n * font. Set geo to a rect with 0,0 positioned on the left-hand baseline.\n */\nvoid\nget_geo( GtkWidget *widget, const char *text, Rect *geo )\n{\n\tPangoLayout *layout;\n\tint width, height;\n\n\tlayout = gtk_widget_create_pango_layout( widget, text );\n\tpango_layout_get_pixel_size( layout, &width, &height );\n\tg_object_unref( layout );\n\n\t/* FIXME ... we left/top to 0 for now.\n\t */\n\tgeo->width = width;\n\tgeo->height = height;\n\tgeo->left = 0;\n\tgeo->top = 0;\n}\n\n/* Set a widget to a fixed size ... width in characters.\n */\nvoid\nset_fixed( GtkWidget *widget, int nchars )\n{\n\tRect geo;\n\n\tget_geo( widget, \"8\", &geo );\n\tgtk_widget_set_size_request( widget, geo.width * nchars, geo.height );\n}\n\n/* Build a GtkEntry, with a widget width specified in characters.\n */\nGtkWidget *\nbuild_entry( int nchars )\n{\n\tGtkWidget *entry;\n\n\tentry = gtk_entry_new();\n\tgtk_entry_set_width_chars( GTK_ENTRY( entry ), nchars );\n\n\treturn( entry );\n}\n\n/* Build a new menu.\n */\nGtkWidget *\nmenu_build( const char *name )\n{\n\tGtkWidget *menu;\n\n\tmenu = gtk_menu_new();\n\tgtk_menu_set_title( GTK_MENU( menu ), name );\n\n\treturn( menu );\n}\n\n/* Add a menu item.\n */\nGtkWidget *\nmenu_add_but( GtkWidget *menu, \n\tconst char *stock_id, GtkSignalFunc cb, void *user )\n{\n\tGtkWidget *but;\n\n\t/* We don't provide an accel group for popup menus.\n\t */\n\tbut = gtk_image_menu_item_new_from_stock( stock_id, NULL );\n\tgtk_menu_shell_append( GTK_MENU_SHELL( menu ), but );\n\tgtk_widget_show( but );\n\tgtk_signal_connect( GTK_OBJECT( but ), \"activate\", cb, user );\n\n\treturn( but );\n}\n\n/* Add a toggle item.\n */\nGtkWidget *\nmenu_add_tog( GtkWidget *menu, const char *name, GtkSignalFunc cb, void *user )\n{\n\tGtkWidget *tog;\n\n\ttog = gtk_check_menu_item_new_with_mnemonic( name );\n\tgtk_menu_shell_append( GTK_MENU_SHELL( menu ), tog );\n\tgtk_widget_show( tog );\n\tgtk_signal_connect( GTK_OBJECT( tog ), \"toggled\", cb, user );\n\n\treturn( tog );\n}\n\n/* Add a separator.\n */\nGtkWidget *\nmenu_add_sep( GtkWidget *menu )\n{\n\tGtkWidget *sep;\n\n\tsep = gtk_menu_item_new();\n\tgtk_widget_set_sensitive( GTK_WIDGET( sep ), FALSE );\n\tgtk_menu_shell_append( GTK_MENU_SHELL( menu ), sep );\n\tgtk_widget_show( sep );\n\n\treturn( sep );\n}\n\n/* Add a pullright.\n */\nGtkWidget *\nmenu_add_pullright( GtkWidget *menu, const char *stock_id )\n{\n\tGtkWidget *pullright;\n\tGtkWidget *subpane;\n\n\tsubpane = gtk_menu_new();\n\tpullright = gtk_image_menu_item_new_from_stock( stock_id, NULL );\n\tgtk_menu_item_set_submenu( GTK_MENU_ITEM( pullright ), subpane );\n\tgtk_menu_shell_append( GTK_MENU_SHELL( menu ), pullright );\n\tgtk_widget_show( pullright );\n\n\treturn( subpane );\n}\n\n/* Four quarks: each menu item has a quark linking back to the main pane, \n * plus a quark for the user signal. The main pane has a quark linking to the\n * widget the menu was popped from, and that has the userdata for this context.\n * One more quark holds the popup in a host.\n */\nstatic GQuark quark_main = 0;\nstatic GQuark quark_host = 0;\nstatic GQuark quark_data = 0;\nstatic GQuark quark_popup = 0;\n\n/* Build a new popup menu.\n */\nGtkWidget *\npopup_build( const char *name )\n{\n\t/* Build our quarks.\n\t */\n\tif( !quark_main ) {\n\t\tquark_main = g_quark_from_static_string( \"quark_main\" );\n\t\tquark_host = g_quark_from_static_string( \"quark_host\" );\n\t\tquark_data = g_quark_from_static_string( \"quark_data\" );\n\t\tquark_popup = g_quark_from_static_string( \"quark_popup\" );\n\t}\n\n\treturn( menu_build( name ) );\n}\n\n/* Activate function for a popup menu item.\n */\nstatic void\npopup_activate_cb( GtkWidget *item, PopupFunc cb )\n{\n\tGtkWidget *qmain = gtk_object_get_data_by_id( \n\t\tGTK_OBJECT( item ), quark_main );\n\tGtkWidget *qhost = gtk_object_get_data_by_id( \n\t\tGTK_OBJECT( qmain ), quark_host );\n\tvoid *qdata = gtk_object_get_data_by_id( \n\t\tGTK_OBJECT( qhost ), quark_data );\n\n\t(*cb)( item, qhost, qdata );\n}\n\n/* Add a menu item to a popup.\n */\nGtkWidget *\npopup_add_but( GtkWidget *popup, const char *name, PopupFunc cb )\n{\n\tGtkWidget *but = menu_add_but( popup, name, \n\t\tGTK_SIGNAL_FUNC( popup_activate_cb ), (void *) cb );\n\n\tgtk_object_set_data_by_id( GTK_OBJECT( but ), quark_main, popup );\n\n\treturn( but );\n}\n\n/* Add a toggle item to a popup.\n */\nGtkWidget *\npopup_add_tog( GtkWidget *popup, const char *name, PopupFunc cb )\n{\n\tGtkWidget *tog = menu_add_tog( popup, name, \n\t\tGTK_SIGNAL_FUNC( popup_activate_cb ), (void *) cb );\n\n\tgtk_object_set_data_by_id( GTK_OBJECT( tog ), quark_main, popup );\n\n\treturn( tog );\n}\n\n/* Add a pullright item to a popup. Return the empty sub-pane.\n */\nGtkWidget *\npopup_add_pullright( GtkWidget *popup, const char *name )\n{\n\tGtkWidget *pullright = menu_add_pullright( popup, name );\n\n\tgtk_object_set_data_by_id( GTK_OBJECT( pullright ), quark_main, popup );\n\n\treturn( pullright );\n}\n\n/* Show the popup.\n */\nvoid\npopup_show( GtkWidget *host, GdkEvent *ev )\n{\n\tGtkWidget *popup = gtk_object_get_data_by_id( \n\t\tGTK_OBJECT( host ), quark_popup );\n\n\tgtk_object_set_data_by_id( GTK_OBJECT( popup ), quark_host, host );\n\tgtk_menu_popup( GTK_MENU( popup ), NULL, NULL,\n\t\t(GtkMenuPositionFunc) NULL, NULL, 3, ev->button.time );\n}\n\n/* Event handler for popupshow.\n */\nstatic gboolean\npopup_handle_event( GtkWidget *host, GdkEvent *ev, gpointer dummy )\n{\n\tgboolean handled = FALSE;\n\n        if( ev->type == GDK_BUTTON_PRESS && ev->button.button == 3 ) {\n\t\tpopup_show( host, ev );\n\t\thandled = TRUE;\n\t}\n\telse if( ev->type == GDK_KEY_PRESS && ev->key.keyval == GDK_F10 && \n\t\tev->key.state & GDK_SHIFT_MASK ) {\n\t\tpopup_show( host, ev );\n\t\thandled = TRUE;\n\t}\n\n\treturn( handled );\n}\n\n/* Link a host to a popup.\n */\nvoid\npopup_link( GtkWidget *host, GtkWidget *popup, void *data )\n{\n\tgtk_object_set_data_by_id( GTK_OBJECT( host ), quark_popup, popup );\n\tgtk_object_set_data_by_id( GTK_OBJECT( host ), quark_data, data );\n}\n\n/* Add a callback to show a popup.\n */\nguint\npopup_attach( GtkWidget *host, GtkWidget *popup, void *data )\n{\n\tguint sid;\n\n\tpopup_link( host, popup, data );\n\n\t/* We can't just use gtk_menu_attach_to_widget(), since that can only\n\t * attach a menu to a single widget. We want to be able to attach a\n\t * single menu to meny widgets.\n\t */\n        sid = gtk_signal_connect( GTK_OBJECT( host ), \"event\",\n                GTK_SIGNAL_FUNC( popup_handle_event ), NULL );\n\n\treturn( sid );\n}\n\nvoid\npopup_detach( GtkWidget *host, guint sid )\n{\n\tgtk_signal_disconnect( GTK_OBJECT( host ), sid );\n}\n\nstatic void\nset_tooltip_events( GtkWidget *wid )\n{\n\tgtk_widget_add_events( wid, \n\t\tGDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK );\n}\n\n/* Set the tooltip on a widget.\n */\nvoid\nset_tooltip( GtkWidget *wid, const char *fmt, ... )\n{\n\tva_list ap;\n\tchar *txt;\n\n\tif( !wid )\n\t\treturn;\n\n\tif( !fmt )\n\t\tfmt = \"\";\n\n\tva_start( ap, fmt );\n\ttxt = g_strdup_vprintf( fmt, ap );\n\tva_end( ap );\n\n\tif( !our_tooltips ) \n\t\tour_tooltips = gtk_tooltips_new();\n\n\tgtk_tooltips_set_tip( our_tooltips, wid, txt, NULL );\n\n\tif( !GTK_WIDGET_REALIZED( wid ) )\n\t\tgtk_signal_connect( GTK_OBJECT( wid ), \"realize\",\n\t\t\tGTK_SIGNAL_FUNC( set_tooltip_events ), NULL );\n\telse\n\t\tset_tooltip_events( wid );\n\n\tg_free( txt );\n}\n\n/* Track tooltips we generate with one of these.\n */\ntypedef struct _TooltipGenerate {\n\tGtkWidget *widget;\n\n\tTooltipGenerateFn generate;\n\tvoid *a;\n\tvoid *b;\n\n\tVipsBuf buf;\n\tchar txt[256];\n} TooltipGenerate;\n\nstatic void\ntooltip_generate_free( GtkWidget *widget, TooltipGenerate *gen )\n{\n\tgen->widget = NULL;\n\tgen->generate = NULL;\n\tgen->a = NULL;\n\tgen->b = NULL;\n\n\tIM_FREE( gen );\n}\n\nstatic gboolean\ntooltip_generate_rebuild( GtkWidget *widget, \n\tGdkEventCrossing *event, TooltipGenerate *gen )\n{\n\tgboolean handled = FALSE;\n\n\tif( gen->widget ) {\n\t\tvips_buf_rewind( &gen->buf );\n\t\tgen->generate( widget, &gen->buf, gen->a, gen->b );\n\t\tset_tooltip( gen->widget, \"%s\", vips_buf_all( &gen->buf ) );\n\t}\n\n\treturn( handled );\n}\n\nstatic void\ntooltip_generate_attach( GtkWidget *widget, TooltipGenerate *gen )\n{\n\t/* Must have enter/leave.\n\t */\n\tgtk_widget_add_events( widget, \n\t\tGDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK );\n\n\t/* On enter, regenerate the tooltip.\n\t */\n\tg_signal_connect( widget, \"enter_notify_event\",\n\t\tG_CALLBACK( tooltip_generate_rebuild ), gen );\n}\n\n/* Set a callback to be used to generate the tooltip.\n */\nvoid\nset_tooltip_generate( GtkWidget *widget, \n\tTooltipGenerateFn generate, void *a, void *b )\n{\n\tTooltipGenerate *gen;\n\n\tif( !(gen = INEW( NULL, TooltipGenerate )) )\n\t\treturn;\n\n\tgen->widget = widget;\n\tgen->generate = generate;\n\tgen->a = a;\n\tgen->b = b;\n\tvips_buf_init_static( &gen->buf, gen->txt, 256 );\n\tg_signal_connect( widget, \"destroy\", \n\t\tG_CALLBACK( tooltip_generate_free ), gen );\n\n\tif( !GTK_WIDGET_REALIZED( widget ) )\n\t\tg_signal_connect( widget, \"realize\",\n\t\t\tG_CALLBACK( tooltip_generate_attach ), gen );\n\telse\n\t\ttooltip_generate_attach( widget, gen );\n}\n\n/* Junk all tooltips, helps trim valgrind noise.\n */\nvoid\njunk_tooltips( void )\n{\n\tif( our_tooltips )\n\t\tg_object_ref_sink( GTK_OBJECT( our_tooltips ) );\n}\n\n/* Set a GtkEditable.\n */\nvoid\nset_gentryv( GtkWidget *edit, const char *fmt, va_list ap )\n{\n\tchar buf[1000];\n\tgint position;\n\tint i;\n\tint len;\n\n\tif( !edit )\n\t\treturn;\n\n\tif( !fmt )\n\t\tfmt = \"\";\n\n\t(void) im_vsnprintf( buf, 1000, fmt, ap );\n\n\t/* Filter out /n and /t ... they confuse gtkentry terribly\n\t */\n\tlen = strlen( buf );\n\tfor( i = 0; i < len; i++ )\n\t\tif( buf[i] == '\\n' || buf[i] == '\\t' )\n\t\t\tbuf[i] = ' ';\n\n\tgtk_editable_delete_text( GTK_EDITABLE( edit ), 0, -1 );\n\tposition = 0;\n\tgtk_editable_insert_text( GTK_EDITABLE( edit ), \n\t\tbuf, strlen( buf ), &position );\n}\n\n/* Set a GtkEditable.\n */\nvoid\nset_gentry( GtkWidget *edit, const char *fmt, ... )\n{\n\tva_list ap;\n\n\tva_start( ap, fmt );\n\tset_gentryv( edit, fmt, ap );\n\tva_end( ap );\n}\n\nvoid\nset_glabel( GtkWidget *label, const char *fmt, ... )\n{\n\tva_list ap;\n\tchar buf[1000];\n\n\tva_start( ap, fmt );\n\t(void) im_vsnprintf( buf, 1000, fmt, ap );\n\tva_end( ap );\n\n\tgtk_label_set_text( GTK_LABEL( label ), buf );\n}\n\n/* Like set_glabel(), but don't display multi-line strings (just display the\n * first line).\n */\nvoid\nset_glabel1( GtkWidget *label, const char *fmt, ... )\n{\n\tva_list ap;\n\tchar txt[1000];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tva_start( ap, fmt );\n\tvips_buf_vappendf( &buf, fmt, ap );\n\tva_end( ap );\n\n\tgtk_label_set_text( GTK_LABEL( label ), vips_buf_firstline( &buf ) );\n}\n\n/* Like set_glabel, but do it caption-style.\n */\nvoid \nset_gcaption( GtkWidget *label, const char *fmt, ... )\n{\n\tva_list ap;\n\tchar buf1[1000];\n\tchar buf2[1000];\n\n\tva_start( ap, fmt );\n\t(void) im_vsnprintf( buf1, 1000, fmt, ap );\n\tva_end( ap );\n\n\tescape_markup( buf1, buf2, 1000 );\n\t(void) im_snprintf( buf1, 1000, \n\t\t\"<span size=\\\"smaller\\\">%s</span>\", buf2 );\n\tgtk_label_set_markup( GTK_LABEL( label ), buf1 );\n}\n\ngboolean\nget_geditable_name( GtkWidget *text, char *out, int sz )\n{\n\tchar *name;\n\tchar *tname;\n\n\tname = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );\n\ttname = trim_nonalpha( name );\n\tif( !tname ) {\n\t\tIM_FREEF( g_free, name );\n\t\terror_top( _( \"Bad identifier.\" ) );\n\t\terror_sub( \n\t\t\t_( \"Enter an identifier. Identifiers start with \"\n\t\t\t\"a letter, and then contain only letters, numbers, \"\n\t\t\t\"apostrophy and underscore.\" ) );\n\t\treturn( FALSE );\n\t}\n\tim_strncpy( out, tname, sz );\n\tg_free( name );\n\n\treturn( TRUE );\n}\n\ngboolean\nget_geditable_string( GtkWidget *text, char *out, int sz )\n{\n\tchar *str;\n\n\tstr = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );\n\tim_strncpy( out, str, sz );\n\tg_free( str );\n\n\treturn( TRUE );\n}\n\ngboolean\nget_geditable_filename( GtkWidget *text, char *out, int sz )\n{\n\tchar *filename;\n\tchar *tfilename;\n\n\tfilename = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );\n\ttfilename = trim_white( filename );\n\tif( !is_valid_filename( tfilename ) ) {\n\t\tg_free( filename );\n\t\treturn( FALSE );\n\t}\n\tim_strncpy( out, tfilename, sz );\n\tg_free( filename );\n\n\treturn( TRUE );\n}\n\n/* Get a geditable as a double.\n */\ngboolean\nget_geditable_double( GtkWidget *text, double *out )\n{\n\tchar *txt;\n\tchar *end;\n\tdouble t;\n\n\ttxt = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );\n\tt = strtod( txt, &end );\n\tif( end == txt ) {\n\t\terror_top( _( \"Bad floating point number.\" ) );\n\t\terror_sub( _( \"\\\"%s\\\" is not a floating point number.\" ), txt );\n\t\tg_free( txt );\n\n\t\treturn( FALSE );\n\t}\n\n\tif( strspn( end, WHITESPACE ) != strlen( end ) ) {\n\t\terror_top( _( \"Bad floating point number.\" ) );\n\t\terror_sub( _( \"Extra characters \\\"%s\\\" after number.\" ), end );\n\t\tg_free( txt );\n\n\t\treturn( FALSE );\n\t}\n\tg_free( txt );\n\n\t*out = t;\n\n\treturn( TRUE );\n}\n\n/* Get as int.\n */\ngboolean\nget_geditable_int( GtkWidget *text, int *n )\n{\n\tint i;\n\tchar *txt;\n\n\t/* Parse values.\n\t */\n\ttxt = gtk_editable_get_chars( GTK_EDITABLE( text ), 0, -1 );\n\tif( sscanf( txt, \"%i\", &i ) != 1 ) {\n\t\terror_top( _( \"Bad integer.\" ) );\n\t\terror_sub( _( \"\\\"%s\\\" is not an integer.\" ), txt );\n\t\tg_free( txt );\n\t\treturn( FALSE );\n\t}\n\tg_free( txt );\n\t*n = i;\n\n\treturn( TRUE );\n}\n\n/* Get as unsigned int.\n */\ngboolean\nget_geditable_uint( GtkWidget *text, int *n )\n{\n\tint i;\n\n\tif( !get_geditable_int( text, &i ) || i < 0 ) {\n\t\terror_top( _( \"Bad unsigned integer.\" ) );\n\t\treturn( FALSE );\n\t}\n\t*n = i;\n\n\treturn( TRUE );\n}\n\n/* Get as positive int.\n */\ngboolean\nget_geditable_pint( GtkWidget *text, int *n )\n{\n\tint i;\n\n\tif( !get_geditable_int( text, &i ) || i <= 0 ) {\n\t\terror_top( _( \"Bad positive integer.\" ) );\n\t\treturn( FALSE );\n\t}\n\t*n = i;\n\n\treturn( TRUE );\n}\n\n/* Indent widget, label above.\n */\nGtkWidget *\nbuild_glabelframe2( GtkWidget *widget, const char *name )\n{\n\tGtkWidget *lab;\n\tGtkWidget *vb;\n\tGtkWidget *hb;\n\tGtkWidget *inv;\n\tchar buf[1000];\n\n        hb = gtk_hbox_new( FALSE, 2 );\n        inv = gtk_label_new( \"\" );\n        gtk_box_pack_start( GTK_BOX( hb ), inv, FALSE, FALSE, 15 );\n        gtk_box_pack_start( GTK_BOX( hb ), widget, TRUE, TRUE, 0 );\n\n        vb = gtk_vbox_new( FALSE, 2 );\n\tim_snprintf( buf, 1000, _( \"%s:\" ), name );\n\tlab = gtk_label_new( buf );\n\tgtk_misc_set_alignment( GTK_MISC( lab ), 0.0, 0.5 );\n        gtk_box_pack_start( GTK_BOX( vb ), lab, FALSE, FALSE, 0 );\n        gtk_box_pack_start( GTK_BOX( vb ), hb, TRUE, TRUE, 0 );\n\n\treturn( vb );\n}\n\n/* Make a text field + label. Indent the text on a new line.\n */\nGtkWidget *\nbuild_glabeltext3( GtkWidget *box, const char *label )\n{\t\n\tGtkWidget *txt;\n\tGtkWidget *vb;\n\n        txt = gtk_entry_new();\n        vb = build_glabelframe2( txt, label );\n        gtk_box_pack_start( GTK_BOX( box ), vb, FALSE, FALSE, 0 );\n\n\treturn( txt );\n}\n\n/* Make text field plus label .. use a sizegroup for alignment.\n */\nGtkWidget *\nbuild_glabeltext4( GtkWidget *box, GtkSizeGroup *group, const char *text )\n{\n\tGtkWidget *hbox;\n\tGtkWidget *label;\n\tGtkWidget *entry;\n\tchar buf[256];\n\n\thbox = gtk_hbox_new( FALSE, 12 );\n\tim_snprintf( buf, 256, _( \"%s:\" ), text );\n\tlabel = gtk_label_new( buf );\n\tgtk_misc_set_alignment( GTK_MISC( label ), 0.0, 0.5 );\n\tif( group )\n\t\tgtk_size_group_add_widget( group, label );  \n\tgtk_box_pack_start( GTK_BOX( hbox ), label, FALSE, FALSE, 0 );\n\n\tentry = gtk_entry_new();\n\tgtk_box_pack_start( GTK_BOX( hbox ), entry, TRUE, TRUE, 0 );\n\n\tgtk_box_pack_start( GTK_BOX( box ), hbox, FALSE, FALSE, 0 );\n\n\tgtk_widget_show_all( hbox );\n\n\treturn( entry );\n}\n\n/* Make a labeled toggle.\n */\nGtkWidget *\nbuild_gtoggle( GtkWidget *box, const char *caption )\n{\n        GtkWidget *hb;\n        GtkWidget *inv;\n\tGtkWidget *toggle;\n\n\t/* Indent left a bit.\n\t */\n        inv = gtk_label_new( \"\" );\n        hb = gtk_hbox_new( FALSE, 0 );\n        gtk_box_pack_start( GTK_BOX( hb ), inv, FALSE, FALSE, 2 );\n        toggle = gtk_check_button_new_with_label( caption );\n\tgtk_container_set_border_width( GTK_CONTAINER( toggle ), 4 );\n        gtk_box_pack_start( GTK_BOX( hb ), toggle, TRUE, TRUE, 0 );\n\n        gtk_box_pack_start( GTK_BOX( box ), hb, FALSE, FALSE, 0 );\n\n\treturn( toggle );\n}\n\n/* Make a label plus option menu.\n */\nGtkWidget *\nbuild_goption( GtkWidget *box, GtkSizeGroup *group, \n\tconst char *name, const char *item_names[], int nitem,\n\tGtkSignalFunc fn, void *value )\n{\n\tGtkWidget *hb;\n\tGtkWidget *label;\n\tGtkWidget *om;\n\tint i;\n\tchar buf[1000];\n\n        hb = gtk_hbox_new( FALSE, 12 );\n\tim_snprintf( buf, 1000, _( \"%s:\" ), name );\n        label = gtk_label_new( buf );\n\tif( group )\n\t\tgtk_size_group_add_widget( group, label );  \n        gtk_box_pack_start( GTK_BOX( hb ), label, FALSE, TRUE, 0 );\n\n\tom = gtk_combo_box_new_text();\n        gtk_box_pack_start( GTK_BOX( hb ), om, FALSE, TRUE, 0 );\n        set_tooltip( om, _( \"Left-click to change value\" ) );\n\n\tfor( i = 0; i < nitem; i++ ) \n\t\tgtk_combo_box_append_text( GTK_COMBO_BOX( om ),\n\t\t\t _( item_names[i] ) );\n\tif( fn ) \n\t\tgtk_signal_connect( GTK_OBJECT( om ), \"changed\", fn, value );\n        gtk_box_pack_start( GTK_BOX( box ), hb, FALSE, TRUE, 0 );\n        gtk_widget_show_all( hb );\n\n\treturn( om );\n}\n\n/* Register a widget as a filename drag receiver.\n */\ntypedef struct {\n\tGtkWidget *widget;\n\tFiledropFunc fn;\n\tvoid *client;\n} FiledropInfo;\n\nstatic gboolean\nfiledrop_trigger( FiledropInfo *fdi, const char *path )\n{\n\tchar buf[FILENAME_MAX];\n\tgboolean result;\n\n\tim_strncpy( buf, path, FILENAME_MAX );\n\tpath_compact( buf );\n\tresult = fdi->fn( fdi->client, buf );\n\n\treturn( result );\n}\n\nstatic void\nfiledrop_drag_data_received( GtkWidget *widget, \n\tGdkDragContext *context,\n\tgint x, gint y, GtkSelectionData *data, guint info, guint time,\n\tFiledropInfo *fdi )\n{\n\tgchar *sPath = NULL;\n\tgchar *pFrom, *pTo; \n\tgboolean result;\n\n        pFrom = strstr( (char *) data->data, \"file:\" );\n\n        while( pFrom ) {\n#if !GLIB_CHECK_VERSION (2,0,0)\n\t\tpFrom += 5; /* remove 'file:' */\n#else\n\t\tGError *error = NULL;\n#endif\n\n\t\tpTo = pFrom;\n\t\twhile( *pTo != 0 && *pTo != 0xd && *pTo != 0xa ) \n\t\t\tpTo += 1;\n\n\t\tsPath = g_strndup( pFrom, pTo - pFrom );\n\n#if !GLIB_CHECK_VERSION (2,0,0)\n\t\tresult = filedrop_trigger( fdi, sPath );\n#else\n\t\t/* format changed with Gtk+1.3, use conversion \n\t\t */\n\t\tpFrom = g_filename_from_uri( sPath, NULL, &error );\n\t\tresult = filedrop_trigger( fdi, pFrom );\n\t\tg_free( pFrom );\n#endif\n\n\t\tg_free( sPath );\n\n\t\tif( !result )\n\t\t\tiwindow_alert( fdi->widget, GTK_MESSAGE_ERROR );\n\n\t\tpFrom = strstr( pTo, \"file:\" );\n        } \n\n        gtk_drag_finish( context, TRUE, FALSE, time );\n}\n\n/* HB: file dnd stuff lent by The Gimp via Dia, not fully understood \n * but working ...\n */\nenum {\n\tTARGET_URI_LIST,\n\tTARGET_TEXT_PLAIN\n};\n\nstatic void\nfiledrop_destroy( GtkWidget *widget, FiledropInfo *fdi )\n{\n\tim_free( fdi );\n}\n\nvoid\nfiledrop_register( GtkWidget *widget, FiledropFunc fn, void *client )\n{\n\tstatic GtkTargetEntry target_table[] = {\n\t\t{ \"text/uri-list\", 0, TARGET_URI_LIST },\n\t\t{ \"text/plain\", 0, TARGET_TEXT_PLAIN }\n\t};\n\n\tFiledropInfo *fdi = INEW( NULL, FiledropInfo );\n\n\tfdi->widget = widget;\n\tfdi->fn = fn;\n\tfdi->client = client;\n\tgtk_signal_connect( GTK_OBJECT( widget ), \"destroy\",\n                GTK_SIGNAL_FUNC( filedrop_destroy ), fdi );\n\n\tgtk_drag_dest_set( GTK_WIDGET( widget ),\n\t\tGTK_DEST_DEFAULT_ALL,\n\t\ttarget_table, IM_NUMBER( target_table ),\n\t\tGDK_ACTION_COPY |\n\t\t/* That's all you need to get draggable URIs in GNOME and\n\t\t * win32, but KDE needs these other flags too, apparently.\n\t\t */\n\t\tGDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK );\n\tgtk_signal_connect( GTK_OBJECT( widget ), \"drag_data_received\",\n\t\tGTK_SIGNAL_FUNC( filedrop_drag_data_received ), fdi );\n}\n\n/* Add symbol drag to the target list.\n */\nvoid\nset_symbol_drag_type( GtkWidget *widget )\n{\n\tstatic const GtkTargetEntry targets[] = {\n\t\t{ \"text/symbol\", 0, TARGET_SYMBOL }\n\t};\n\n\tGtkTargetList *target_list;\n\n\tif( !GTK_WIDGET_REALIZED( widget ) ) \n\t\treturn;\n\n\t/* We can't always set the dest types, since we're probably already a\n\t * filedrop. Just add to the target list.\n\t */\n\tif( (target_list = \n\t\tgtk_drag_dest_get_target_list( widget )) )\n\t\tgtk_target_list_add_table( target_list, \n\t\t\ttargets, IM_NUMBER( targets ) );\n\telse\n\t\tgtk_drag_dest_set( widget,\n\t\t\tGTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_MOTION | \n\t\t\t\tGTK_DEST_DEFAULT_DROP,\n\t\t\ttargets, IM_NUMBER( targets ),\n\t\t\tGDK_ACTION_COPY );\n\n\tgtk_drag_source_set( widget,\n\t\tGDK_BUTTON1_MASK | GDK_BUTTON3_MASK,\n\t\ttargets, IM_NUMBER( targets ),\n\t\tGDK_ACTION_COPY | GDK_ACTION_MOVE );\n}\n\ntypedef struct _Listen {\n\tGObject *gobject;\t\t/* This object */\n\tGObject *source;\t\t/* Listens for signals from this */\n\tGObject **zap;\t\t\t/* NULL this on destroy */\n\tconst char *name;\t\t/* Signal name */\n\tGCallback gcallback;\t\t/* Call this handler */\n\n\tguint name_sid;\n\tguint gobject_destroy_sid;\n\tguint source_destroy_sid;\n} Listen;\n\nstatic void\nlisten_gobject_destroy_cb( GObject *gobject, Listen *listen )\n{\n\t/* gobject has gone ... source should no longer send us signals.\n\t */\n\tFREESID( listen->name_sid, listen->source );\n\tFREESID( listen->source_destroy_sid, listen->source );\n\n\tg_free( listen );\n}\n\nstatic void\nlisten_source_destroy_cb( GObject *gobject, Listen *listen )\n{\n\t/* Source has gone, these signals have been destroyed.\n\t */\n\tlisten->name_sid = 0;\n\tlisten->source_destroy_sid = 0;\n\n\t/* Link broken, no need to auto-free us on gobject destroy.\n\t */\n\tFREESID( listen->gobject_destroy_sid, listen->gobject );\n\n\t/* Zap gobject member pointer to source.\n\t */\n\tif( listen->zap ) {\n\t\tg_assert( !*(listen->zap) || \n\t\t\t*(listen->zap) == listen->source );\n\n\t\t*(listen->zap) = NULL;\n\t}\n\n\tg_free( listen );\n}\n\nvoid\nlisten_add( GObject *gobject, GObject **zap, \n\tconst char *name, GCallback gcallback )\n{\n\tListen *listen = g_new( Listen, 1 );\n\n\tlisten->gobject = gobject;\n\tlisten->source = *zap;\n\tlisten->zap = zap;\n\tlisten->name = name;\n\tlisten->gcallback = gcallback;\n\n\tlisten->name_sid = g_signal_connect( listen->source, \n\t\tlisten->name, listen->gcallback, listen->gobject );\n\tlisten->source_destroy_sid = g_signal_connect( listen->source, \n\t\t\"destroy\",\n\t\tG_CALLBACK( listen_source_destroy_cb ), listen );\n\tlisten->gobject_destroy_sid = g_signal_connect( gobject, \"destroy\",\n\t\tG_CALLBACK( listen_gobject_destroy_cb ), listen );\n}\n\nvoid\nwidget_update_pointer( GtkWidget *widget, GdkEvent *ev )\n{\n\tif( ev->type == GDK_MOTION_NOTIFY && ev->motion.is_hint ) {\n\t\tGdkDisplay *display = gtk_widget_get_display( widget );\n\t\tGdkScreen *screen;\n\t\tint x_root, y_root;\n\n\t\tgdk_display_get_pointer( display, \n\t\t\t&screen, &x_root, &y_root, NULL );\n\t\tev->motion.x_root = x_root;\n\t\tev->motion.y_root = y_root; \n\t}\n}\n\nvoid *\ngobject_print( GObject *gobject )\n{\n\tprintf( \"%s (%p)\\n\", G_OBJECT_TYPE_NAME( gobject ), gobject );\n\n\treturn( NULL );\n}\n\n/* Get the default DPI.\n */\nint\nget_dpi( void )\n{\n\tGdkScreen *screen = gdk_screen_get_default();\n\n\tif( screen ) {\n\t\tint width_pixels = gdk_screen_get_width( screen );\n\t\tint width_mm = gdk_screen_get_width_mm( screen );\n\n\t\treturn( width_pixels / (width_mm / 25.4) );\n\t}\n\telse\n\t\treturn( 72 );\n}\n\nGtkWidget *\nimage_new_from_file( const char *name )\n{\n\tGtkWidget *image;\n\tchar *file;\n\n\tif( (file = path_find_file( name )) ) {\n\t\timage = (GtkWidget *) callv_string_filename( \n\t\t\t(callv_string_fn) gtk_image_new_from_file, \n\t\t\tfile, NULL, NULL, NULL );\n\t\tim_free( file );\n\t}\n\telse\n\t\t/* We get a broken image icon if this fails.\n\t\t */\n\t\timage = gtk_image_new_from_file( name );\n\n\treturn( image );\n}\n\nvoid\nvfatal( GError **error )\n{\n\tfprintf( stderr, PACKAGE \": fatal error\\n\" );\n\n\tif( *error ) {\n\t\tfprintf( stderr, \"%s\\n\", (*error)->message );\n\t\tIM_FREEF( g_error_free, *error );\n\t}\n\n\texit( -1 );\n} \n\nchar *\ntext_view_get_text( GtkTextView *text_view )\n{ \n\tGtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view );\n\tGtkTextIter start_iter;\n\tGtkTextIter end_iter;\n\tchar *text;\n\n\tgtk_text_buffer_get_start_iter( text_buffer, &start_iter );\n\tgtk_text_buffer_get_end_iter( text_buffer, &end_iter );\n\ttext = gtk_text_buffer_get_text( text_buffer, \n\t\t&start_iter, &end_iter, FALSE ); \n\n\treturn( text );\n}\n\nvoid\ntext_view_set_text( GtkTextView *text_view, \n\tconst char *text, gboolean editable )\n{\n\tGtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view );\n\n\tgtk_text_buffer_set_text( text_buffer, text ? text : \"\", -1 );\n\n\tgtk_text_view_set_editable( text_view, editable );\n\tgtk_text_view_set_cursor_visible( text_view, editable );\n}\n\nvoid\ntext_view_select_text( GtkTextView *text_view, int start, int end )\n{\n\tGtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view );\n\tGtkTextMark *mark = gtk_text_buffer_get_insert( text_buffer );\n\tGtkTextIter start_iter;\n\tGtkTextIter end_iter;\n\n\tgtk_text_buffer_get_iter_at_offset( text_buffer, &start_iter, start );\n\tgtk_text_buffer_get_iter_at_offset( text_buffer, &end_iter, end );\n\tgtk_text_buffer_select_range( text_buffer, &start_iter, &end_iter );\n\tgtk_text_view_scroll_mark_onscreen( text_view, mark );\n}\n\n/* If parent dies, kill us too. Parent can be anything, but child must be an\n * iobject.\n */\ntypedef struct _DestroyIfDestroyed {\n\tGObject *child;\n\tGObject *parent;\n\tDestroyFn destroy_fn;\n} DestroyIfDestroyed;\n\nstatic void destroy_if_destroyed_parent_cb( DestroyIfDestroyed *difd, \n\tGObject *parent );\nstatic void destroy_if_destroyed_child_cb( DestroyIfDestroyed *difd, \n\tGObject *child );\n\nstatic void\ndestroy_if_destroyed_parent_cb( DestroyIfDestroyed *difd, GObject *parent )\n{\n\tGObject *child;\n\tDestroyFn destroy_fn;\n\n#ifdef DEBUG\n\tprintf( \"destroy_if_destroyed_parent_cb: %p\\n\", difd );\n#endif /*DEBUG*/\n\n\t/* Destroying the child will trigger the other half of difd, make sure\n\t * we remove the link first.\n\t */\n\tchild = difd->child;\n\tdestroy_fn = difd->destroy_fn;\n\tg_object_weak_unref( difd->child, \n\t\t(GWeakNotify) destroy_if_destroyed_child_cb, difd );\n\tdestroy_fn( child );\n\n\tdifd->child = NULL;\n\tdifd->parent = NULL;\n\tdifd->destroy_fn = NULL;\n\tg_free( difd );\n}\n\nstatic void\ndestroy_if_destroyed_child_cb( DestroyIfDestroyed *difd, GObject *child )\n{\n#ifdef DEBUG\n\tprintf( \"destroy_if_destroyed_child_cb: %p\\n\", difd );\n#endif /*DEBUG*/\n\n\tg_object_weak_unref( difd->parent, \n\t\t(GWeakNotify) destroy_if_destroyed_parent_cb, difd );\n\n\tdifd->child = NULL;\n\tdifd->parent = NULL;\n\tdifd->destroy_fn = NULL;\n\tg_free( difd );\n}\n\nvoid\ndestroy_if_destroyed( GObject *child, GObject *parent, DestroyFn destroy_fn )\n{\n\tDestroyIfDestroyed *difd = g_new( DestroyIfDestroyed, 1 );\n\n#ifdef DEBUG\n\tprintf( \"destroy_if_destroyed %p: parent=%p, child=%p\\n\", \n\t\tdifd, parent, child );\n#endif /*DEBUG*/\n\n\tdifd->child = child;\n\tdifd->parent = parent;\n\tdifd->destroy_fn = destroy_fn;\n\n\tg_object_weak_ref( parent, \n\t\t(GWeakNotify) destroy_if_destroyed_parent_cb, difd );\n\tg_object_weak_ref( child, \n\t\t(GWeakNotify) destroy_if_destroyed_child_cb, difd );\n}\n\n/* A 'safe' way to run a few events.\n */\nvoid\nprocess_events( void )\n{\n\t/* Max events we process before signalling a timeout. Without this we\n\t * can get stuck in event loops in some circumstances.\n\t */\n\tstatic const int max_events = 100;\n\n\t/* Block too much recursion. 0 is from the top-level, 1 is from a\n\t * callback, we don't want any more than that.\n\t */\n\tif( g_main_depth() < 2 ) {\n\t\tint n;\n\n#ifdef DEBUG\n\t\tprintf( \"progress_update: starting event dispatch\\n\" );\n#endif /*DEBUG*/\n\n\t\tfor( n = 0; n < max_events && \n\t\t\tg_main_context_iteration( NULL, FALSE ); n++ )\n\t\t\t;\n\n#ifdef DEBUG\n\t\tprintf( \"progress_update: event dispatch done\\n\" );\n\t\tif( n == max_events )\n\t\t\tprintf( \"progress_update: event dispatch timeout\\n\" );\n#endif /*DEBUG*/\n\t}\n}\n"
  },
  {
    "path": "src/gtkutil.h",
    "content": "/* Declarations supporting gtkutil.c\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* Look up an object's parent class dynamically.\n */\n#define PARENT_CLASS_DYNAMIC( OBJECT ) \\\n\t(g_type_class_peek( \\\n\t\tg_type_parent( \\\n\t\t\tG_TYPE_FROM_INSTANCE( OBJECT ) ) ))\n\n/* Like G_CHECK_TYPE, but insist on an exact match.\n */\n#define TYPE_EXACT( OBJECT, TYPE ) \\\n\t(G_TYPE_FROM_INSTANCE( OBJECT ) == (TYPE))\n\n#define DESTROY_GTK( X ) { \\\n\tif( X ) { \\\n\t\tgtk_object_destroy( GTK_OBJECT( X ) ); \\\n\t\t(X) = NULL; \\\n\t} \\\n}\n\nvoid adjustments_set_value( GtkAdjustment *hadj, GtkAdjustment *vadj,\n        float hval, float vval );\n\nvoid *object_destroy( void *obj );\nvoid *null_g_free( void *obj );\nconst char *object_type_name( GtkObject *obj );\n\nvoid widget_visible( GtkWidget *widget, gboolean visible );\n\n/* Make widgets.\n */\nGtkWidget *build_button( const char *name, GtkSignalFunc cb, gpointer user );\nvoid get_geo( GtkWidget *widget, const char *text, Rect *geo );\nvoid set_fixed( GtkWidget *widget, int nchars );\nGtkWidget *build_entry( int nchars );\n\nGtkWidget *menu_build( const char *name );\nGtkWidget *menu_add_but( GtkWidget *menu, \n\tconst char *name, GtkSignalFunc cb, void *user );\nGtkWidget *menu_add_tog( GtkWidget *menu, \n\tconst char *name, GtkSignalFunc cb, void *user );\nGtkWidget *menu_add_sep( GtkWidget *menu );\nGtkWidget *menu_add_pullright( GtkWidget *popup, const char *name );\n\n/* Popup menu handling.\n */\ntypedef void (*PopupFunc)( GtkWidget *, GtkWidget *, void * );\n#define POPUP_FUNC( fn ) ((PopupFunc) (fn))\n\nGtkWidget *popup_build( const char *name );\nGtkWidget *popup_add_but( GtkWidget *, const char *, PopupFunc );\nGtkWidget *popup_add_tog( GtkWidget *, const char *, PopupFunc );\nGtkWidget *popup_add_pullright( GtkWidget *popup, const char *name );\nvoid popup_show( GtkWidget *host, GdkEvent *ev );\nvoid popup_link( GtkWidget *host, GtkWidget *popup, void *data );\nguint popup_attach( GtkWidget *host, GtkWidget *popup, void *data );\nvoid popup_detach( GtkWidget *host, guint sid );\n\nvoid set_tooltip( GtkWidget *wid, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\nvoid junk_tooltips( void );\n\ntypedef void (*TooltipGenerateFn)( GtkWidget *, VipsBuf *, void *a, void *b );\nvoid set_tooltip_generate( GtkWidget *widget, \n\tTooltipGenerateFn fn, void *a, void *b );\n\n/* Set/get a label/entry, printf style.\n */\nvoid set_gentryv( GtkWidget *edit, const char *fmt, va_list ap );\nvoid set_gentry( GtkWidget *entry, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\nvoid set_glabel( GtkWidget *label, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\nvoid set_glabel1( GtkWidget *label, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\nvoid set_gcaption( GtkWidget *label, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\ngboolean get_geditable_string( GtkWidget *text, char *out, int sz );\ngboolean get_geditable_name( GtkWidget *text, char *out, int sz );\ngboolean get_geditable_filename( GtkWidget *text, char *out, int sz );\ngboolean get_geditable_double( GtkWidget *text, double *out );\ngboolean get_geditable_int( GtkWidget *text, int *n );\ngboolean get_geditable_uint( GtkWidget *text, int *n );\ngboolean get_geditable_pint( GtkWidget *text, int *n );\n\n/* Make widget groups.\n */\nGtkWidget *build_glabelframe2( GtkWidget *box, const char *label );\nGtkWidget *build_glabeltext3( GtkWidget *box, const char *label );\nGtkWidget *build_glabeltext4( GtkWidget *box, GtkSizeGroup *group, \n\tconst char *label );\nGtkWidget *build_gtoggle( GtkWidget *box, const char *caption );\nGtkWidget *build_goption( GtkWidget *box, GtkSizeGroup *group, \n\tconst char *name, const char *item_names[], int nitem,\n\tGtkSignalFunc fn, void *value );\n\ntypedef gboolean (*FiledropFunc)( void *client, const char *file );\nvoid filedrop_register( GtkWidget *widget, FiledropFunc fn, void *client );\n\n/* Tag our thumbnail drag-n-drops with these. Start up a bit to leave room for \n * filedrop.\n */\nenum {\n\tTARGET_SYMBOL = 99\n};\n\nvoid set_symbol_drag_type( GtkWidget *widget );\n\nvoid listen_add( GObject *gobject, GObject **zap, \n\tconst char *name, GCallback gcallback );\n\nvoid widget_update_pointer( GtkWidget *widget, GdkEvent *ev );\n\nvoid *gobject_print( GObject *gobject );\n\nint get_dpi( void );\n\nGtkWidget *image_new_from_file( const char *name );\n\nvoid vfatal( GError **error );\n\nchar *text_view_get_text( GtkTextView *text_view );\nvoid text_view_set_text( GtkTextView *text_view, \n\tconst char *text, gboolean editable );\nvoid text_view_select_text( GtkTextView *text_view, int start, int end );\n\ntypedef void (*DestroyFn)( GObject * );\nvoid destroy_if_destroyed( GObject *child, GObject *parent, \n\tDestroyFn destroy_fn );\n\nvoid process_events( void );\n"
  },
  {
    "path": "src/heap.c",
    "content": "/* Heap management.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n/* GC on every alloc too! Extraordinarily slow. Turn on DEBUG_HEAP in ip.h\n * first. Good for spotting heap pointer errors.\n#define DEBUG_HEAP_GC\n */\n\n/* Count GCs and %full, handy for tuning.\n#define DEBUG_GETMEM\n */\n\n/* Time each GC, handy for benchmarking.\n#define DEBUG_GC_TIME\n */\n\n#include \"ip.h\"\n\nstatic iObjectClass *parent_class = NULL;\n\nstatic GSList *heap_all = NULL;\n\n/* Call a function, passing in a \"safe\" PElement ... ie. the PElement points\n * at a fresh element which will be safe from the GC.\n */\nvoid *\nheap_safe_pointer( Heap *heap, heap_safe_pointer_fn fn, \n\tvoid *a, void *b, void *c, void *d )\n{\n\tElement e;\n\tPElement pe;\n\tvoid *result;\n\n\te.type = ELEMENT_NOVAL;\n\te.ele = (void *) 5;\n\tPEPOINTE( &pe, &e );\n\theap_register_element( heap, &e );\n\n\tresult = fn( heap, &pe, a, b, c, d );\n\n\theap_unregister_element( heap, &e );\n\n\treturn( result );\n}\n\n/* Map a function over a piece of graph.\n */\nvoid *\nheap_map( HeapNode *hn, heap_map_fn fn, void *a, void *b )\n{\n\tvoid *c;\n\n\tif( !hn )\n\t\treturn( NULL );\n\n\tswitch( hn->type ) {\n\tcase TAG_APPL:\n\tcase TAG_CONS:\n\t\tif( (c = fn( hn, a, b )) )\n\t\t\treturn( c );\n\n\t\tif( GETLT( hn ) == ELEMENT_NODE && \n\t\t\t(c = heap_map( GETLEFT( hn ), fn, a, b )) )\n\t\t\treturn( c );\n\t\tif( GETRT( hn ) == ELEMENT_NODE && \n\t\t\t(c = heap_map( GETRIGHT( hn ), fn, a, b )) )\n\t\t\treturn( c );\n\n\t\treturn( NULL );\n\n\tcase TAG_REFERENCE:\n\tcase TAG_COMPLEX:\n\tcase TAG_GEN:\n\tcase TAG_FILE:\n\tcase TAG_CLASS:\n\tcase TAG_DOUBLE:\n\t\treturn( fn( hn, a, b ) );\n\n\tcase TAG_SHARED:\n\t\tif( (c = fn( hn, a, b )) )\n\t\t\treturn( c );\n\n\t\treturn( heap_map( GETLEFT( hn ), fn, a, b ) );\n\n\tcase TAG_FREE:\n\tdefault:\n\t\tg_assert( FALSE );\n\n\t\t/* Keep gcc happy.\n\t\t */\n\t\treturn( NULL );\n\t}\n}\n\n#ifdef DEBUG_HEAP_GC\n/* Debugging ... check that all nodes on the free list are TAG_FREE, and that\n * all other nodes are not TAG_FREE.\n */\nstatic void\nheap_check_free( Heap *heap )\n{\n\tHeapNode *hn;\n\tHeapBlock *hb;\n\n\t/* Clear all the DEBUG flags.\n\t */\n\tfor( hb = heap->hb; hb; hb = hb->next ) {\n\t\tint i;\n\n\t\tfor( i = 0; i < hb->sz; i++ ) {\n\t\t\tHeapNode *hn = &hb->node[i];\n\n\t\t\thn->flgs &= FLAG_DEBUG ^ FLAG_ALL;\n\t\t}\n\t}\n\n\t/* Check free list.\n\t */\n\tfor( hn = heap->free; hn; hn = GETLEFT( hn ) ) {\n\t\tg_assert( hn->type == TAG_FREE );\n\n\t\thn->flgs |= FLAG_DEBUG;\n\t}\n\n\t/* Check for all non-free.\n\t */\n\tfor( hb = heap->hb; hb; hb = hb->next ) {\n\t\tint i;\n\n\t\tfor( i = 0; i < hb->sz; i++ ) {\n\t\t\tHeapNode *hn = &hb->node[i];\n\n\t\t\tg_assert( hn->type != TAG_FREE || \n\t\t\t\t(hn->flgs & FLAG_DEBUG) );\n\t\t}\n\t}\n}\n#endif /*DEBUG_HEAP_GC*/\n\n#ifdef DEBUG_HEAP_GC\nstatic void\nheap_check_managed( void *key, void *value, Heap *heap )\n{\n\t/* Validate pointer.\n\t */\n\t(void) MANAGED( value );\n}\n#endif /*DEBUG_HEAP_GC*/\n\n/* Test for sanity. \n */\nint\nheap_sanity( Heap *heap )\n{\n#ifdef DEBUG_HEAP_GC\n\theap_check_free( heap );\n\n\theap_gc( heap );\n\theap_check_free( heap );\n\tg_hash_table_foreach( heap->mtable, (GHFunc) heap_check_managed, heap );\n#endif /*DEBUG_HEAP_GC*/\n\n\treturn( 0 );\n}\n\n/* Debugging ... check that all heaps have been closed, dump any which\n * haven't.\n */\nvoid\nheap_check_all_destroyed( void )\n{\n\tslist_map( heap_all, (SListMapFn) iobject_dump, NULL );\n}\n\n/* Free a HeapBlock.\n */\nstatic void\nheapblock_free( HeapBlock *hb )\n{\n#ifdef DEBUG\n\tprintf( \"heapblock_free\\n\" );\n#endif /*DEBUG*/\n\n\tif( hb->next )\n\t\theapblock_free( hb->next );\n\tif( hb->node )\n\t\tIM_FREE( hb->node );\n\tIM_FREE( hb );\n}\n\nstatic void\nheap_set_flush( Heap *heap, gboolean flush )\n{\n\theap->flush = flush;\n}\n\nstatic void \nheap_dispose_print( void *key, void *value )\n{ \n\tManaged *managed = MANAGED( value );\n\n\tiobject_print( IOBJECT( managed ) );\n}\n\nstatic void\nheap_dispose( GObject *gobject )\n{\n\tHeap *heap = HEAP( gobject );\n\n\t/* Repeatedly close managed objects. Each close can trigger other\n\t * closes, so we need to loop until done.\n\t */\n\tmanaged_clear( heap );\n\theap_set_flush( heap, TRUE );\n\twhile( managed_free_unused( heap ) )\n\t\t;\n\n\t/* Check all managed objects are dead.\n\t */\n\tg_hash_table_foreach( heap->mtable, \n\t\t(GHFunc) heap_dispose_print, NULL );\n\n\tIM_FREEF( g_source_remove, heap->gc_tid );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\nheap_finalize( GObject *gobject )\n{\n\tHeap *heap = HEAP( gobject );\n\n\tif( heap->hb )\n\t\theapblock_free( heap->hb );\n\n\tIM_FREEF( g_hash_table_destroy, heap->emark );\n\n\tIM_FREEF( g_hash_table_destroy, heap->rmark );\n\n\tIM_FREEF( g_hash_table_destroy, heap->mtable );\n\n\theap_all = g_slist_remove( heap_all, heap );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\nheap_info( iObject *iobject, VipsBuf *buf )\n{\n\tHeap *heap = HEAP( iobject );\n\n\tvips_buf_appendf( buf, \"compile = \" );\n\tif( heap->compile )\n\t\tif( heap->compile->sym ) {\n\t\t\tsymbol_qualified_name( heap->compile->sym, buf );\n\t\t\tvips_buf_appendf( buf, \"(%p) (sym)\\n\", heap->compile->sym ); \n\t\t}\n\t\telse\n\t\t\tvips_buf_appendf( buf, \"(compile, but no sym)\\n\" );\n\telse\n\t\tvips_buf_appendf( buf, \"(no compile)\\n\" );\n\tvips_buf_appendf( buf, \"mxb (max blocks) = %d\\n\", heap->mxb );\n\tvips_buf_appendf( buf, \"rsz (nodes per block) = %d\\n\", heap->rsz );\n\tvips_buf_appendf( buf, \"nb (number of blocks) = %d\\n\", heap->nb );\n\tvips_buf_appendf( buf, \"emark = %d pointers\\n\", \n\t\tg_hash_table_size( heap->emark ) );\n\tvips_buf_appendf( buf, \"rmark = %d pointers\\n\", \n\t\tg_hash_table_size( heap->rmark ) );\n\tvips_buf_appendf( buf, \"ncells (cells allocated) = %d\\n\", heap->ncells );\n\tvips_buf_appendf( buf, \"nfree (cells free at last GC) = %d\\n\", heap->nfree );\n\tvips_buf_appendf( buf, \"mtable (Managed blocks) = %d pointers\\n\", \n\t\tg_hash_table_size( heap->mtable ) );\n\n\tIOBJECT_CLASS( parent_class )->info( iobject, buf );\n}\n\n/* Empty a heap block.\n */\nstatic void\nheapblock_empty( HeapBlock *hb )\n{\n\tint i;\n\n\t/* Set as empty free-list.\n\t */\n\tfor( i = 0; i < hb->sz; i++ ) {\n\t\tHeapNode *hn = &hb->node[i];\n\n\t\thn->type = TAG_FREE;\n\t\thn->flgs = 0;\n\t\tPPUTLEFT( hn, ELEMENT_NODE, hn + 1 );\n\t}\n\tPPUTLEFT( &hb->node[hb->sz - 1], ELEMENT_NODE, NULL );\n}\n\n/* Add another HeapBlock, if we can.\n */\nstatic gboolean\nheapblock_create( Heap *heap, int sz )\n{\n\tHeapBlock *hb;\n\n\tif( heap->nb > heap->mxb ) {\n\t\theap->mxb = 1 + (heap->max_fn( heap ) / heap->rsz);\n\t\tif( heap->nb > heap->mxb ) \n\t\t\t/* Hit limit ... caller detects full by ->free becomng\n\t\t\t * NULL.\n\t\t\t */\n\t\t\treturn( TRUE );\n\t}\n\n#ifdef DEBUG\n\tprintf( \"heapblock_create: new block, size %d\\n\", sz );\n#endif /*DEBUG*/\n\n\tif( !(hb = INEW( NULL, HeapBlock )) ) \n\t\treturn( FALSE );\n\thb->heap = heap;\n\thb->next = NULL;\n\thb->node = NULL;\n\thb->sz = sz;\n\n\tif( !(hb->node = IARRAY( NULL, sz, HeapNode )) ) {\n\t\theapblock_free( hb );\n\t\treturn( FALSE );\n\t}\n\theapblock_empty( hb );\n\n\t/* Link to existing blocks.\n\t */\n\thb->next = heap->hb;\n\theap->hb = hb;\n\tPPUTLEFT( &hb->node[hb->sz - 1], ELEMENT_NODE, heap->free );\n\theap->free = &hb->node[0];\n\theap->nb++;\n\n\treturn( TRUE );\n}\n\nstatic void\nheap_class_init( HeapClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tiObjectClass *iobject_class = IOBJECT_CLASS( class );\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = heap_dispose;\n\tgobject_class->finalize = heap_finalize;\n\n\tiobject_class->info = heap_info;\n}\n\nstatic void\nheap_init( Heap *heap )\n{\n\theap->compile = NULL;\n\n\theap->max_fn = NULL;\n\theap->mxb = -1;\n\theap->rsz = 0;\n\theap->nb = 0;\n\theap->hb = NULL;\n\theap->free = NULL;\n\n\theap->ncells = 0;\n\theap->nfree = 0;\n\theap->serial = 0;\n\theap->filled = FALSE;\n\n\theap->emark = g_hash_table_new( NULL, g_direct_equal );\n\theap->rmark = g_hash_table_new( NULL, g_direct_equal );\n\theap->mtable = g_hash_table_new( NULL, g_direct_equal );\n\n\theap->gc_tid = 0;\n\n\theap->flush = FALSE;\n\n\theap_all = g_slist_prepend( heap_all, heap );\n}\n\nGType\nheap_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( HeapClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) heap_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Heap ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) heap_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_IOBJECT, \n\t\t\t\"Heap\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\nheap_link( Heap *heap, Compile *compile, heap_max_fn max_fn, int stsz, int rsz )\n{\n\theap->compile = compile;\n\theap->max_fn = max_fn;\n\theap->rsz = rsz;\n\n\t(void) heapblock_create( heap, stsz );\n\n\tif( compile )\n\t\tiobject_set( IOBJECT( heap ), \n\t\t\tIOBJECT( compile->sym )->name, NULL );\n\n\t/* Can now set max blocks.\n\t */\n\theap->mxb = 1 + (heap->max_fn( heap ) / rsz);\n}\n\n/* Create an empty heap. mxsz is maximum size of heap in units of nodes, \n * stsz is start size, rsz is heap growth unit.\n */\nHeap *\nheap_new( Compile *compile, heap_max_fn max_fn, int stsz, int rsz )\n{\n\tHeap *heap;\n\n\theap = HEAP( g_object_new( TYPE_HEAP, NULL ) );\n\theap_link( heap, compile, max_fn, stsz, rsz );\n\n\treturn( heap );\n}\n\n/* Set flags on a heap.\n */\nvoid\nheap_set( Heap *heap, NodeFlags setmask )\n{\n\tHeapBlock *hb;\n\tint i;\n\n\tfor( hb = heap->hb; hb; hb = hb->next ) \n\t\tfor( i = 0; i < hb->sz; i++ )\n\t\t\thb->node[i].flgs |= setmask;\n}\n\n/* Clear flags on a heap.\n */\nvoid\nheap_clear( Heap *heap, NodeFlags clearmask )\n{\n\tHeapBlock *hb;\n\tint i;\n\tint cmask = clearmask ^ FLAG_ALL;\n\n\tfor( hb = heap->hb; hb; hb = hb->next ) \n\t\tfor( i = 0; i < hb->sz; i++ )\n\t\t\thb->node[i].flgs &= cmask;\n}\n\n/* Allocate a new serial number for a heap. On return, we guarantee that \n * heap->serial is a value not used by any nodes in the heap.\n */\nint\nheap_serial_new( Heap *heap )\n{\n\theap->serial += 1;\n\tif( heap->serial > FLAG_SERIAL ) {\n\t\theap->serial = 1;\n\t\theap_clear( heap, FLAG_SERIAL );\n\t}\n\n\treturn( heap->serial );\n}\n\n/* Mark a tree. Avoid recursion because of the danger of C stack overflow on \n * large heaps.\n */\nstatic void \nheap_mark_tree( Heap *heap, HeapNode *hn )\n{\n\tGSList *pending = NULL;\n\n\tpending = g_slist_prepend( pending, hn );\n\n\twhile( pending ) {\n\t\thn = (HeapNode *) pending->data;\n\t\tpending = g_slist_remove( pending, hn );\n\n\t\t/* Chase down the LHS of the nodes, add the RHS nodes we pass \n\t\t * to the pending list.\n\t\t */\n\t\tfor(;;) {\n\t\t\tif( hn->flgs & FLAG_MARK ) \n\t\t\t\tbreak;\n\n\t\t\thn->flgs |= FLAG_MARK;\n\n\t\t\t/* Don't modify hn for the do-nothing case: we'll\n\t\t\t * break on the next loop.\n\t\t\t */\n\t\t\tswitch( hn->type ) {\n\t\t\tcase TAG_GEN:\n\t\t\tcase TAG_COMPLEX:\n\t\t\tcase TAG_CLASS:\n\t\t\tcase TAG_APPL:\n\t\t\tcase TAG_CONS:\n\t\t\t\tif( GETRT( hn ) == ELEMENT_MANAGED ) \n\t\t\t\t\tmanaged_mark( (Managed *) \n\t\t\t\t\t\tGETRIGHT( hn ) );\n\t\t\t\tif( GETLT( hn ) == ELEMENT_MANAGED ) \n\t\t\t\t\tmanaged_mark( (Managed *) \n\t\t\t\t\t\tGETLEFT( hn ) );\n\n\t\t\t\tif( GETRT( hn ) == ELEMENT_NODE ) {\n\t\t\t\t\tif( GETLT( hn ) == ELEMENT_NODE ) {\n\t\t\t\t\t\tpending = g_slist_prepend( \n\t\t\t\t\t\t\tpending, \n\t\t\t\t\t\t\tGETRIGHT( hn ) );\n\t\t\t\t\t\thn = GETLEFT( hn );\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\thn = GETRIGHT( hn );\n\t\t\t\t}\n\t\t\t\telse if( GETLT( hn ) == ELEMENT_NODE ) \n\t\t\t\t\thn = GETLEFT( hn );\n\n\t\t\t\tbreak;\n\n\t\t\tcase TAG_FILE:\n\t\t\t\tg_assert( GETLT( hn ) == ELEMENT_MANAGED );\n\t\t\t\tmanaged_mark( (Managed *) GETLEFT( hn ) );\n\t\t\t\tbreak;\n\n\t\t\tcase TAG_DOUBLE:\n\t\t\t\tbreak;\n\n\t\t\tcase TAG_SHARED:\n\t\t\tcase TAG_REFERENCE:\n\t\t\t\tif( GETLT( hn ) == ELEMENT_NODE ) \n\t\t\t\t\thn = GETLEFT( hn );\n\t\t\t\tbreak;\n\n\t\t\tcase TAG_FREE:\n\t\t\tdefault:\n\t\t\t\tg_assert( FALSE );\n\t\t\t}\n\t\t}\n\t}\n}\n\n/* Mark an element.\n */\nstatic void *\nmark_pelement( PElement *base, Heap *heap )\n{\n\tif( PEISMANAGED( base ) )\n\t\tmanaged_mark( MANAGED( PEGETVAL( base ) ) );\n\telse if( PEISNODE( base ) ) \n\t\theap_mark_tree( heap, PEGETVAL( base ) );\n\n\treturn( NULL );\n}\n\n/* Mark an element.\n */\nstatic void \nmark_element( void *key, void *value, Heap *heap )\n{\n\tElement *root = (Element *) value;\n\tPElement base;\n\n\tPEPOINTE( &base, root );\n\t(void) mark_pelement( &base, heap ); \n}\n\n/* Mark a reduce context ... the heapnodes on the spine stack etc.\n */\nstatic void *\nmark_reduce( void *key, void *value, Heap *heap )\n{\n\tReduce *rc = (Reduce *) value;\n\tint i;\n\n#ifdef DEBUG\n\tprintf( \"mark_reduce: marking %d stack elements\\n\", rc->sp );\n#endif /*DEBUG*/\n\n\tfor( i = 0; i < rc->sp; i++ )\n\t\theap_mark_tree( heap, rc->nstack[i] );\n\n\treturn( NULL );\n}\n\n/* Do a garbage collect.\n */\ngboolean\nheap_gc( Heap *heap )\n{\n\tHeapBlock *hb;\n\tint nfree;\n\tint ncells;\n\tint nblocks;\n\n#ifdef DEBUG_GC_TIME\n\tstatic GTimer *GC_timer = NULL;\n\n\tif( !GC_timer )\n\t\tGC_timer = g_timer_new();\n\n\tg_timer_reset( GC_timer );\n\n\tprintf( \"heap_gc: starting GC for heap %s\\n\", IOBJECT( heap )->name );\n#endif /*DEBUG_GC_TIME*/\n\n\t/* Clear marks on managed objects. Nodes should all be clear already.\n\t */\n\tmanaged_clear( heap );\n\n\t/* All flags should be clear, so just mark.\n\t */\n\tg_hash_table_foreach( heap->emark, (GHFunc) mark_element, heap );\n\tg_hash_table_foreach( heap->rmark, (GHFunc) mark_reduce, heap );\n\n\t/* And sweep up unmarked into new free list.\n\t */\n\theap->free = NULL;\n\tncells = nfree = nblocks = 0;\n\tfor( hb = heap->hb; hb; hb = hb->next ) {\n\t\tconst int sz = hb->sz;\n\t\tint i;\n\n\t\tfor( i = 0; i < sz; i++ ) {\n\t\t\tHeapNode * const hn = &hb->node[i];\n\n\t\t\tif( !(hn->flgs & FLAG_MARK) ) {\n\t\t\t\thn->type = TAG_FREE;\n\t\t\t\tPPUTLEFT( hn, ELEMENT_NODE, heap->free );\n#ifdef DEBUG_HEAP_GC\n\t\t\t\t/* Not necessary, but may be helpful to zap\n\t\t\t\t * any pointer in there.\n\t\t\t\t */\n\t\t\t\tPPUTRIGHT( hn, ELEMENT_NODE, NULL );\n#endif /*DEBUG_HEAP_GC*/\n\t\t\t\theap->free = hn;\n\t\t\t\tnfree += 1;\n\t\t\t}\n\n\t\t\thn->flgs &= FLAG_MARK ^ FLAG_ALL;\n\t\t}\n\n\t\tncells += hb->sz;\n\t\tnblocks += 1;\n\t}\n\theap->ncells = ncells;\n\theap->nfree = nfree;\n\n\t/* Close unused managed objects. It can (potentially) take a couple of\n\t * passes through mtable to free everything ... but we'll do more on\n\t * the next GC.\n\t */\n\tmanaged_free_unused( heap );\n\n#ifdef DEBUG_GC_TIME\n\tprintf( \"heap_gc: %d cells in %d blocks, %d in use\\n\",\n\t\tncells, nblocks, ncells - nfree );\n\tprintf( \"(GC took %gs)\\n\",  g_timer_elapsed( GC_timer, NULL ) );\n#endif /*DEBUG_GC_TIME*/\n\n\treturn( TRUE );\n}\n\nstatic gint\nheap_gc_request_cb( Heap *heap )\n{\n\theap->gc_tid = 0;\n\n\tif( !heap_gc( heap ) )\n\t\tprintf( \"help! delayed GC failed!\\n\" );\n\n\tiobject_changed( IOBJECT( heap ) );\n\n\treturn( FALSE );\n}\n\n/* Request a delayed garbage collect.\n */\nvoid\nheap_gc_request( Heap *heap )\n{\n\tIM_FREEF( g_source_remove, heap->gc_tid );\n\theap->gc_tid = g_timeout_add( 1000, \n\t\t(GSourceFunc) heap_gc_request_cb, heap );\n}\n\n/* Register a pointer into a heap.\n */\nvoid\nheap_register_element( Heap *heap, Element *root )\n{\n\tg_hash_table_insert( heap->emark, root, root );\n}\n\n/* Unregister a pointer into a heap.\n */\nvoid\nheap_unregister_element( Heap *heap, Element *root )\n{\n\tif( g_hash_table_remove( heap->emark, root ) ) {\n#ifdef DEBUG\n\t\tprintf( \"heap_unregister_element: %d pointers\\n\",\n\t\t\tg_hash_table_size( heap->emark ) );\n#endif \n\t}\n}\n\n/* Register a Reduce working on this heap.\n */\nvoid\nheap_register_reduce( Heap *heap, Reduce *rc )\n{\n\tg_hash_table_insert( heap->rmark, rc, rc );\n}\n\n/* Unregister a reduce context.\n */\nvoid\nheap_unregister_reduce( Heap *heap, Reduce *rc )\n{\n\tg_hash_table_remove( heap->rmark, rc );\n}\n\n/* Allocate a new HeapNode ... long version. See NEWNODE() macro.\n */\nHeapNode *\nheap_getmem( Heap *heap ) \n{\n\tHeapNode *hn;\n\tint pcused;\n#ifdef DEBUG_GETMEM\n\tstatic int n_heap_getmem = 0;\n#endif /*DEBUG_GETMEM*/\n\n\t/* Easy case ... this should be handled by the NEWNODE macro, but do\n\t * it here as well just in case.\n\t */\n\tif( heap->free ) {\n\t\t(void) EXTRACTNODE( heap, hn );\n\t\treturn( hn );\n\t}\n\n#ifdef DEBUG\n\tprintf( \"heap_getmem: GC on full heap for heap %s\\n\", \n\t\tIOBJECT( heap )->name );\n#endif /*DEBUG*/\n\n\t/* Try a GC.\n\t */\n\tif( !heap_gc( heap ) )\n\t\treturn( NULL );\n\n\t/* Is heap over x% full? Add another heap block if we can.\n\t */\n\tpcused = 100 * (heap->ncells - heap->nfree) / heap->ncells;\n#ifdef DEBUG_GETMEM\n\tn_heap_getmem += 1;\n\tprintf( \"heap_getmem: %d%% (%d)\\n\", pcused, n_heap_getmem );\n#endif /*DEBUG_GETMEM*/\n\n\tif( pcused > 50 ) {\n\t\tint nblocks = 1 + (heap->ncells - heap->nfree) / heap->rsz;\n\t\tint i;\n\n#ifdef DEBUG_GETMEM\n\t\tprintf( \"heap_getmem: %d more blocks added\\n\", nblocks );\n#endif /*DEBUG_GETMEM*/\n\t\tfor( i = 0; i < nblocks; i++ )\n\t\t\tif( !heapblock_create( heap, heap->rsz ) )\n\t\t\t\treturn( NULL );\n\t}\n\n\tif( !heap->free ) {\n\t\terror_top( _( \"Heap full.\" ) );\n\t\tif( heap->compile ) {\n\t\t\tchar txt[100];\n\t\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\t\tcompile_name( heap->compile, &buf );\n\t\t\terror_sub( _( \"The compile heap for %s has filled. \"\n\t\t\t\t\"Make it smaller and less complicated.\" ),\n\t\t\t\tvips_buf_all( &buf ) );\n\t\t}\n\t\telse\n\t\t\terror_sub( _( \"The main calculation heap has filled. \"\n\t\t\t\t\"Raise the heap size limit in Preferences.\" ) );\n\t\theap->filled = TRUE;\n\t\treturn( NULL );\n\t}\n\n\t(void) EXTRACTNODE( heap, hn );\n\n\treturn( hn );\n}\n\ngboolean\nheap_bool_new( Heap *heap, gboolean val, PElement *out )\n{\n\tPEPUTP( out, ELEMENT_BOOL, val );\n\n\treturn( TRUE );\n}\n\n/* Write a real to an element.\n */\ngboolean\nheap_real_new( Heap *heap, double in, PElement *out )\n{\n\tHeapNode *hn;\n\n\tif( NEWNODE( heap, hn ) )\n\t\treturn( FALSE );\n\thn->type = TAG_DOUBLE;\n\thn->body.num = in;\n\n\tPEPUTP( out, ELEMENT_NODE, hn );\n\n\treturn( TRUE );\n}\n\n/* Write an element to an element.\n */\ngboolean\nheap_element_new( Heap *heap, Element *e, PElement *out )\n{\n\tPEPUTE( out, e );\n\n\treturn( TRUE );\n}\n\n/* Make a complex node from two elements. \n */\ngboolean\nheap_complex_element_new( Heap *heap, \n\tPElement *rp, PElement *ip, PElement *out )\n{\n\tHeapNode *hn;\n\n\tif( NEWNODE( heap, hn ) )\n\t\treturn( FALSE );\n\thn->type = TAG_COMPLEX;\n\tPPUT( hn, PEGETTYPE( rp ), PEGETVAL( rp ), \n\t\tPEGETTYPE( ip ), PEGETVAL( ip ) ); \n\n\tPEPUTP( out, ELEMENT_NODE, hn );\n\n\treturn( TRUE );\n}\n\n/* Make a complex node.\n */\ngboolean\nheap_complex_new( Heap *heap, double rp, double ip, PElement *out )\n{\n\tElement dummy;\n\tPElement t;\n\n\t/* Form complex node.\n\t */\n\tdummy.type = ELEMENT_NOVAL;\n\tdummy.ele = (void *) 6;\n\tPEPOINTE( &t, &dummy );\n\tif( !heap_complex_element_new( heap, &t, &t, out ) )\n\t\treturn( FALSE );\n\n\t/* Install real and imag parts.\n\t */\n\tPEPOINTLEFT( PEGETVAL( out ), &t );\n\tif( !heap_real_new( heap, rp, &t ) )\n\t\treturn( FALSE );\n\tPEPOINTRIGHT( PEGETVAL( out ), &t );\n\tif( !heap_real_new( heap, ip, &t ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* 'get' a list: move the PE to point at the list.\n */\ngboolean\nheap_get_list( PElement *list )\n{\n\tg_assert( PEISLIST( list ) );\n\n\tif( PEISMANAGEDSTRING( list ) ) {\n\t\tif( !managedstring_get( PEGETMANAGEDSTRING( list ), list ) )\n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Set list to [].\n */\nvoid\nheap_list_init( PElement *list )\n{\n\tPEPUTP( list, ELEMENT_ELIST, NULL );\n}\n\n/* Add new node to list, point data at new CONS LHS.\n */\ngboolean\nheap_list_add( Heap *heap, PElement *list, PElement *data )\n{\n\tHeapNode *hn;\n\n\t/* Build CONS node.\n\t */\n\tif( NEWNODE( heap, hn ) )\n\t\treturn( FALSE );\n\thn->type = TAG_CONS;\n\tPPUTLEFT( hn, ELEMENT_NOVAL, (void *) 7 );\n\tPEPUTRIGHT( hn, list );\n\tPEPUTP( list, ELEMENT_NODE, hn );\n\n\t/* Point data to new LHS.\n\t */\n\tPEPOINTLEFT( hn, data );\n\n\treturn( TRUE );\n}\n\n/* Move list on to the next RHS. list points at [], or pointer to next node.\n * Used with heap_list_init()/heap_list_add() to build lists.\n */\ngboolean\nheap_list_next( PElement *list )\n{\n\tHeapNode *hn = PEGETVAL( list );\n\n\tif( hn ) {\n\t\tPEPOINTRIGHT( hn, list );\n\t\treturn( TRUE );\n\t}\n\telse\n\t\treturn( FALSE );\n}\n\ngboolean\nheap_list_cat( Reduce *rc, PElement *a, PElement *b, PElement *out )\n{\n\tPElement list = *out;\n\n\tREDUCE_CATCH_START( FALSE );\n\treduce_clone_list( rc, a, &list );\n\tPEPUTPE( &list, b );\n\tREDUCE_CATCH_STOP;\n\n\treturn( TRUE );\n}\n\n/* Start off a function application.\n */\nvoid\nheap_appl_init( PElement *base, PElement *func )\n{\n\tPEPUTPE( base, func );\n}\n\n/* Add a new parameter to a function application. base points at the\n * function built so far ... update base to point to new node (old base\n * becomes LHS), return parm pointing to new RHS\n */\ngboolean\nheap_appl_add( Heap *heap, PElement *base, PElement *parm )\n{\n\tHeapNode *hn;\n\n\t/* Build appl node.\n\t */\n\tif( NEWNODE( heap, hn ) )\n\t\treturn( FALSE );\n\thn->type = TAG_APPL;\n\tPEPUTLEFT( hn, base );\n\tPPUTRIGHT( hn, ELEMENT_ELIST, NULL );\n\tPEPUTP( base, ELEMENT_NODE, hn );\n\n\t/* Point parm to new RHS.\n\t */\n\tPEPOINTRIGHT( hn, parm );\n\n\treturn( TRUE );\n}\n\n/* Make a lazy file read node.\n */\ngboolean\nheap_file_new( Heap *heap, const char *filename, PElement *out )\n{\n\tManagedfile *managedfile;\n\tHeapNode *hn;\n\n\tif( !(managedfile = managedfile_new( heap, filename )) )\n\t\treturn( FALSE );\n\n\t/* Make sure the managedfile survives a GC.\n\t */\n\tMANAGED_REF( managedfile );\n\n\tif( NEWNODE( heap, hn ) ) {\n\t\tMANAGED_UNREF( managedfile );\n\t\treturn( FALSE );\n\t}\n\thn->type = TAG_FILE;\n\tPPUT( hn, \n\t\tELEMENT_MANAGED, managedfile,\n\t\tELEMENT_ELIST, NULL );\n\tPEPUTP( out, ELEMENT_NODE, hn );\n\n\tMANAGED_UNREF( managedfile );\n\n\treturn( TRUE );\n}\n\n/* Make a heap string.\n */\ngboolean\nheap_string_new( Heap *heap, const char *str, PElement *out )\n{\n\tPElement list = *out;\n\tconst int n = strlen( str );\n\tint i;\n\n\theap_list_init( &list ); \n\n\tfor( i = 0; i < n; i++ ) {\n\t\tPElement t;\n\n\t\tif( !heap_list_add( heap, &list, &t ) )\n\t\t\treturn( FALSE );\n\t\tPEPUTP( &t, ELEMENT_CHAR, (int) str[i] );\n\t\t(void) heap_list_next( &list );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Make a managed string.\n */\ngboolean\nheap_managedstring_new( Heap *heap, const char *str, PElement *out )\n{\n\tManagedstring *managedstring;\n\n\tif( strcmp( str, \"\" ) == 0 ) {\n\t\tPEPUTP( out, ELEMENT_ELIST, NULL );\n\t}\n\telse {\n\t\tif( !(managedstring = managedstring_find( heap, str )) )\n\t\t\treturn( FALSE );\n\t\tPEPUTP( out, ELEMENT_MANAGED, managedstring );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Make a [[char]].\n */\ngboolean\nheap_lstring_new( Heap *heap, GSList *labels, PElement *out )\n{\n\tPElement list = *out;\n\tconst int n = g_slist_length( labels );\n\tint i;\n\n\t/* Make first RHS ... the end of the list. \n\t */\n\theap_list_init( &list ); \n\n\t/* Build a CONS node for each element. \n\t */\n\tfor( i = 0; i < n; i++ ) {\n\t\tPElement t;\n\n\t\tif( !heap_list_add( heap, &list, &t ) ||\n\t\t\t!heap_managedstring_new( heap, \n\t\t\t\tg_slist_nth_data( labels, i ), &t ) )\n\t\t\treturn( FALSE );\n\t\t(void) heap_list_next( &list );\n\t}\n\n\treturn( TRUE );\n\n}\n\n/* Make a realvec.\n */\ngboolean\nheap_realvec_new( Heap *heap, int n, double *vec, PElement *out )\n{\n\tPElement list = *out;\n\tint i;\n\n\t/* Make first RHS ... the end of the list. \n\t */\n\theap_list_init( &list );\n\n\t/* Build a CONS node for each element. \n\t */\n\tfor( i = 0; i < n; i++ ) {\n\t\tPElement t;\n\n\t\tif( !heap_list_add( heap, &list, &t ) )\n\t\t\treturn( FALSE );\n\t\tif( !heap_real_new( heap, vec[i], &t ) )\n\t\t\treturn( FALSE );\n\t\t(void) heap_list_next( &list );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Make a realvec, but from an int*.\n */\ngboolean\nheap_intvec_new( Heap *heap, int n, int *vec, PElement *out )\n{\n\tPElement list = *out;\n\tint i;\n\n\t/* Make first RHS ... the end of the list. \n\t */\n\theap_list_init( &list );\n\n\t/* Build a CONS node for each element. \n\t */\n\tfor( i = 0; i < n; i++ ) {\n\t\tPElement t;\n\n\t\tif( !heap_list_add( heap, &list, &t ) )\n\t\t\treturn( FALSE );\n\t\tif( !heap_real_new( heap, (double) vec[i], &t ) )\n\t\t\treturn( FALSE );\n\t\t(void) heap_list_next( &list );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Make a matrix.\n */\ngboolean\nheap_matrix_new( Heap *heap, \n\tint xsize, int ysize, double *vec, PElement *out )\n{\n\tPElement list = *out;\n\tint y, i;\n\n\t/* Make first RHS ... the end of the list. \n\t */\n\theap_list_init( &list );\n\n\t/* Build a CONS node for each element. \n\t */\n\tfor( i = 0, y = 0; y < ysize; y++ ) {\n\t\tPElement t;\n\n\t\tif( !heap_list_add( heap, &list, &t ) )\n\t\t\treturn( FALSE );\n\t\tif( !heap_realvec_new( heap, xsize, vec + i, &t ) )\n\t\t\treturn( FALSE );\n\t\ti += xsize;\n\t\t(void) heap_list_next( &list );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Make a typecheck error. Always return FALSE ... the gboolean is just there\n * for REDUCE_CATCH.\n */\ngboolean\nheap_error_typecheck( PElement *e, const char *name, const char *type )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t(void) reduce_error_typecheck( reduce_context, e, name, type );\n\tREDUCE_CATCH_STOP; \n\n\treturn( FALSE );\n}\n\n/* Map over a heap list. Reduce the list spine as we go, don't reduce the\n * heads. Return base on error, or whatever the user function returns (unlike\n * reduce_map_list(), which we can't just wrap).\n */\nvoid *\nheap_map_list( PElement *base, heap_map_list_fn fn, void *a, void *b )\n{\n\tReduce *rc = reduce_context;\n\tPElement e = *base;\n\n\tif( !reduce_pelement( rc, reduce_spine, &e ) )\n\t\treturn( base );\n\n\tif( !PEISLIST( &e ) ) {\n\t\theap_error_typecheck( &e, \"heap_map_list\", \"[*]\" );\n\t\treturn( base );\n\t}\n\n\twhile( PEISFLIST( &e ) ) {\n\t\tPElement head;\n\t\tvoid *res;\n\n\t\tif( !heap_get_list( &e ) )\n\t\t\treturn( base );\n\n\t\t/* Apply user function to the head.\n\t\t */\n\t\tPEGETHD( &head, &e );\n\t\tif( (res = fn( &head, a, b )) )\n\t\t\treturn( res );\n\n\t\t/* Reduce the tail.\n\t\t */\n\t\tPEGETTL( &e, &e );\n\t\tif( !reduce_pelement( rc, reduce_spine, &e ) )\n\t\t\treturn( base );\n\t}\n\n\treturn( NULL );\n}\n\n/* Iterate over a list. Move list on to the next tl, point data at the\n * head of the current node, FALSE for []. \n */\ngboolean\nheap_get_list_next( PElement *list, PElement *data )\n{\n\tReduce *rc = reduce_context;\n\n\tif( !reduce_pelement( rc, reduce_spine, list ) )\n\t\treturn( FALSE );\n\n\tif( PEISFLIST( list ) ) {\n\t\tHeapNode *hn;\n\n\t\tif( !heap_get_list( list ) )\n\t\t\treturn( FALSE );\n\n\t\thn = PEGETVAL( list );\n\n\t\tPEPOINTRIGHT( hn, list );\n\t\tPEPOINTLEFT( hn, data );\n\n\t\treturn( TRUE );\n\t}\n\telse\n\t\treturn( FALSE );\n}\n\ntypedef struct _HeapMapDict {\n\theap_map_dict_fn fn;\n\tvoid *a;\n\tvoid *b;\n} HeapMapDict;\n\nstatic void *\nheap_map_dict_entry( PElement *head, HeapMapDict *map_dict )\n{\n\tReduce *rc = reduce_context;\n\tchar key[256];\n\tPElement p1, p2;\n\tvoid *result;\n\n\tif( !reduce_pelement( rc, reduce_spine, head ) )\n\t\treturn( head );\n\tif( !PEISFLIST( head ) ) {\n\t\theap_error_typecheck( head, \"heap_map_dict\", \"[*]\" );\n\t\treturn( head );\n\t}\n\tif( !heap_get_list( head ) )\n\t\treturn( head );\n\tPEGETHD( &p1, head );\n\tif( !heap_get_string( &p1, key, 256 ) )\n\t\treturn( head );\n\n\tPEGETTL( &p2, head );\n\tif( !reduce_pelement( rc, reduce_spine, &p2 ) )\n\t\treturn( head );\n\tif( !PEISFLIST( &p2 ) ) {\n\t\theap_error_typecheck( &p2, \"heap_map_dict\", \"[*]\" );\n\t\treturn( head );\n\t}\n\tif( !heap_get_list( &p2 ) )\n\t\treturn( head );\n\tPEGETHD( &p1, &p2 );\n\tif( (result = map_dict->fn( key, &p1, map_dict->a, map_dict->b )) )\n\t\treturn( result );\n\n\tPEGETTL( &p1, &p2 );\n\tif( !reduce_pelement( rc, reduce_spine, &p1 ) )\n\t\treturn( head );\n\tif( !PEISELIST( &p1 ) ) {\n\t\theap_error_typecheck( &p1, \"heap_map_dict\", \"[]\" );\n\t\treturn( head );\n\t}\n\n\treturn( NULL );\n}\n\n/* Map over a list of [\"key\", value] pairs.\n */\nvoid *\nheap_map_dict( PElement *base, heap_map_dict_fn fn, void *a, void *b )\n{\n\tHeapMapDict map_dict;\n\n\tmap_dict.fn = fn;\n\tmap_dict.a = a;\n\tmap_dict.b = b;\n\n\treturn( heap_map_list( base, \n\t\t(heap_map_list_fn) heap_map_dict_entry, &map_dict, NULL ) );\n}\n\n/* Evaluate a PElement into a string buffer. \n */\ngboolean\nheap_get_string( PElement *base, char *buf, int n )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t(void) reduce_get_string( reduce_context, base, buf, n );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\n/* Evaluate a PElement to a [[char]]. \n */\ngboolean\nheap_get_lstring( PElement *base, GSList **labels )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t(void) reduce_get_lstring( reduce_context, base, labels );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\n/* Get an element as a bool. \n */\ngboolean\nheap_get_bool( PElement *base, gboolean *out )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t*out = reduce_get_bool( reduce_context, base );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\n/* Get an element as a real. \n */\ngboolean\nheap_get_real( PElement *base, double *out )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t*out = reduce_get_real( reduce_context, base );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\n/* Get an element as a class ... just reduce and typecheck.\n */\ngboolean\nheap_get_class( PElement *base, PElement *out )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\treduce_get_class( reduce_context, base );\n\tREDUCE_CATCH_STOP; \n\n\t/* Point out at base ... for consistency with other getters.\n\t */\n\t*out = *base;\n\n\treturn( TRUE );\n}\n\n/* Get an element as an image.\n */\ngboolean\nheap_get_image( PElement *base, Imageinfo **out )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t*out = reduce_get_image( reduce_context, base );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\n/* Get an element as a realvec. Return -1 on error, or length of vector.\n */\nint\nheap_get_realvec( PElement *base, double *buf, int n )\n{\n\tReduce *rc = reduce_context;\n\tint l;\n\n\tREDUCE_CATCH_START( -1 );\n\tl = reduce_get_realvec( reduce_context, base, buf, n );\n\tREDUCE_CATCH_STOP; \n\n\treturn( l );\n}\n\n/* Get an element as a imagevec. Return -1 on error, or length of vector.\n */\nint\nheap_get_imagevec( PElement *base, Imageinfo **buf, int n )\n{\n\tReduce *rc = reduce_context;\n\tint l;\n\n\tREDUCE_CATCH_START( -1 );\n\tl = reduce_get_imagevec( reduce_context, base, buf, n );\n\tREDUCE_CATCH_STOP; \n\n\treturn( l );\n}\n\n/* Get an element as a matrix. Return -1 on error, or length of buffer used. \n * Write xsize/ysize to args.\n */\ngboolean\nheap_get_matrix_size( PElement *base, int *xsize, int *ysize )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t(void) reduce_get_matrix_size( reduce_context, base, xsize, ysize );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\n/* Get an element as a matrix. Return -1 on error, or length of buffer used. \n * Write xsize/ysize to args.\n */\ngboolean\nheap_get_matrix( PElement *base, double *buf, int n, int *xsize, int *ysize )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t(void) reduce_get_matrix( reduce_context, base, buf, n, xsize, ysize );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\ngboolean \nheap_is_elist( PElement *base, gboolean *out ) \n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t*out = reduce_is_elist( rc, base );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\ngboolean \nheap_is_list( PElement *base, gboolean *out ) \n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t*out = reduce_is_list( rc, base );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\n/* Do a get, check it's OK. We don't get very much, in case it's a long\n * string and will take a while to eval.\n */\ngboolean \nheap_is_string( PElement *base, gboolean *out ) \n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t*out = reduce_is_string( rc, base );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\ngboolean \nheap_is_realvec( PElement *base, gboolean *out ) \n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t*out = reduce_is_realvec( rc, base );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\ngboolean \nheap_is_imagevec( PElement *base, gboolean *out ) \n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t*out = reduce_is_imagevec( rc, base );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\ngboolean \nheap_is_matrix( PElement *base, gboolean *out ) \n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t*out = reduce_is_matrix( rc, base );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\ngboolean\nheap_is_class( PElement *base, gboolean *out )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t*out = reduce_is_class( rc, base );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\ngboolean\nheap_is_instanceof_exact( const char *name, PElement *klass, gboolean *out )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t*out = reduce_is_instanceof_exact( rc, name, klass );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\ngboolean\nheap_is_instanceof( const char *name, PElement *klass, gboolean *out )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\t*out = reduce_is_instanceof( rc, name, klass );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\nint\nheap_list_length( PElement *base )\n{\n\tReduce *rc = reduce_context;\n\tint result;\n\n\tREDUCE_CATCH_START( -1 );\n\tresult = reduce_list_length( rc, base );\n\tREDUCE_CATCH_STOP; \n\n\treturn( result );\n}\n\nint\nheap_list_length_max( PElement *base, int max_length )\n{\n\tReduce *rc = reduce_context;\n\tint result;\n\n\tREDUCE_CATCH_START( -1 );\n\tresult = reduce_list_length_max( rc, base, max_length );\n\tREDUCE_CATCH_STOP; \n\n\treturn( result );\n}\n\ngboolean\nheap_list_index( PElement *base, int n, PElement *out )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\treduce_list_index( rc, base, n, out );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\ngboolean\nheap_reduce_strict( PElement *base )\n{\n\tReduce *rc = reduce_context;\n\n\tREDUCE_CATCH_START( FALSE );\n\treduce_spine_strict( rc, base );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\n/* hn is a node in a compiled function, out is part of a node in reduce\n * space to which it should be copied. \n *\n * Have to be careful to copy sym pointers in nodes from compile heap.\n */\nstatic gboolean\ncopy_node( Heap *heap, HeapNode *ri[], HeapNode *hn, PElement *out )\n{\n\tHeapNode *hn1;\n\tPElement pleft, pright;\n\tint i;\n\n\t/* Look for relocation nodes.\n\t */\n\tif( hn->type == TAG_SHARED ) {\n\t\t/* RHS of SHARE is the index of this share node.\n\t\t */\n\t\ti = GPOINTER_TO_INT( GETRIGHT( hn ) );\n\n\t\t/* Skip to shared section.\n\t\t */\n\t\thn = GETLEFT( hn );\n\n\t\t/* Copy and link on this node.\n\t\t */\n\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\treturn( FALSE );\n\t\t*hn1 = *hn;\n\t\tPEPUTP( out, ELEMENT_NODE, hn1 );\n\n\t\t/* Note pointer in relocation table.\n\t\t */\n\t\tri[i] = hn1;\n\t}\n\telse if( hn->type == TAG_REFERENCE ) {\n\t\t/* Must have already copied this SHARE, just link back.\n\t\t */\n\t\thn1 = GETLEFT( hn );\n\t\ti = GPOINTER_TO_INT( GETRIGHT( hn1 ) );\n\t\tPEPUTP( out, ELEMENT_NODE, ri[i] );\n\n\t\t/* Done!\n\t\t */\n\t\treturn( TRUE );\n\t}\n\telse {\n\t\t/* Copy and link on this node.\n\t\t */\n\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\treturn( FALSE );\n\t\t*hn1 = *hn;\n\t\tPEPUTP( out, ELEMENT_NODE, hn1 );\n\t}\n\n\t/* If it's a DOUBLE, no more to do.\n\t */\n\tif( hn->type == TAG_DOUBLE )\n\t\treturn( TRUE );\n\n\tif( hn->ltype != ELEMENT_NODE && hn->rtype == ELEMENT_NODE ) {\n\t\t/* Right pointer only. Zap pointer so we can GC\n\t\t * safely.\n\t\t */\n\t\thn1->rtype = ELEMENT_CHAR;\n\n\t\t/* Recurse for RHS of node.\n\t\t */\n\t\tPEPOINTRIGHT( hn1, &pright );\n\t\tif( !copy_node( heap, ri, GETRIGHT( hn ), &pright ) )\n\t\t\treturn( FALSE );\n\t}\n\telse if( hn->ltype == ELEMENT_NODE && hn->rtype != ELEMENT_NODE ) {\n\t\t/* Left pointer only. Zap pointer so we can GC\n\t\t * safely.\n\t\t */\n\t\thn1->ltype = ELEMENT_CHAR;\n\n\t\t/* Recurse for LHS of node.\n\t\t */\n\t\tPEPOINTLEFT( hn1, &pleft );\n\t\tif( !copy_node( heap, ri, GETLEFT( hn ), &pleft ) )\n\t\t\treturn( FALSE );\n\t}\n\telse if( hn->ltype == ELEMENT_NODE && hn->rtype == ELEMENT_NODE ) {\n\t\t/* Both pointers. Zap pointers so we can GC safely.\n\t\t */\n\t\thn1->ltype = ELEMENT_CHAR;\n\t\thn1->rtype = ELEMENT_CHAR;\n\n\t\t/* Recurse for boths sides of node.\n\t\t */\n\t\tPEPOINTLEFT( hn1, &pleft );\n\t\tPEPOINTRIGHT( hn1, &pright );\n\t\tif( !copy_node( heap, ri, GETLEFT( hn ), &pleft ) ||\n\t\t\t!copy_node( heap, ri, GETRIGHT( hn ), &pright ) )\n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Copy a compiled graph into the main reduce space. Overwrite the node at\n * out.\n */\ngboolean\nheap_copy( Heap *heap, Compile *compile, PElement *out )\n{\n\tElement *root = &compile->base;\n\tHeapNode *ri[MAX_RELOC];\n\n\t/* Check for possible C stack overflow ... can't go over 2M on most\n\t * systems if we're using (or any of our libs are using) threads.\n\t */\n\tif( (char *) main_c_stack_base - (char *) &heap > 2000000 ) {\n\t\terror_top( _( \"Overflow error.\" ) );\n\t\terror_sub( _( \"C stack overflow. Circular definition.\" ) );\n\t\treturn( FALSE ); \n\t}\n\n#ifdef DEBUG\n\tprintf( \"heap_copy: \" );\n\tsymbol_name_print( compile->sym );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Check for possible C stack overflow ... can't go over 2M on most\n\t * systems if we're using (or any of our libs are using) threads.\n\t */\n\tif( (char *) main_c_stack_base - (char *) &heap > 2000000 ) {\n\t\terror_top( _( \"Overflow error.\" ) );\n\t\terror_sub( _( \"C stack overflow. Expression too complex.\" ) );\n\t\t\treturn( FALSE );\n\t}\n\n\tswitch( root->type ) {\n\tcase ELEMENT_NODE:\n\t\t/* Need a tree copy.\n\t\t */\n\t\tif( !copy_node( heap, &ri[0], (HeapNode *) root->ele, out ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase ELEMENT_SYMBOL:\n\tcase ELEMENT_CHAR:\n\tcase ELEMENT_BOOL:\n\tcase ELEMENT_BINOP:\n\tcase ELEMENT_SYMREF:\n\tcase ELEMENT_COMPILEREF:\n\tcase ELEMENT_CONSTRUCTOR:\n\tcase ELEMENT_UNOP:\n\tcase ELEMENT_COMB:\n\tcase ELEMENT_TAG:\n\tcase ELEMENT_ELIST:\n\tcase ELEMENT_MANAGED:\n\t\t/* Copy value.\n\t\t */\n\t\tPEPUTP( out, root->type, root->ele );\n\t\tbreak;\n\n\tcase ELEMENT_NOVAL:\n\t\t/* Not compiled yet: compile now, then copy.\n\t\t */\n\t\tif( compile_object( compile ) )\n\t\t\treturn( FALSE );\n\t\tif( !heap_copy( heap, compile, out ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Try to make a gvalue from a heap object. \n */\ngboolean\nheap_ip_to_gvalue( PElement *in, GValue *out )\n{\n\tReduce *rc = reduce_context;\n\n\tif( !reduce_pelement( rc, reduce_spine_strict, in ) )\n\t\treturn( FALSE );\n\n\tif( PEISREAL( in ) ) {\n\t\tg_value_init( out, G_TYPE_DOUBLE );\n\t\tg_value_set_double( out, PEGETREAL( in ) );\n\t}\n\telse if( PEISBOOL( in ) ) {\n\t\tg_value_init( out, G_TYPE_BOOLEAN );\n\t\tg_value_set_boolean( out, PEGETBOOL( in ) );\n\t}\n\telse if( PEISCOMPLEX( in ) ) {\n\t\tprintf( \"ip_to_gvalue: no complex gtype!\\n\" );\n\t\treturn( FALSE );\n\t}\n\telse if( PEISIMAGE( in ) ) {\n\t\tImageinfo *ii = PEGETII( in );\n\t\tVipsImage *im = imageinfo_get( FALSE, ii );\n\n\t\tg_value_init( out, VIPS_TYPE_IMAGE );\n\t\tg_value_set_object( out, im );\n\t}\n\telse if( PEISLIST( in ) ) {\n\t\tgboolean result;\n\n\t\tif( heap_is_string( in, &result ) &&\n\t\t\tresult ) {\n\t\t\tchar name[256];\n\n\t\t\tif( !heap_get_string( in, name, 256 ) )\n\t\t\t\treturn( FALSE );\n\n\t\t\t/* We want a refstring, not a G_TYPE_STRING, since\n\t\t\t * this GValue will (probably) be used by vips with\n\t\t\t * im_header_string() etc.\n\t\t\t */\n\t\t\tg_value_init( out, IM_TYPE_REF_STRING );\n\t\t\tim_ref_string_set( out, name );\n\t\t}\n#if VIPS_MAJOR_VERSION > 7 || VIPS_MINOR_VERSION > 39\n\t\t/* vips_value_set_array_*() is a 7.40 feature.\n\t\t */\n\t\telse if( heap_is_imagevec( in, &result ) &&\n\t\t\tresult ) { \n\t\t\tImageinfo *iivec[MAX_VEC];\n\t\t\tVipsImage **ivec;\n\t\t\tint n;\n\t\t\tint i;\n\n\t\t\tif( (n = heap_get_imagevec( in, \n\t\t\t\tiivec, MAX_VEC )) < 0 ) \n\t\t\t\treturn( FALSE );\n\t\t\tg_value_init( out, VIPS_TYPE_ARRAY_IMAGE );\n\t\t\tvips_value_set_array_image( out, n ); \n\t\t\tivec = vips_value_get_array_image( out, NULL );\n\t\t\tfor( i = 0; i < n; i++ ) {\n\t\t\t\tivec[i] = imageinfo_get( FALSE, iivec[i] );\n\n\t\t\t\t/* g_value_unset() on out will unref every\n\t\t\t\t * array element, so we need to ref.\n\t\t\t\t */\n\t\t\t\tg_object_ref( ivec[i] ); \n\t\t\t}\n\t\t}\n\t\telse if( heap_is_realvec( in, &result ) &&\n\t\t\tresult ) { \n\t\t\tdouble realvec[MAX_VEC];\n\t\t\tint n;\n\n\t\t\tif( (n = heap_get_realvec( in, \n\t\t\t\trealvec, MAX_VEC )) < 0 ) \n\t\t\t\treturn( FALSE );\n\t\t\tg_value_init( out, VIPS_TYPE_ARRAY_DOUBLE );\n\t\t\tvips_value_set_array_double( out, realvec, n );\n\t\t}\n#endif\n\t\telse {\n\t\t\terror_top( _( \"Unimplemented list type.\" ) );\n\t\t\treturn( FALSE );\n\t\t}\n\t}\n\telse if( PEISMANAGED( in ) && IS_MANAGEDGOBJECT( PEGETVAL( in ) ) ) {\n\t\tg_value_init( out, G_TYPE_OBJECT );\n\t\tg_value_set_object( out, \n\t\t\tMANAGEDGOBJECT( PEGETMANAGED( in ) )->object );\n\t}\n\telse {\n\t\tchar txt[100];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\terror_top( _( \"Unimplemented argument type.\" ) );\n\t\t(void) itext_value( rc, &buf, in );\n\t\terror_sub( _( \"Cannot convert %s to GValue.\" ), \n\t\t\tvips_buf_all( &buf ) );\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Try to make a heap object from a gvalue.\n */\ngboolean\nheap_gvalue_to_ip( GValue *in, PElement *out )\n{\n\tReduce *rc = reduce_context;\n\tHeap *heap = rc->heap;\n\n\tif( G_VALUE_HOLDS_BOOLEAN( in ) ) {\n\t\tPEPUTP( out, ELEMENT_BOOL, (int) g_value_get_boolean( in ) );\n\t}\n\telse if( G_VALUE_HOLDS_CHAR( in ) ) {\n\t\t/* g_value_get_schar() is not in older glibs.\n\t\t */\n\t\tPEPUTP( out, ELEMENT_CHAR, (int) g_value_get_uchar( in ) );\n\t}\n\telse if( G_VALUE_HOLDS_UCHAR( in ) ) {\n\t\tPEPUTP( out, ELEMENT_CHAR, (int) g_value_get_uchar( in ) );\n\t}\n\telse if( G_VALUE_HOLDS_INT( in ) ) {\n\t\tif( !heap_real_new( heap, g_value_get_int( in ), out ) )\n\t\t\treturn( FALSE );\n\t}\n\telse if( G_VALUE_HOLDS_UINT( in ) ) {\n\t\tif( !heap_real_new( heap, g_value_get_uint( in ), out ) )\n\t\t\treturn( FALSE );\n\t}\n\telse if( G_VALUE_HOLDS_LONG( in ) ) {\n\t\tif( !heap_real_new( heap, g_value_get_long( in ), out ) )\n\t\t\treturn( FALSE );\n\t}\n\telse if( G_VALUE_HOLDS_ULONG( in ) ) {\n\t\tif( !heap_real_new( heap, g_value_get_ulong( in ), out ) )\n\t\t\treturn( FALSE );\n\t}\n\telse if( G_VALUE_HOLDS_INT64( in ) ) {\n\t\tif( !heap_real_new( heap, g_value_get_int64( in ), out ) )\n\t\t\treturn( FALSE );\n\t}\n\telse if( G_VALUE_HOLDS_UINT64( in ) ) {\n\t\tif( !heap_real_new( heap, g_value_get_uint64( in ), out ) )\n\t\t\treturn( FALSE );\n\t}\n\telse if( G_VALUE_HOLDS_FLOAT( in ) ) {\n\t\tif( !heap_real_new( heap, g_value_get_float( in ), out ) )\n\t\t\treturn( FALSE );\n\t}\n\telse if( G_VALUE_HOLDS_DOUBLE( in ) ) {\n\t\tif( !heap_real_new( heap, g_value_get_double( in ), out ) )\n\t\t\treturn( FALSE );\n\t}\n\telse if( G_VALUE_HOLDS_ENUM( in ) ) {\n\t\tif( !heap_real_new( heap, g_value_get_enum( in ), out ) )\n\t\t\treturn( FALSE );\n\t}\n\telse if( G_VALUE_HOLDS_STRING( in ) ) {\n\t\tif( !heap_managedstring_new( heap, \n\t\t\tg_value_get_string( in ), out ) )\n\t\t\treturn( FALSE );\n\t}\n\telse if( G_VALUE_HOLDS_OBJECT( in ) ) {\n\t\tGObject *object;\n\t\tManaged *managed;\n\n\t\tobject = g_value_get_object( in );\n\n\t\tif( VIPS_IS_IMAGE( object ) ) {\n\t\t\tVipsImage *image = VIPS_IMAGE( object ); \n\n\t\t\tg_object_ref( image ); \n\t\t\tmanaged = MANAGED( imageinfo_new( main_imageinfogroup, \n\t\t\t\theap, image, image->filename ) );\n\t\t}\n\t\telse \n\t\t\tmanaged = MANAGED( managedgobject_new( heap, object ) );\n\n\t\tPEPUTP( out, ELEMENT_MANAGED, managed );\n\t}\n\telse if( g_value_type_transformable( G_VALUE_TYPE( in ), \n\t\tG_TYPE_STRING ) ) {\n\t\tGValue temp = { 0 };\n\n\t\tg_value_init( &temp, G_TYPE_STRING );\n\t\tg_value_transform( in, &temp );\n\t\tif( !heap_managedstring_new( heap, \n\t\t\tg_value_get_string( &temp ), out ) ) {\n\t\t\treturn( FALSE );\n\t\t\tg_value_unset( &temp );\n\t\t}\n\t\tg_value_unset( &temp );\n\t}\n\telse {\n\t\terror_top( _( \"Unimplemented type.\" ) );\n\t\terror_sub( _( \"Unable to convert %s to a nip type.\" ), \n\t\t\tG_VALUE_TYPE_NAME( in ) ); \n\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Indent step.\n */\n#define TAB (2)\n\n/* Fwd ref.\n */\nstatic void lisp_pelement( VipsBuf *buf, PElement *base, \n\tGSList **back, gboolean fn, int indent );\n\n/* Print a sym-value list.\n */\nstatic void\nlisp_symval( VipsBuf *buf, PElement *base, \n\tGSList **back, gboolean fn, int indent, PElement *stop )\n{\n\tgboolean error = FALSE;\n\n\t/* Reached the \"stop\" element?\n\t */\n\tif( stop && *base->type == *stop->type && *base->ele == *stop->ele )\n\t\treturn;\n\n\tif( PEISNODE( base ) ) {\n\t\tHeapNode *hn = PEGETVAL( base );\n\t\tPElement pe;\n\n\t\tif( hn->type != TAG_CONS )\n\t\t\terror = TRUE;\n\n\t\tPEPOINTLEFT( hn, &pe );\n\t\tif( !error && PEISNODE( &pe ) ) {\n\t\t\tHeapNode *hn2 = PEGETVAL( &pe );\n\n\t\t\tif( hn2->type != TAG_CONS )\n\t\t\t\terror = TRUE;\n\n\t\t\tPEPOINTLEFT( hn2, &pe );\n\t\t\tif( !error && PEISSYMREF( &pe ) ) {\n\t\t\t\tvips_buf_appendf( buf, \"\\n%s\", spc( indent ) );\n\t\t\t\tsymbol_qualified_name( \n\t\t\t\t\tPEGETSYMREF( &pe ), buf );\n\t\t\t\tvips_buf_appendf( buf, \" = \" );\n\n\t\t\t\tPEPOINTRIGHT( hn2, &pe );\n\t\t\t\tlisp_pelement( buf, &pe, \n\t\t\t\t\tback, fn, indent + TAB );\n\n\t\t\t\tPEPOINTRIGHT( hn, &pe );\n\t\t\t\tlisp_symval( buf, &pe, back, fn, indent, stop );\n\t\t\t}\n\t\t\telse\n\t\t\t\terror = TRUE;\n\t\t}\n\t\telse\n\t\t\terror = TRUE;\n\t}\n\telse if( !PEISELIST( base ) ) \n\t\terror = TRUE;\n\n\tif( error )\n\t\tvips_buf_appendf( buf, \"\\n%s<*** malformed symval list>\", \n\t\t\tspc( indent ) );\n}\n\n/* Print a [*] ... our caller has printed the enclosing [ ] and the first\n * element, so we print a \", \" followed by us.\n */\nstatic void\nlisp_list( VipsBuf *buf, PElement *base, \n\tGSList **back, gboolean fn, int indent )\n{\n\tif( PEISNODE( base ) ) {\n\t\tHeapNode *hn = PEGETVAL( base );\n\t\tPElement pe;\n\n\t\tvips_buf_appends( buf, \", \" );\n\n\t\tif( hn->type == TAG_CONS ) {\n\t\t\tPEPOINTLEFT( hn, &pe );\n\t\t\tlisp_pelement( buf, &pe, back, fn, indent );\n\n\t\t\tPEPOINTRIGHT( hn, &pe );\n\t\t\tlisp_list( buf, &pe, back, fn, indent );\n\t\t}\n\t\telse\n\t\t\tlisp_pelement( buf, base, back, fn, indent );\n\t}\n\telse if( PEISMANAGEDSTRING( base ) ) {\n\t\tvips_buf_appends( buf, \", Managedstring <\" );\n\t\tvips_buf_appends( buf, PEGETMANAGEDSTRING( base )->string );\n\t\tvips_buf_appends( buf, \">\" );\n\t}\n\telse if( !PEISELIST( base ) ) \n\t\tlisp_pelement( buf, base, back, fn, indent );\n}\n\n/* Print a [char] ... fall back to lisp_list() if we hit a non-char\n * element. base is the RHS of a cons, so it can be a managedstring too.\n */\nstatic gboolean\nlisp_string( VipsBuf *buf, PElement *base, \n\tGSList **back, gboolean fn, int indent )\n{\n\tgboolean error = FALSE;\n\n\tif( PEISNODE( base ) ) {\n\t\tHeapNode *hn = PEGETVAL( base );\n\t\tPElement pe;\n\n\t\tif( hn->type != TAG_CONS )\n\t\t\terror = TRUE;\n\n\t\tPEPOINTLEFT( hn, &pe );\n\t\tif( !error ) {\n\t\t\tif( PEISCHAR( &pe ) ) {\n\t\t\t\tvips_buf_appendf( buf, \"%c\", PEGETCHAR( &pe ) );\n\n\t\t\t\tPEPOINTRIGHT( hn, &pe );\n\t\t\t\t(void) lisp_string( buf, \n\t\t\t\t\t&pe, back, fn, indent );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tvips_buf_appends( buf, \"\\\":[\" );\n\t\t\t\tlisp_pelement( buf, &pe, back, fn, indent );\n\n\t\t\t\tPEPOINTRIGHT( hn, &pe );\n\t\t\t\tlisp_list( buf, &pe, back, fn, indent );\n\t\t\t\tvips_buf_appends( buf, \"]\" );\n\n\t\t\t\terror = TRUE;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\terror = TRUE;\n\t}\n\telse if( PEISMANAGEDSTRING( base ) ) \n\t\tvips_buf_appends( buf, PEGETMANAGEDSTRING( base )->string );\n\telse if( !PEISELIST( base ) ) \n\t\terror = TRUE;\n\n\treturn( error ); \n}\n\n/* Print a graph LISP-style.\n */\nstatic void\nlisp_node( VipsBuf *buf, HeapNode *hn, GSList **back, gboolean fn, int indent )\n{\n\tint i;\n\tPElement p1, p2;\n\n\t/* Have we printed this node before?\n\t */\n\tif( hn->flgs & FLAG_PRINT ) {\n\t\tif( (i = g_slist_index( *back, hn )) == -1 ) {\n\t\t\t*back = g_slist_prepend( *back, hn );\n\t\t\tvips_buf_appendf( buf, \"<\" ); \n\t\t\tvips_buf_appendf( buf, _( \"circular\" ) ); \n\t\t\tvips_buf_appendf( buf, \" (%p)>\", hn );\n\t\t}\n\t\telse {\n\t\t\tvips_buf_appendf( buf, \"<\" );\n\t\t\tvips_buf_appendf( buf, _( \"circular to label %d\" ), i );\n\t\t\tvips_buf_appendf( buf, \">\" );\n\t\t}\n\n\t\treturn;\n\t}\n\thn->flgs |= FLAG_PRINT;\n\n\tif( (i = g_slist_index( *back, hn )) != -1 ) {\n\t\tvips_buf_appendf( buf, \"*\" );\n\t\tvips_buf_appendf( buf, _( \"label %d\" ), i );\n\t\tvips_buf_appendf( buf, \": \" );\n\t}\n\n\tswitch( hn->type ) {\n\tcase TAG_APPL:\n\t\tif( fn ) {\n\t\t\tPEPOINTLEFT( hn, &p1 );\n\t\t\tPEPOINTRIGHT( hn, &p2 );\n\t\t\tvips_buf_appends( buf, \"(\" );\n\t\t\tlisp_pelement( buf, &p1, back, fn, indent );\n\t\t\tvips_buf_appends( buf, \" \" );\n\t\t\tlisp_pelement( buf, &p2, back, fn, indent );\n\t\t\tvips_buf_appends( buf, \")\" );\n\t\t}\n\t\telse {\n\t\t\tvips_buf_appends( buf, \"<\" );\n\t\t\tvips_buf_appends( buf, _( \"unevaluated\" ) );\n\t\t\tvips_buf_appends( buf, \">\" );\n\t\t}\n\n\t\tbreak;\n\n\tcase TAG_CONS:\n\t\tPEPOINTLEFT( hn, &p1 );\n\t\tif( PEISCHAR( &p1 ) ) {\n\t\t\tvips_buf_appendf( buf, \"\\\"%c\", PEGETCHAR( &p1 ) );\n\t\t\tPEPOINTRIGHT( hn, &p2 );\n\t\t\t(void) lisp_string( buf, &p2, back, fn, indent );\n\t\t\tvips_buf_appends( buf, \"\\\"\" );\n\t\t}\n\t\telse {\n\t\t\tvips_buf_appends( buf, \"[\" );\n\t\t\tlisp_pelement( buf, &p1, back, fn, indent );\n\t\t\tPEPOINTRIGHT( hn, &p2 );\n\t\t\tlisp_list( buf, &p2, back, fn, indent );\n\t\t\tvips_buf_appends( buf, \"]\" );\n\t\t}\n\t\tbreak;\n\n\tcase TAG_DOUBLE:\n\t\tvips_buf_appendf( buf, \"%g\", hn->body.num );\n\t\tbreak;\n\n\tcase TAG_COMPLEX:\n\t\tvips_buf_appendf( buf, \"(%g,%g)\", \n\t\t\tGETLEFT( hn )->body.num, GETRIGHT( hn )->body.num );\n\t\tbreak;\n\n\tcase TAG_CLASS:\n\t\tif( fn ) {\n\t\t\tvips_buf_appendf( buf, \"\\n%s\", spc( indent ) );\n\t\t\tvips_buf_appendf( buf, _( \"class (%p)\" ), hn );\n\t\t\tvips_buf_appendf( buf, \" \" );\n\t\t}\n\n\t\tPEPOINTLEFT( hn, &p1 );\n\t\tlisp_pelement( buf, &p1, back, fn, indent );\n\n\t\tif( fn ) {\n\t\t\thn = GETRIGHT( hn );\n\n\t\t\tvips_buf_appendf( buf, \"\\n%s\", spc( indent + TAB ) ); \n\t\t\tvips_buf_appendf( buf, _( \"members\" ) );\n\t\t\tvips_buf_appendf( buf, \" = { \" );\n\t\t\tPEPOINTRIGHT( hn, &p1 );\n\t\t\tlisp_symval( buf, &p1, \n\t\t\t\tback, fn, indent + TAB * 2, NULL );\n\t\t\tvips_buf_appendf( buf, \"\\n%s}\", spc( indent + TAB ) ); \n\n\t\t\tPEPOINTLEFT( hn, &p2 );\n\t\t\tif( *p1.type != *p2.type || *p1.ele != *p2.ele ) { \n\t\t\t\tvips_buf_appendf( buf, \"\\n%s\", \n\t\t\t\t\tspc( indent + TAB ) );\n\t\t\t\tvips_buf_appendf( buf, _( \"secret\" ) );\n\t\t\t\tvips_buf_appendf( buf, \" = { \" );\n\t\t\t\tlisp_symval( buf, &p2, \n\t\t\t\t\tback, fn, indent + TAB * 2, &p1 );\n\t\t\t\tvips_buf_appendf( buf, \n\t\t\t\t\t\"\\n%s} \", spc( indent + TAB ) ); \n\t\t\t}\n\t\t}\n\n\t\tbreak;\n\n\tcase TAG_GEN:\n\t\tvips_buf_appendf( buf, \"[%g,%g...\", \n\t\t\tGETLEFT( hn )->body.num, \n\t\t\tGETLEFT( GETRIGHT( hn ) )->body.num ); \n\t\tif( GETRT( GETRIGHT( hn ) ) == ELEMENT_ELIST )\n\t\t\tvips_buf_appends( buf, \"[ ]]\" );\n\t\telse\n\t\t\tvips_buf_appendf( buf, \"%g]\",\n\t\t\t\tGETRIGHT( GETRIGHT( hn ) )->body.num ); \n\t\tbreak;\n\n\tcase TAG_SHARED:\n\t\tPEPOINTLEFT( hn, &p1 );\n\t\ti = GPOINTER_TO_INT( GETRIGHT( hn ) );\n\t\tvips_buf_appendf( buf, \"SHARE%d[\", i );\n\t\tlisp_pelement( buf, &p1, back, fn, indent );\n\t\tvips_buf_appends( buf, \"]\" );\n\t\tbreak;\n\n\tcase TAG_REFERENCE:\n\t\ti = GPOINTER_TO_INT( GETRIGHT( GETLEFT( hn ) ) );\n\t\tvips_buf_appendf( buf, \"REF%d\", i );\n\t\tbreak;\n\n\tcase TAG_FREE:\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n}\n\n/* Print a pelement LISP-style.\n */\nstatic void\nlisp_pelement( VipsBuf *buf, PElement *base, \n\tGSList **back, gboolean fn, int indent )\n{\n\tHeapNode *hn;\n\tEType type = PEGETTYPE( base );\n\n\tswitch( type ) {\n\tcase ELEMENT_NOVAL:\n\t\tvips_buf_appends( buf, \"<\" );\n\t\tvips_buf_appendf( buf, _( \"no value (type %d)\" ), \n\t\t\tGPOINTER_TO_INT( PEGETVAL( base ) ) );\n\t\tvips_buf_appends( buf, \">\" );\n\t\tbreak;\n\n\tcase ELEMENT_NODE:\n\t\tif( !(hn = PEGETVAL( base )) ) {\n\t\t\tvips_buf_appends( buf, \"<\" );\n\t\t\tvips_buf_appends( buf, _( \"NULL pointer\" ) );\n\t\t\tvips_buf_appends( buf, \">\" );\n\t\t}\n\t\telse\n\t\t\tlisp_node( buf, hn, back, fn, indent );\n\t\tbreak;\n\n\tcase ELEMENT_SYMBOL:\n\t\tvips_buf_appends( buf, \"<\" ); \n\t\tvips_buf_appends( buf, _( \"symbol\" ) ); \n\t\tvips_buf_appends( buf, \" \\\"\" ); \n\t\tsymbol_qualified_name( PEGETSYMBOL( base ), buf );\n\t\tvips_buf_appends( buf, \"\\\">\" ); \n\t\tbreak;\n\n\tcase ELEMENT_CONSTRUCTOR:\n\t\tvips_buf_appends( buf, \"<\" ); \n\t\tvips_buf_appends( buf, _( \"constructor\" ) ); \n\t\tvips_buf_appends( buf, \" \\\"\" ); \n\t\tsymbol_qualified_name( PEGETCOMPILE( base )->sym, buf );\n\t\tvips_buf_appends( buf, \"\\\">\" ); \n\t\tbreak;\n\n\tcase ELEMENT_SYMREF:\n\t\tvips_buf_appends( buf, \"<\" ); \n\t\tvips_buf_appends( buf, _( \"symref\" ) ); \n\t\tvips_buf_appends( buf, \" \\\"\" ); \n\t\tsymbol_qualified_name( PEGETSYMBOL( base ), buf );\n\t\tvips_buf_appends( buf, \"\\\">\" ); \n\t\tbreak;\n\n\tcase ELEMENT_COMPILEREF:\n\t\tvips_buf_appends( buf, \"<\" ); \n\t\tvips_buf_appends( buf, _( \"compileref\" ) ); \n\t\tvips_buf_appends( buf, \" \\\"\" ); \n\t\tsymbol_qualified_name( PEGETCOMPILE( base )->sym, buf );\n\t\tvips_buf_appends( buf, \"\\\">\" ); \n\t\tbreak;\n\n\tcase ELEMENT_CHAR:\n\t\tvips_buf_appendf( buf, \"'%c'\", (int) PEGETCHAR( base ) );\n\t\tbreak;\n\n\tcase ELEMENT_BOOL:\n\t\tvips_buf_appends( buf, bool_to_char( PEGETBOOL( base ) ) );\n\t\tbreak;\n\n\tcase ELEMENT_BINOP:\n\t\tvips_buf_appends( buf, decode_BinOp( PEGETBINOP( base ) ) );\n\t\tbreak;\n\n\tcase ELEMENT_UNOP:\n\t\tvips_buf_appends( buf, decode_UnOp( PEGETUNOP( base ) ) );\n\t\tbreak;\n\n\tcase ELEMENT_ELIST:\n\t\tvips_buf_appends( buf, \"[ ]\" ); \n\t\tbreak;\n\n\tcase ELEMENT_TAG:\n\t\tvips_buf_appendf( buf, \"<\" );\n\t\tvips_buf_appendf( buf, _( \"tag \\\"%s\\\"\" ), PEGETTAG( base ) );\n\t\tvips_buf_appendf( buf, \">\" );\n\t\tbreak;\n\n\tcase ELEMENT_MANAGED:\n\t\tvips_buf_appendf( buf, \"<Managed* %p>\", PEGETVAL( base ) );\n\t\tbreak;\n\n\tcase ELEMENT_COMB:\n\t\tvips_buf_appends( buf, \n\t\t\tdecode_CombinatorType( PEGETCOMB( base ) ) );\n\t\tbreak;\n\n\tdefault:\n\t\tvips_buf_appendf( buf, \"<\" );\n\t\tvips_buf_appendf( buf, _( \"unknown element tag %d\" ), type );\n\t\tvips_buf_appendf( buf, \">\" );\n\t\tbreak;\n\t}\n}\n\n/* Print a node to a buffer. If fn is true, trace into functions.\n */\nvoid\ngraph_node( Heap *heap, VipsBuf *buf, HeapNode *root, gboolean fn )\n{\n\tGSList *back;\n\tchar txt[4];\n\tVipsBuf buf2 = VIPS_BUF_STATIC( txt );\n\n\t/* May be called before heap is built.\n\t */\n\tif( !heap )\n\t\treturn;\n\n\tback = NULL;\n\theap_clear( heap, FLAG_PRINT );\n\tlisp_node( &buf2, root, &back, fn, 0 );\n\theap_clear( heap, FLAG_PRINT );\n\tlisp_node( buf, root, &back, fn, 0 );\n\tIM_FREEF( g_slist_free, back );\n}\n\n/* As above, but start from a pelement.\n */\nvoid\ngraph_pelement( Heap *heap, VipsBuf *buf, PElement *root, gboolean fn )\n{\n\tGSList *back;\n\tchar txt[4];\n\tVipsBuf buf2 = VIPS_BUF_STATIC( txt );\n\n\t/* May be called before heap is built.\n\t */\n\tif( !heap )\n\t\treturn;\n\n\t/* We print twice ... the first time through we build the list of back\n\t * pointers so we can label the graph correctly.\n\t */\n\tback = NULL;\n\n\theap_clear( heap, FLAG_PRINT );\n\tlisp_pelement( &buf2, root, &back, fn, 0 );\n\n\theap_clear( heap, FLAG_PRINT );\n\tlisp_pelement( buf, root, &back, fn, 0 );\n\n\tIM_FREEF( g_slist_free, back );\n}\n\n/* As above, but start from an element.\n */\nvoid\ngraph_element( Heap *heap, VipsBuf *buf, Element *root, gboolean fn )\n{\n\tPElement base;\n\n\tPEPOINTE( &base, root );\n\tgraph_pelement( heap, buf, &base, fn );\n}\n\nvoid\ngraph_pointer( PElement *root )\n{\n\tchar txt[1000];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_pelement( reduce_context->heap, &buf, root, TRUE );\n\tprintf( \"%s\\n\", vips_buf_all( &buf ) );\n}\n\n/* Fwd ref.\n */\nstatic void shell_pelement( PElement *base );\n\n/* Print a graph shell-style.\n */\nstatic void\nshell_node( HeapNode *hn )\n{\n\tPElement p1, p2;\n\n\t/* Have we printed this node before?\n\t */\n\tif( hn->flgs & FLAG_PRINT ) {\n\t\tprintf( \"<*circular*>\" );\n\t\treturn;\n\t}\n\thn->flgs |= FLAG_PRINT;\n\n\tswitch( hn->type ) {\n\tcase TAG_CLASS:\n\tcase TAG_APPL:\n\tcase TAG_REFERENCE:\n\tcase TAG_SHARED:\n\tcase TAG_GEN:\n\t\tbreak;\n\t\t\n\tcase TAG_CONS:\n{\n\t\tgboolean string_mode;\n\n\t\tPEPOINTLEFT( hn, &p1 );\n\t\tstring_mode = PEISCHAR( &p1 );\n\n\t\tfor(;;) {\n\t\t\tif( string_mode )\n\t\t\t\tprintf( \"%c\", PEGETCHAR( &p1 ) );\n\t\t\telse\n\t\t\t\tshell_pelement( &p1 );\n\n\t\t\tPEPOINTRIGHT( hn, &p2 );\n\t\t\tif( PEISMANAGEDSTRING( &p2 ) ) {\n\t\t\t\tprintf( \"%s\\n\", \n\t\t\t\t\tPEGETMANAGEDSTRING( &p2 )->string );\n\t\t\t\tbreak;\n\n\t\t\t}\n\t\t\telse if( PEISELIST( &p2 ) ) \n\t\t\t\tbreak;\n\n\t\t\tif( !string_mode )\n\t\t\t\tprintf( \"\\n\" );\n\t\t\thn = PEGETVAL( &p2 );\n\t\t\tPEPOINTLEFT( hn, &p1 );\n\t\t\tif( string_mode && !PEISCHAR( &p1 ) )\n\t\t\t\tstring_mode = FALSE;\n\t\t}\n}\n\t\tbreak;\n\n\tcase TAG_DOUBLE:\n\t\tprintf( \"%g\", hn->body.num );\n\t\tbreak;\n\n\tcase TAG_COMPLEX:\n\t\tprintf( \"%g %g\", \n\t\t\tGETLEFT( hn )->body.num, GETRIGHT( hn )->body.num );\n\t\tbreak;\n\n\tcase TAG_FREE:\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n}\n\n/* Print a pelement shell-style.\n */\nstatic void\nshell_pelement( PElement *base )\n{\n\tswitch( PEGETTYPE( base ) ) {\n\t/* Only allow concrete base types.\n\t */\n\tcase ELEMENT_SYMREF:\n\tcase ELEMENT_COMPILEREF:\n\tcase ELEMENT_CONSTRUCTOR:\n\tcase ELEMENT_BINOP:\n\tcase ELEMENT_UNOP:\n\tcase ELEMENT_COMB:\n\tcase ELEMENT_TAG:\n\tcase ELEMENT_SYMBOL:\n\tcase ELEMENT_NOVAL:\n\t\tprintf( \"no-value\" );\n\t\tbreak;\n\n\tcase ELEMENT_NODE:\n\t\tshell_node( PEGETVAL( base ) );\n\t\tbreak;\n\n\tcase ELEMENT_CHAR:\n\t\tprintf( \"%c\", (int)PEGETCHAR( base ) );\n\t\tbreak;\n\n\tcase ELEMENT_BOOL:\n\t\tprintf( \"%s\", bool_to_char( PEGETBOOL( base ) ) );\n\t\tbreak;\n\n\tcase ELEMENT_ELIST:\n\t\tprintf( \"[ ]\" ); \n\t\tbreak;\n\n\tcase ELEMENT_MANAGED:\n\t\tif( PEISIMAGE( base ) )\n\t\t\tprintf( \"%s\", PEGETIMAGE( base )->filename );\n\t\telse if( PEISMANAGEDSTRING( base ) ) \n\t\t\tprintf( \"%s\", PEGETMANAGEDSTRING( base )->string );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n}\n\n/* Print a pelement shell-style.\n */\nvoid\ngraph_value( PElement *root )\n{\n\tReduce *rc = reduce_context;\n\n\tif( !reduce_pelement( rc, reduce_spine_strict, root ) ) {\n\t\tiwindow_alert( NULL, GTK_MESSAGE_ERROR );\n\t\treturn;\n\t}\n\n\theap_clear( reduce_context->heap, FLAG_PRINT );\n\tshell_pelement( root );\n\tprintf( \"\\n\" );\n}\n"
  },
  {
    "path": "src/heap.h",
    "content": "/* Heap management.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* Node type. Generally represent data objects.\n *\n * Don't use enum, as we want this to fit in 1 byte. \n */\ntypedef unsigned char NodeType;\n#define TAG_APPL (0)\t\t/* Application */\n#define TAG_CONS (1)\t\t/* List cons */\n#define TAG_FREE (2) \t\t/* On free list */\n#define TAG_DOUBLE (3)\t\t/* Constant double */\n#define TAG_COMPLEX (4)\t\t/* Constant complex */\n#define TAG_GEN (5)\t\t/* List generator */\n#define TAG_CLASS (8)\t\t/* Class object */\n#define TAG_SHARED (9)\t\t/* Root of a common sub-expression */\n#define TAG_REFERENCE (10)\t/* Reference to a common sub-expression */\n#define TAG_FILE (12)\t\t/* Generate list from file */\n\n/* Element types. Generally represent operators.\n */\ntypedef unsigned char EType;\n#define ELEMENT_NOVAL (0)\t/* No value */\n#define ELEMENT_NODE (1)\t/* Pointer to another node */\n#define ELEMENT_SYMBOL (2)\t/* Pointer to Symbol, reduces to value */\n#define ELEMENT_SYMREF (3)\t/* Pointer to Symbol, does not reduce */\n#define ELEMENT_COMPILEREF (4)\t/* Pointer to Compile, does not reduce */\n#define ELEMENT_CHAR (5)\t/* Boxed char type */\n#define ELEMENT_BOOL (6)\t/* Boxed bool type */\n#define ELEMENT_BINOP (7)\t/* Binary operator */\n#define ELEMENT_UNOP (8)\t/* Unary operator */\n#define ELEMENT_COMB (9)\t/* Combinator */\n#define ELEMENT_TAG (10)\t/* RHS of '.' operator */\n#define ELEMENT_MANAGED (11)\t/* A managed object */\n#define ELEMENT_CONSTRUCTOR (12)/* Class constructor */\n#define ELEMENT_ELIST (13)\t/* Empty list */\n\n/* Flags we attach to a node.\n */\ntypedef unsigned char NodeFlags;\n#define FLAG_SERIAL (31)\t/* Serial number mask  .. must be 1st */\n#define FLAG_PRINT (32)\t\t/* Marked (for decompile print) */\n#define FLAG_DEBUG (64)\t\t/* Marked (for debug traverse) */\n#define FLAG_MARK (128)\t\t/* Marked (for mark-sweep) */\n#define FLAG_ALL (255)\t\t/* All flags mask */\n\n/* Set the serial number without disturbing other stuff.\n */\n#define SETSERIAL( FLAGS, SERIAL ) { \\\n\t(FLAGS) = ((FLAGS) & (FLAG_SERIAL ^ FLAG_ALL)) | \\\n\t\t((SERIAL) & FLAG_SERIAL); \\\n}\n\n/* Combinators. Don't change the order of these! See reduce.c for an array\n * indexed with a CombinatorType.\n */\ntypedef enum combinator_type {\n\tCOMB_S = 0,\t\t/* S combinator */\n\tCOMB_SL,\t\t/* S-left combinator */\n\tCOMB_SR,\t\t/* S-right combinator */\n\tCOMB_I,\t\t\t/* Identity combinator */\n\tCOMB_K,\t\t\t/* K combinator */\n\tCOMB_GEN \t\t/* List generator combinator */\n} CombinatorType;\n\n/* An element ... a tag plus a pointer. Use one of these to hold a pointer\n * into a heap.\n */\ntypedef struct _Element {\n\tEType type;\n\tvoid *ele;\n} Element;\n\n/* A node on the heap. Should fit in 12 bytes on most machines.\n */\ntypedef struct _HeapNode {\n\t/* Elements: either a pair of pointers, or a double. Sensible on most\n\t * 32-bit systems, not so great on 64 bitters.\n\t */\n\tunion {\n\t\tstruct {\n\t\t\tvoid *left;\n\t\t\tvoid *right;\t\t\n\t\t} ptrs;\n\t\tdouble num;\n\t} body;\n\n\t/* Flags ... should fit in 4 bytes.\n\t */\n\tNodeType type;\t\t/* What this is */\n\tNodeFlags flgs;\t\t/* GC flags etc */\n\tEType ltype;\t\t/* Type of left element */\n\tEType rtype;\t\t/* Type of right element */\n} HeapNode;\n\n/* Put type/value pairs into nodes. Make sure we completely read before we \n * write.\n */\n#define PPUTLEFT(N,T,V) {\\\n\tEType t99 = (T);\\\n\tvoid *v99 = (void*)(V);\\\n\t\\\n\t(N)->ltype = t99;\\\n\t(N)->body.ptrs.left = v99;\\\n}\n#define PPUTRIGHT(N,T,V) {\\\n\tEType t99 = (T);\\\n\tvoid *v99 = (void*)(V);\\\n\t\\\n\t(N)->rtype = t99;\\\n\t(N)->body.ptrs.right = v99;\\\n}\n#define PPUT(N,Tl,Vl,Tr,Vr) {PPUTLEFT( N, Tl, Vl ); PPUTRIGHT( N, Tr, Vr );}\n\n/* Get value as a HeapNode pointer (most common case).\n */\n#define GETLEFT(N) ((HeapNode*)((N)->body.ptrs.left))\n#define GETRIGHT(N) ((HeapNode*)((N)->body.ptrs.right))\n#define GETLT(N) ((N)->ltype)\n#define GETRT(N) ((N)->rtype)\n\n/* A pointer to an element inside a HeapNode, or to an Element.\n */\ntypedef struct pelement {\n\tEType *type;\n\tvoid **ele;\n} PElement;\n\n/* Make a PElement point to a node.\n */\n#define PEPOINTLEFT(N,P) \\\n\t{(P)->type=&((N)->ltype);(P)->ele=&((N)->body.ptrs.left);}\n#define PEPOINTRIGHT(N,P) \\\n\t{(P)->type=&((N)->rtype);(P)->ele=&((N)->body.ptrs.right);}\n\n/* Make a PElement point to an element.\n */\n#define PEPOINTE(PE,E) \\\n\t{(PE)->type=&((E)->type);(PE)->ele=&((E)->ele);}\n\n/* Get from a PE.\n */\n#define PEGETTYPE(P) (*((P)->type))\n#define PEGETVAL(P) ((HeapNode*)(*((P)->ele)))\n#define PEGETE(P,E) ((E)->type = PEGETTYPE(P),(E)->ele = PEGETVAL(P))\n#define PEGETP(PE,T,V) ((T)=*((PE)->type),(V)=*((PE)->ele))\n\n/* Write to a PE. We are careful to eval all args before writing, in case we\n * are writing to one of the inputs.\n */\n#define PEPUTE(PE,E) {*((PE)->type)=(E)->type;*((PE)->ele)=(E)->ele;}\n#define PEPUTPE(PEto,PEfrom) {\\\n\tEType t99 = PEGETTYPE(PEfrom);\\\n\tvoid *v99 = PEGETVAL(PEfrom);\\\n\t\\\n\t*((PEto)->type) = t99;\\\n\t*((PEto)->ele) = v99;\\\n}\n#define PEPUTP(PE,T,V) {\\\n\tEType t99 = (T);\\\n\tvoid *v99 = GUINT_TO_POINTER(V);\\\n\t\\\n\t*((PE)->type) = t99;\\\n\t*((PE)->ele) = v99;\\\n}\n\n/* Write a PE to a node. Again, make sure we read both before we write, in\n * case we are writing an expression to ourselves.\n */\n#define PEPUTLEFT(N,PE) {\\\n\tEType t99 = PEGETTYPE(PE);\\\n\tvoid *v99 = PEGETVAL(PE);\\\n\t\\\n\t(N)->ltype = t99;\\\n\t(N)->body.ptrs.left = v99;\\\n}\n#define PEPUTRIGHT(N,PE) {\\\n\tEType t99 = PEGETTYPE(PE);\\\n\tvoid *v99 = PEGETVAL(PE);\\\n\t\\\n\t(N)->rtype = t99;\\\n\t(N)->body.ptrs.right = v99;\\\n}\n\n/* Predicates.\n */\n#define PEISBINOP(P) (PEGETTYPE(P) == ELEMENT_BINOP)\n#define PEISBOOL(P) (PEGETTYPE(P) == ELEMENT_BOOL)\n#define PEISCHAR(P) (PEGETTYPE(P) == ELEMENT_CHAR)\n#define PEISCLASS(P) (PEISNODE(P) && PEGETVAL(P)->type == TAG_CLASS)\n#define PEISCONSTRUCTOR(P) (PEGETTYPE(P) == ELEMENT_CONSTRUCTOR)\n#define PEISCOMB(P) (PEGETTYPE(P) == ELEMENT_COMB)\n#define PEISCOMPLEX(P) (PEISNODE(P) && PEGETVAL(P)->type == TAG_COMPLEX)\n#define PEISTAG(P) (PEGETTYPE(P) == ELEMENT_TAG)\n#define PEISMANAGED(P) (PEGETTYPE(P) == ELEMENT_MANAGED)\n#define PEISMANAGEDGOBJECT(P) (PEISMANAGED(P) && \\\n\tIS_MANAGEDGOBJECT( PEGETVAL(P) ))\n#define PEISMANAGEDSTRING(P) (PEISMANAGED(P) && \\\n\tIS_MANAGEDSTRING(PEGETVAL(P)))\n#define PEISIMAGE(P) (PEISMANAGED(P) && IS_IMAGEINFO( PEGETVAL(P) ))\n#define PEISVIPSOBJECT(P) \\\n\t(PEISMANAGEDGOBJECT(P) && VIPS_IS_OBJECT( PEGETMANAGEDGOBJECT(P) )) \n#define PEISFILE(P) (PEISMANAGED(P) && IS_MANAGEDFILE(PEGETVAL(P)))\n#define PEISELIST(P) (PEGETTYPE(P) == ELEMENT_ELIST)\n#define PEISFLIST(P) ((PEISNODE(P) && PEGETVAL(P)->type == TAG_CONS) || \\\n\tPEISMANAGEDSTRING(P))\n#define PEISLIST(P) (PEISELIST(P) || PEISFLIST(P))\n#define PEISNOVAL(P) (PEGETTYPE(P) == ELEMENT_NOVAL)\n#define PEISNUM(P) (PEISREAL(P) || PEISCOMPLEX(P))\n#define PEISNODE(P) (PEGETTYPE(P) == ELEMENT_NODE)\n#define PEISREAL(P) (PEISNODE(P) && PEGETVAL(P)->type == TAG_DOUBLE)\n#define PEISSYMBOL(P) (PEGETTYPE(P) == ELEMENT_SYMBOL)\n#define PEISSYMREF(P) (PEGETTYPE(P) == ELEMENT_SYMREF)\n#define PEISCOMPILEREF(P) (PEGETTYPE(P) == ELEMENT_COMPILEREF)\n#define PEISUNOP(P) (PEGETTYPE(P) == ELEMENT_UNOP)\n\n/* Extract bits of primitive compound types.\n */\n#define PEGETSYMBOL(P) ((Symbol*)PEGETVAL(P))\n#define PEGETSYMREF(P) ((Symbol*)PEGETVAL(P))\n#define PEGETCOMPILE(P) ((Compile*)(PEGETVAL(P)))\n#define PEGETBINOP(P) ((BinOp)PEGETVAL(P))\n#define PEGETUNOP(P) ((UnOp)PEGETVAL(P))\n#define PEGETCOMB(P) ((CombinatorType)PEGETVAL(P))\n#define PEGETTAG(P) ((char*)PEGETVAL(P))\n#define PEGETREAL(P) (PEGETVAL(P)->body.num)\n#define PEGETBOOL(P) ((gboolean)GPOINTER_TO_UINT(PEGETVAL(P)))\n#define PEGETCHAR(P) ((unsigned char)(GPOINTER_TO_UINT(PEGETVAL(P))))\n#define PEGETIMAGE(P) (((Imageinfo*)PEGETVAL(P))->im)\n#define PEGETII(P) ((Imageinfo*)PEGETVAL(P))\n#define PEGETFILE(P) ((Managedfile*)PEGETVAL(P))\n#define PEGETMANAGED(P) ((Managed*)PEGETVAL(P))\n#define PEGETMANAGEDSTRING(P) ((Managedstring*)PEGETVAL(P))\n#define PEGETMANAGEDGOBJECT(P) (((Managedgobject*)PEGETVAL(P))->object)\n#define PEGETVIPSOBJECT(P) \\\n\t\t((VipsObject*)(((Managedgobject*)PEGETVAL(P))->object))\n\n#define PEGETHD(P1,P2) PEPOINTLEFT(PEGETVAL(P2), P1)\n#define PEGETTL(P1,P2) PEPOINTRIGHT(PEGETVAL(P2), P1)\n\n#define PEGETREALPART(P) (GETLEFT(PEGETVAL(P))->body.num)\n#define PEGETIMAGPART(P) (GETRIGHT(PEGETVAL(P))->body.num)\n\n#define PEGETCLASSCOMPILE(P) (COMPILE(GETLEFT(PEGETVAL(P))))\n#define PEGETCLASSSECRET(P1,P2) PEPOINTLEFT(GETRIGHT(PEGETVAL(P2)),P1)\n#define PEGETCLASSMEMBER(P1,P2) PEPOINTRIGHT(GETRIGHT(PEGETVAL(P2)),P1)\n\n/* A block on the heap.\n */\nstruct _HeapBlock {\n\tHeap *heap;\t\t/* Heap we are part of */\n\tHeapBlock *next;\t/* Next block in chain */\n\tHeapNode *node;\t\t/* Nodes on this block */\n\tint sz;\t\t\t/* Number of nodes in this block */\n};\n\n/* Function to get max heap size.\n */\ntypedef int (*heap_max_fn)( Heap * );\n\n#define TYPE_HEAP (heap_get_type())\n#define HEAP( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_HEAP, Heap ))\n#define HEAP_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_HEAP, HeapClass))\n#define IS_HEAP( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_HEAP ))\n#define IS_HEAP_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_HEAP ))\n#define HEAP_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_HEAP, HeapClass ))\n\nstruct _Heap {\n\tiObject parent_object;\n\n\tCompile *compile;\t/* If non-null, assoc. compile */\n\n\theap_max_fn max_fn;\t/* Max nodes in this heap */\n\tint mxb;\t\t/* Max blocks until next check */\n\tint rsz;\t\t/* Nodes to allocate in each extra block */\n\tint nb;\t\t\t/* Number of blocks attached */\n\tHeapBlock *hb;\t\t/* List of current blocks */\n\tHeapNode *free;\t\t/* Start of free-node chain (sweep to here) */\n\n\tint ncells;\t\t/* Cells allocated */\n\tint nfree;\t\t/* Cells free */\n\tint serial;\t\t/* Last serial number we used */\n\tgboolean filled;\t/* Set on heap full */\n\n\tGHashTable *emark;\t/* Set of elements to mark on GC */\n\tGHashTable *rmark;\t/* Set of Reduce to mark on GC */\n\tGHashTable *mtable;\t/* Managed associated with this heap */\n\n        guint gc_tid;\t\t/* id of gc delay timer */\n\n\t/* Set this to force unreffed objects out immediately. Handy for leak \n\t * testing.\n\t */\n\tgboolean flush;\n};\n\ntypedef struct _HeapClass {\n\tiObjectClass parent_class;\n\n\t/* My methods.\n\t */\n} HeapClass;\n\n/* Get a node from the free-list. No check for free-list exhausted! Set sym\n * pointer in node to heap sym pointer.\n */\n#ifdef DEBUG_HEAP\n#define EXTRACTNODE( H, A ) \\\n\t(heap_sanity( H ), (A) = (H)->free, (H)->free = GETLEFT( A ), 0)\n#else /*!DEBUG_HEAP*/\n#define EXTRACTNODE( H, A ) \\\n\t((A) = (H)->free, (H)->free = GETLEFT( A ), 0)\n#endif /*DEBUG_HEAP*/\n\n/* Allocate a new node from heap H, pop the pointer into A, return non-zero if\n * alloc failed. Node is uninitialised!\n */\n#define NEWNODE( H, A ) ( \\\n\t(H)->free ? \\\n\t\tEXTRACTNODE( H, A ): \\\n\t\t(((A) = heap_getmem( H )) ? 0 : -1) \\\n\t)\n\ntypedef void *(*heap_safe_pointer_fn)( Heap *heap, PElement *, \n\tvoid *, void *, void *, void * );\nvoid *heap_safe_pointer( Heap *heap, heap_safe_pointer_fn fn, \n\tvoid *a, void *b, void *c, void *d );\n\ntypedef void *(*heap_map_fn)( HeapNode *, void *, void *);\nvoid *heap_map( HeapNode *hn, heap_map_fn fn, void *a, void *b );\n\nint heap_sanity( Heap *heap );\n\nvoid heap_check_all_destroyed( void );\nvoid heap_destroy( Heap *heap );\nGType heap_get_type( void );\nHeap *heap_new( Compile *compile, heap_max_fn max_fn, int stsz, int rsz );\nHeapNode *heap_getmem( Heap *heap );\ngboolean heap_gc( Heap *heap );\nvoid heap_gc_request( Heap *heap );\nvoid heap_register_element( Heap *heap, Element *root );\nvoid heap_unregister_element( Heap *heap, Element *root );\nvoid heap_register_reduce( Heap *heap, Reduce *rc );\nvoid heap_unregister_reduce( Heap *heap, Reduce *rc );\nvoid heap_set( Heap *heap, NodeFlags setmask );\nvoid heap_clear( Heap *heap, NodeFlags clearmask );\nint heap_serial_new( Heap *heap );\n\ngboolean heap_bool_new( Heap *heap, gboolean val, PElement *out );\ngboolean heap_real_new( Heap *heap, double in, PElement *out );\ngboolean heap_element_new( Heap *heap, Element *e, PElement *out );\ngboolean heap_complex_element_new( Heap *heap, \n\tPElement *rp, PElement *ip, PElement *out );\ngboolean heap_complex_new( Heap *heap, double rp, double ip, PElement *out );\ngboolean heap_realvec_new( Heap *heap, int n, double *vec, PElement *out );\ngboolean heap_intvec_new( Heap *heap, int n, int *vec, PElement *out );\nvoid heap_list_init( PElement *list );\ngboolean heap_list_add( Heap *heap, PElement *list, PElement *data );\ngboolean heap_list_next( PElement *list );\ngboolean heap_list_cat( Reduce *rc, PElement *a, PElement *b, PElement *out );\nvoid heap_appl_init( PElement *base, PElement *func );\ngboolean heap_appl_add( Heap *heap, PElement *base, PElement *parm );\ngboolean heap_matrix_new( Heap *heap, \n\tint xsize, int ysize, double *vec, PElement *out );\ngboolean heap_string_new( Heap *heap, const char *str, PElement *out );\ngboolean heap_managedstring_new( Heap *heap, const char *str, PElement *out );\ngboolean heap_lstring_new( Heap *heap, GSList *labels, PElement *out );\ngboolean heap_file_new( Heap *heap, const char *filename, PElement *out );\n\ngboolean heap_error_typecheck( PElement *e, \n\tconst char *name, const char *type );\ntypedef void *(*heap_map_list_fn)( PElement *, void *, void * );\nvoid *heap_map_list( PElement *base, heap_map_list_fn fn, void *a, void *b );\ntypedef void *(*heap_map_dict_fn)( const char *, PElement *, void *a, void *b );\nvoid *heap_map_dict( PElement *base, heap_map_dict_fn fn, void *a, void *b );\n\ngboolean heap_get_list( PElement *list );\ngboolean heap_get_list_next( PElement *list, PElement *data );\ngboolean heap_get_string( PElement *base, char *buf, int n );\ngboolean heap_get_lstring( PElement *base, GSList **labels );\ngboolean heap_get_bool( PElement *base, gboolean *out );\ngboolean heap_get_real( PElement *base, double *out );\ngboolean heap_get_class( PElement *base, PElement *out );\ngboolean heap_get_image( PElement *base, Imageinfo **out );\nint heap_get_realvec( PElement *base, double *buf, int n );\nint heap_get_imagevec( PElement *base, Imageinfo **buf, int n );\ngboolean heap_get_matrix_size( PElement *base, int *xsize, int *ysize );\ngboolean heap_get_matrix( PElement *base, \n\tdouble *buf, int n, int *xsize, int *ysize );\n\ngboolean heap_is_elist( PElement *base, gboolean *out );\ngboolean heap_is_list( PElement *base, gboolean *out );\ngboolean heap_is_string( PElement *base, gboolean *out );\ngboolean heap_is_realvec( PElement *base, gboolean *out );\ngboolean heap_is_imagevec( PElement *base, gboolean *out );\ngboolean heap_is_matrix( PElement *base, gboolean *out );\ngboolean heap_is_class( PElement *base, gboolean *out );\ngboolean heap_is_instanceof_exact( const char *name, PElement *klass, \n\tgboolean *out);\ngboolean heap_is_instanceof( const char *name, PElement *klass, gboolean *out );\n\nint heap_list_length( PElement *base );\nint heap_list_length_max( PElement *base, int max_length );\ngboolean heap_list_index( PElement *base, int n, PElement *out );\ngboolean heap_reduce_strict( PElement *base );\n\ngboolean heap_copy( Heap *heap, Compile *compile, PElement *out );\n\ngboolean heap_ip_to_gvalue( PElement *in, GValue *out );\ngboolean heap_gvalue_to_ip( GValue *in, PElement *out );\n\nvoid graph_node( Heap *heap, VipsBuf *buf, HeapNode *root, gboolean fn );\nvoid graph_pelement( Heap *heap, VipsBuf *buf, PElement *root, gboolean fn );\nvoid graph_element( Heap *heap, VipsBuf *buf, Element *root, gboolean fn );\nvoid graph_pointer( PElement *root );\n\n/* Reduce and print, csh-style output.\n */\nvoid graph_value( PElement *root );\n"
  },
  {
    "path": "src/heapmodel.c",
    "content": "/* base class for models of heap classes\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ModelClass *parent_class = NULL;\n\nvoid *\nheapmodel_new_heap( Heapmodel *heapmodel, PElement *root )\n{\n\tHeapmodelClass *heapmodel_class = HEAPMODEL_GET_CLASS( heapmodel );\n\n\tif( heapmodel_class->new_heap ) {\n\t\tvoid *res;\n\t\t\n\t\tres = heapmodel_class->new_heap( heapmodel, root );\n\n\t\treturn( res );\n\t}\n\n\treturn( NULL );\n}\n\nvoid *\nheapmodel_update_model( Heapmodel *heapmodel )\n{\n\tHeapmodelClass *heapmodel_class = HEAPMODEL_GET_CLASS( heapmodel );\n\n#ifdef DEBUG\n\tprintf( \"heapmodel_update_model: %s \",\n\t\tG_OBJECT_TYPE_NAME( heapmodel ) );\n\trow_name_print( heapmodel->row );\n\tprintf( \" modified = %d\\n\", heapmodel->modified );\n#endif /*DEBUG*/\n\n\tif( heapmodel_class->update_model && !heapmodel->modified ) {\n\t\tvoid *res;\n\n\t\tres = heapmodel_class->update_model( heapmodel );\n\n\t\treturn( res );\n\t}\n\n\treturn( NULL );\n}\n\nvoid *\nheapmodel_update_heap( Heapmodel *heapmodel )\n{\n\tHeapmodelClass *heapmodel_class = HEAPMODEL_GET_CLASS( heapmodel );\n\n\tif( heapmodel_class->update_heap && heapmodel->modified ) {\n\t\tvoid *res;\n\n\t\tres = heapmodel_class->update_heap( heapmodel );\n\n\t\treturn( res );\n\t}\n\n\treturn( NULL );\n}\n\nvoid *\nheapmodel_clear_edited( Heapmodel *heapmodel )\n{\n\tHeapmodelClass *heapmodel_class = HEAPMODEL_GET_CLASS( heapmodel );\n\n\tif( heapmodel_class->clear_edited )\n\t\treturn( heapmodel_class->clear_edited( heapmodel ) );\n\n\treturn( NULL );\n}\n\nstatic Rhs *\nheapmodel_get_rhs( Heapmodel *heapmodel )\n{\n\tiContainer *p;\n\n\t/* Search for the enclosing RHS ... may not be one if (eg.) this is a\n\t * top-level row.\n\t */\n\tfor( p = ICONTAINER( heapmodel )->parent; p; p = p->parent )\n\t\tif( IS_RHS( p ) )\n\t\t\treturn( RHS( p ) );\n\n\treturn( NULL );\n}\n\nstatic Row *\nheapmodel_get_row( Heapmodel *heapmodel )\n{\n\tRhs *rhs;\n\n\tif( IS_RHS( heapmodel ) )\n\t\treturn( ROW( ICONTAINER( heapmodel )->parent ) );\n\telse if( (rhs = heapmodel_get_rhs( heapmodel )) )\n\t\treturn( HEAPMODEL( rhs )->row );\n\telse\n\t\treturn( NULL );\n}\n\nstatic void\nheapmodel_parent_add( iContainer *child )\n{\n\tHeapmodel *heapmodel = HEAPMODEL( child );\n\n\tg_assert( IS_HEAPMODEL( child->parent ) || \n\t\tIS_FILEMODEL( child->parent ) ); \n\n\tICONTAINER_CLASS( parent_class )->parent_add( child );\n\n\t/* Update our context.\n\t */\n\theapmodel->rhs = heapmodel_get_rhs( heapmodel );\n\theapmodel->row = heapmodel_get_row( heapmodel );\n}\n\nstatic void *\nheapmodel_real_new_heap( Heapmodel *heapmodel, PElement *root )\n{\n\tiobject_changed( IOBJECT( heapmodel ) );\n\n\treturn( NULL );\n}\n\nstatic void *\nheapmodel_real_update_model( Heapmodel *heapmodel )\n{\n\tiobject_changed( IOBJECT( heapmodel ) );\n\n\treturn( NULL );\n}\n\nstatic void *\nheapmodel_real_update_heap( Heapmodel *heapmodel )\n{\n\tg_assert( heapmodel->modified );\n\n\theapmodel_set_modified( heapmodel, FALSE );\n\n\treturn( NULL );\n}\n\nstatic void *\nheapmodel_real_clear_edited( Heapmodel *heapmodel )\n{\n\treturn( NULL );\n}\n\nstatic void\nheapmodel_class_init( HeapmodelClass *class )\n{\n\tHeapmodelClass *heapmodel_class = (HeapmodelClass *) class;\n\tiContainerClass *icontainer_class = (iContainerClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Init methods.\n\t */\n\ticontainer_class->parent_add = heapmodel_parent_add;\n\n\theapmodel_class->new_heap = heapmodel_real_new_heap;\n\theapmodel_class->update_heap = heapmodel_real_update_heap;\n\theapmodel_class->update_model = heapmodel_real_update_model;\n\theapmodel_class->clear_edited = heapmodel_real_clear_edited;\n}\n\nstatic void\nheapmodel_init( Heapmodel *heapmodel )\n{\n        heapmodel->row = NULL;\n        heapmodel->rhs = NULL;\n\n\theapmodel->modified = FALSE;\n}\n\nGType\nheapmodel_get_type( void )\n{\n\tstatic GType heapmodel_type = 0;\n\n\tif( !heapmodel_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( HeapmodelClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) heapmodel_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Heapmodel ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) heapmodel_init,\n\t\t};\n\n\t\theapmodel_type = g_type_register_static( TYPE_MODEL, \n\t\t\t\"Heapmodel\", &info, 0 );\n\t}\n\n\treturn( heapmodel_type );\n}\n\nvoid\nheapmodel_set_modified( Heapmodel *heapmodel, gboolean modified )\n{\n\tif( heapmodel->modified != modified ) {\n#ifdef DEBUG\n{\n\t\tHeapmodelClass *heapmodel_class = \n\t\t\tHEAPMODEL_GET_CLASS( heapmodel );\n\n\t\tprintf( \"heapmodel_set_modified: %s::\", \n\t\t\tG_OBJECT_CLASS_NAME( heapmodel_class ) );\n\t\trow_name_print( heapmodel->row );\n\t\tprintf( \" %s\\n\", bool_to_char( modified ) );\n}\n#endif /*DEBUG*/\n\n\t\theapmodel->modified = modified;\n\t\tiobject_changed( IOBJECT( heapmodel ) );\n\t}\n}\n\n/* Generate a descriptive name for a heapmodel. Used for captions.\n */\ngboolean\nheapmodel_name( Heapmodel *heapmodel, VipsBuf *buf )\n{\n\tRow *row = heapmodel->row;\n\tExpr *expr;\n\tSymbol *sym;\n\tToolitem *toolitem;\n\n\tif( !row || !(expr = row->expr) || !PEISCLASS( &expr->root ) ) \n\t\treturn( FALSE );\n\tsym = PEGETCLASSCOMPILE( &expr->root )->sym;\n\n\t/* If this is an action member we should be able to look up\n\t * it's sym and get a descriptive label.\n\t */\n\tif( (toolitem = toolitem_lookup( row->ws->kitg, sym )) )\n\t\tvips_buf_appends( buf, toolitem->name );\n\telse \n\t\tsymbol_qualified_name_relative( row->ws->sym, sym, buf );\n\n\treturn( TRUE );\n}\n\n/* Print the value member to a buf.\n */\ngboolean\nheapmodel_value( Heapmodel *heapmodel, VipsBuf *buf )\n{\n\tExpr *expr;\n\tPElement value;\n\n\tif( !heapmodel->row ||\n\t\t!(expr = heapmodel->row->expr) ||\n\t\texpr->err || \n\t\texpr->sym->dirty ||\n\t\t!class_get_member( &expr->root, MEMBER_VALUE, NULL, &value ) ) \n\t\treturn( FALSE );\n\n\titext_value( reduce_context, buf, &value );\n\n\treturn( TRUE );\n}\n\n"
  },
  {
    "path": "src/heapmodel.h",
    "content": "/* like a model, but something that represents a part of the heap (eg.\n * toggle/slider/text etc.)\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_HEAPMODEL (heapmodel_get_type())\n#define HEAPMODEL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_HEAPMODEL, Heapmodel ))\n#define HEAPMODEL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_HEAPMODEL, HeapmodelClass))\n#define IS_HEAPMODEL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_HEAPMODEL ))\n#define IS_HEAPMODEL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_HEAPMODEL ))\n#define HEAPMODEL_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_HEAPMODEL, HeapmodelClass ))\n\nstruct _Heapmodel {\n\tModel parent_class;\n\n\t/* Context.\n\t */\n\tRow *row;\t\t/* Enclosing row */\n\tRhs *rhs;\t\t/* Enclosing rhs */\n\n\t/* Set if model has changes which have not yet been applied to the\n\t * heap ... update_model() blocks, update_heap() clears.\n\t */\n\tgboolean modified;\n};\n\ntypedef struct _HeapmodelClass {\n\tModelClass parent_class;\n\n\t/* Building heaps from models, building models from heaps.\n\n\t\tnew_heap\tthe heap has changed ... recurse down adding,\n\t\t\t\tupdating (with a recursive new_heap()) and \n\t\t\t\tremoving children\n\n\t\tupdate_model\tread the heap into the model ... eg. update\n\t\t\t\ttext representation\n\n\t\tupdate_heap\tif the heapmodel has any unapplied user edits,\n\t\t\t\tuse them to update the heap ... update the\n\t\t\t\theap area pointed to by the last\n\t\t\t\tupdate_model\n\n\t\tclear_edited\tset back to default values\n\n\t */\n\tvoid *(*new_heap)( Heapmodel *, PElement * );\t\n\tvoid *(*update_model)( Heapmodel * );\n\tvoid *(*update_heap)( Heapmodel * );\n\tvoid *(*clear_edited)( Heapmodel * );\n} HeapmodelClass;\n\nvoid *heapmodel_new_heap( Heapmodel *heapmodel, PElement *root );\nvoid *heapmodel_update_model( Heapmodel *heapmodel );\nvoid *heapmodel_update_heap( Heapmodel *heapmodel );\nvoid *heapmodel_clear_edited( Heapmodel *heapmodel );\n\nGType heapmodel_get_type( void );\n\nvoid heapmodel_set_modified( Heapmodel *heapmodel, gboolean modified );\ngboolean heapmodel_name( Heapmodel *heapmodel, VipsBuf *buf );\ngboolean heapmodel_value( Heapmodel *heapmodel, VipsBuf *buf );\n"
  },
  {
    "path": "src/helpindex.h",
    "content": "{ \"sec:object\", \"nipguidese34.html#nip_label_sec:object\" },\n{ \"sec:menu-colour\", \"nipguidese14.html#nip_label_sec:menu-colour\" },\n{ \"tb:colour\", \"nipguidese14.html#nip_label_tb:colour\" },\n{ \"sec:pattern\", \"nipguidese30.html#nip_label_sec:pattern\" },\n{ \"sec:nerdtour\", \"nipguidese3.html#nip_label_sec:nerdtour\" },\n{ \"fg:Fred\", \"nipguidese3.html#nip_label_fg:Fred\" },\n{ \"fg:mainFred\", \"nipguidese3.html#nip_label_fg:mainFred\" },\n{ \"fg:slideFred\", \"nipguidese3.html#nip_label_fg:slideFred\" },\n{ \"fg:Jim\", \"nipguidese3.html#nip_label_fg:Jim\" },\n{ \"fg:twomoreregions\", \"nipguidese3.html#nip_label_fg:twomoreregions\" },\n{ \"fg:myjoin\", \"nipguidese3.html#nip_label_fg:myjoin\" },\n{ \"sec:menu-object\", \"nipguidese20.html#nip_label_sec:menu-object\" },\n{ \"sec:operators\", \"nipguidese27.html#nip_label_sec:operators\" },\n{ \"tb:precedence\", \"nipguidese27.html#nip_label_tb:precedence\" },\n{ \"sec:listsyntax\", \"nipguidese27.html#nip_label_sec:listsyntax\" },\n{ \"sec:func\", \"nipguidese27.html#nip_label_sec:func\" },\n{ \"sec:vidpref\", \"nipguidese4.html#nip_label_sec:vidpref\" },\n{ \"fg:vidpref\", \"nipguidese4.html#nip_label_fg:vidpref\" },\n{ \"sec:imcap\", \"nipguidese4.html#nip_label_sec:imcap\" },\n{ \"sec:grey\", \"nipguidese4.html#nip_label_sec:grey\" },\n{ \"sec:linuxgrey\", \"nipguidese4.html#nip_label_sec:linuxgrey\" },\n{ \"sec:wingrey\", \"nipguidese4.html#nip_label_sec:wingrey\" },\n{ \"sec:lists\", \"nipguidese28.html#nip_label_sec:lists\" },\n{ \"tb:list\", \"nipguidese28.html#nip_label_tb:list\" },\n{ \"sec:cmdline\", \"nipguidese13.html#nip_label_sec:cmdline\" },\n{ \"sec:menu-histogram\", \"nipguidese16.html#nip_label_sec:menu-histogram\" },\n{ \"sec:menu-matrix\", \"nipguidese19.html#nip_label_sec:menu-matrix\" },\n{ \"sec:quicktour\", \"nipguidese1.html#nip_label_sec:quicktour\" },\n{ \"fg:loadedimage\", \"nipguidese1.html#nip_label_fg:loadedimage\" },\n{ \"fg:imageview\", \"nipguidese1.html#nip_label_fg:imageview\" },\n{ \"tb:shortcuts\", \"nipguidese1.html#nip_label_tb:shortcuts\" },\n{ \"fg:imageviewregion\", \"nipguidese1.html#nip_label_fg:imageviewregion\" },\n{ \"fg:main2regions\", \"nipguidese1.html#nip_label_fg:main2regions\" },\n{ \"fg:rotate\", \"nipguidese1.html#nip_label_fg:rotate\" },\n{ \"fg:join\", \"nipguidese1.html#nip_label_fg:join\" },\n{ \"fg:browse\", \"nipguidese1.html#nip_label_fg:browse\" },\n{ \"tb:builtin\", \"nipguidese24.html#nip_label_tb:builtin\" },\n{ \"tb:toolkits\", \"nipguidese31.html#nip_label_tb:toolkits\" },\n{ \"sec:menu-filter\", \"nipguidese15.html#nip_label_sec:menu-filter\" },\n{ \"sec:progwin\", \"nipguidese12.html#nip_label_sec:progwin\" },\n{ \"sec:trace\", \"nipguidese12.html#nip_label_sec:trace\" },\n{ \"sec:menu-tasks\", \"nipguidese21.html#nip_label_sec:menu-tasks\" },\n{ \"sec:menu-capture\", \"nipguidese21.html#nip_label_sec:menu-capture\" },\n{ \"sec:menu-mosaic\", \"nipguidese21.html#nip_label_sec:menu-mosaic\" },\n{ \"sec:menu-picture-frame\", \"nipguidese21.html#nip_label_sec:menu-picture-frame\" },\n{ \"sec:menu-print\", \"nipguidese21.html#nip_label_sec:menu-print\" },\n{ \"sec:bowser\", \"nipguidese33.html#nip_label_sec:bowser\" },\n{ \"sec:tools\", \"nipguidese33.html#nip_label_sec:tools\" },\n{ \"fg:toolkit\", \"nipguidese33.html#nip_label_fg:toolkit\" },\n{ \"fg:toolkit2\", \"nipguidese33.html#nip_label_fg:toolkit2\" },\n{ \"fg:toolkit3\", \"nipguidese33.html#nip_label_fg:toolkit3\" },\n{ \"sec:workspaces\", \"nipguidese33.html#nip_label_sec:workspaces\" },\n{ \"fg:row2\", \"nipguidese33.html#nip_label_fg:row2\" },\n{ \"tb:classes\", \"nipguidese33.html#nip_label_tb:classes\" },\n{ \"sec:Image\", \"nipguidese33.html#nip_label_sec:Image\" },\n{ \"sec:colour\", \"nipguidese33.html#nip_label_sec:colour\" },\n{ \"sec:loadsave\", \"nipguidese10.html#nip_label_sec:loadsave\" },\n{ \"fg:open\", \"nipguidese10.html#nip_label_fg:open\" },\n{ \"fg:save\", \"nipguidese10.html#nip_label_fg:save\" },\n{ \"sec:view\", \"nipguidese9.html#nip_label_sec:view\" },\n{ \"fg:scr3\", \"nipguidese9.html#nip_label_fg:scr3\" },\n{ \"fg:scr4\", \"nipguidese9.html#nip_label_fg:scr4\" },\n{ \"sec:paintbox\", \"nipguidese9.html#nip_label_sec:paintbox\" },\n{ \"fg:paint\", \"nipguidese9.html#nip_label_fg:paint\" },\n{ \"sec:program\", \"nipguidech6.html#nip_label_sec:program\" },\n{ \"sec:lazy\", \"nipguidese29.html#nip_label_sec:lazy\" },\n{ \"sec:optimise\", \"nipguidese35.html#nip_label_sec:optimise\" },\n{ \"sec:menus\", \"nipguidech5.html#nip_label_sec:menus\" },\n{ \"sec:ipwindow\", \"nipguidese11.html#nip_label_sec:ipwindow\" },\n{ \"fg:startup\", \"nipguidese11.html#nip_label_fg:startup\" },\n{ \"sec:column\", \"nipguidese11.html#nip_label_sec:column\" },\n{ \"sec:row\", \"nipguidese11.html#nip_label_sec:row\" },\n{ \"fg:row\", \"nipguidese11.html#nip_label_fg:row\" },\n{ \"sec:apply\", \"nipguidese11.html#nip_label_sec:apply\" },\n{ \"sec:batch\", \"nipguidese11.html#nip_label_sec:batch\" },\n{ \"sec:error\", \"nipguidese11.html#nip_label_sec:error\" },\n{ \"sec:diaref\", \"nipguidese11.html#nip_label_sec:diaref\" },\n{ \"sec:menu-math\", \"nipguidese18.html#nip_label_sec:menu-math\" },\n{ \"sec:ir\", \"nipguidech3.html#nip_label_sec:ir\" },\n{ \"sec:mosaicing\", \"nipguidese5.html#nip_label_sec:mosaicing\" },\n{ \"sec:pieces\", \"nipguidese5.html#nip_label_sec:pieces\" },\n{ \"sec:tutorial\", \"nipguidech2.html#nip_label_sec:tutorial\" },\n{ \"sec:reference\", \"nipguidech4.html#nip_label_sec:reference\" },\n{ \"sec:class\", \"nipguidese32.html#nip_label_sec:class\" },\n{ \"sec:inheritance\", \"nipguidese32.html#nip_label_sec:inheritance\" },\n{ \"sec:balance\", \"nipguidese6.html#nip_label_sec:balance\" },\n{ \"sec:irtut\", \"nipguidese2.html#nip_label_sec:irtut\" },\n{ \"fg:loadsamples\", \"nipguidese2.html#nip_label_fg:loadsamples\" },\n{ \"fg:readyjoin\", \"nipguidese2.html#nip_label_fg:readyjoin\" },\n{ \"fg:joined\", \"nipguidese2.html#nip_label_fg:joined\" },\n{ \"sec:config\", \"nipguideap1.html#nip_label_sec:config\" },\n{ \"sec:menu-image\", \"nipguidese17.html#nip_label_sec:menu-image\" },\n{ \"sec:callvips\", \"nipguidese36.html#nip_label_sec:callvips\" },\n"
  },
  {
    "path": "src/iarrow.c",
    "content": "/* an ip arrow class object in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic void\niarrow_finalize( GObject *gobject )\n{\n\tiArrow *iarrow;\n\n#ifdef DEBUG\n\tprintf( \"iarrow_finalize\\n\" );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_IARROW( gobject ) );\n\n\tiarrow = IARROW( gobject );\n\n\t/* My instance finalize stuff.\n\t */\n\tiregion_instance_destroy( &iarrow->instance );\n\tvips_buf_destroy( &iarrow->caption_buffer );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void *\niarrow_generate_caption_sub( iImage *iimage, iArrow *iarrow, gboolean *first )\n{\n\tWorkspace *ws = HEAPMODEL( iarrow )->row->ws;\n\tRow *row = HEAPMODEL( iimage )->row;\n\n\t/* Suppress this name in the caption if it's a superclass. If this\n\t * thing is on a super, it's on the subclass too ... not helpful to\n\t * have it twice.\n\t */\n\tif( !is_super( row->sym ) ) {\n\t\tif( *first )\n\t\t\t*first = FALSE;\n\t\telse \n\t\t\tvips_buf_appends( &iarrow->caption_buffer, \", \" );\n\n\t\trow_qualified_name_relative( ws->sym, row,\n\t\t\t&iarrow->caption_buffer );\n\t}\n\n\treturn( NULL );\n}\n\nstatic const char *\niarrow_generate_caption( iObject *iobject )\n{\n\tstatic const char *names[] = {\n\t\tCLASS_HGUIDE,\n\t\tCLASS_VGUIDE,\n\t\tCLASS_MARK,\n\t\tCLASS_ARROW,\n\t\tNULL\n\t};\n\n\tiArrow *iarrow = IARROW( iobject );\n\tVipsBuf *buf = &iarrow->caption_buffer;\n\tconst int nimages = g_slist_length( CLASSMODEL( iarrow )->iimages );\n\tExpr *expr;\n\tgboolean result;\n\tgboolean first;\n\tint i;\n\n\tif( !HEAPMODEL( iarrow )->row ||\n\t\t!(expr = HEAPMODEL( iarrow )->row->expr) || \n\t\t!heap_is_class( &expr->root, &result ) || \n\t\t!result )\n\t\treturn( _( \"No image\" ) );\n\n\tvips_buf_rewind( buf );\n\theapmodel_name( HEAPMODEL( iarrow ), buf );\n\tvips_buf_appendf( buf, \" \" );\n\n\t/* Used in (eg.) \"Mark at (10, 10) on [A1, A2]\"\n\t */\n\tvips_buf_appendf( buf, _( \"on\" ) );\n\tvips_buf_appendf( buf, \" \" );\n\tif( nimages > 1 )\n\t\tvips_buf_appendf( buf, \"[\" );\n\tfirst = TRUE;\n\tslist_map2( CLASSMODEL( iarrow )->iimages,\n\t\t(SListMap2Fn) iarrow_generate_caption_sub, iarrow, &first );\n\tif( nimages > 1 )\n\t\tvips_buf_appendf( buf, \"]\" );\n\tvips_buf_appendf( buf, \" \" );\n\n\tfor( i = 0; names[i]; i++ ) {\n\t\tif( !heap_is_instanceof( names[i], &expr->root, &result ) )\n\t\t\tbreak;\n\n\t\tif( result ) {\n\t\t\tswitch( i ) {\n\t\t\tcase 0:\n\t\t\t\tvips_buf_appendf( buf, _( \"at %d\" ),\n\t\t\t\t\tiarrow->instance.area.top );\n\t\t\t\tbreak;\n\n\t\t\tcase 1:\n\t\t\t\tvips_buf_appendf( buf, _( \"at %d\" ),\n\t\t\t\t\tiarrow->instance.area.left );\n\t\t\t\tbreak;\n\n\t\t\tcase 2:\n\t\t\t\tvips_buf_appendf( buf, _( \"at (%d, %d)\" ),\n\t\t\t\t\tiarrow->instance.area.left,\n\t\t\t\t\tiarrow->instance.area.top );\n\t\t\t\tbreak;\n\n\t\t\tcase 3:\n\t\t\t\tvips_buf_appendf( buf, \n\t\t\t\t\t_( \"at (%d, %d), offset (%d, %d)\" ),\n\t\t\t\t\tiarrow->instance.area.left, \n\t\t\t\t\tiarrow->instance.area.top,\n\t\t\t\t\tiarrow->instance.area.width, \n\t\t\t\t\tiarrow->instance.area.height );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tg_assert( 0 );\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn( vips_buf_all( buf ) );\n}\n\nstatic View *\niarrow_view_new( Model *model, View *parent )\n{\n\treturn( valueview_new() );\n}\n\nstatic void *\niarrow_update_model( Heapmodel *heapmodel )\n{\n\t/* Parent first ... this will update our instance vars.\n\t */\n\tif( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) )\n\t\treturn( heapmodel );\n\n\tif( heapmodel->row->expr ) {\n\t\tiArrow *iarrow = IARROW( heapmodel );\n\n\t\t/* Update who-has-displays-on-what stuff.\n\t\t */\n\t\tclassmodel_iimage_update( CLASSMODEL( iarrow ), \n\t\t\tiarrow->instance.ii );\n\n\t\t/* Need to make sure the caption is regenerated.\n\t\t */\n\t\tiobject_changed( IOBJECT( heapmodel ) );\n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\niarrow_get_instance( Classmodel *classmodel )\n{\n\tiArrow *iarrow = IARROW( classmodel );\n\n\treturn( &iarrow->instance );\n}\n\nstatic void\niarrow_class_init( iArrowClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tiContainerClass *icontainer_class = (iContainerClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tHeapmodelClass *heapmodel_class = (HeapmodelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\t/* We share methods with iregion in a sort of MI way ... iregion needs\n\t * to be initialised before we can work. Force it to start up.\n\t */\n\t(void) iregion_get_type();\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->finalize = iarrow_finalize;\n\n\tiobject_class->generate_caption = iarrow_generate_caption;\n\n\ticontainer_class->parent_add = iregion_parent_add;\n\n\tmodel_class->view_new = iarrow_view_new;\n\tmodel_class->edit = iregion_edit;\n\tmodel_class->save = iregion_save;\n\tmodel_class->load = iregion_load;\n\n\theapmodel_class->update_model = iarrow_update_model;\n\theapmodel_class->update_heap = iregion_update_heap;\n\n\tclassmodel_class->class_get = iregion_class_get;\n\tclassmodel_class->class_new = iregion_class_new;\n\tclassmodel_class->get_instance = iarrow_get_instance;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\niarrow_init( iArrow *iarrow )\n{\n\tiregion_instance_init( &iarrow->instance, CLASSMODEL( iarrow ) );\n\tvips_buf_init_dynamic( &iarrow->caption_buffer, MAX_LINELENGTH );\n\n\tiobject_set( IOBJECT( iarrow ), CLASS_ARROW, NULL );\n}\n\nGType\niarrow_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( iArrowClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) iarrow_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( iArrow ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) iarrow_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"iArrow\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/iarrow.h",
    "content": "/* a ip region class in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_IARROW (iarrow_get_type())\n#define IARROW( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IARROW, iArrow ))\n#define IARROW_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_IARROW, iArrowClass))\n#define IS_IARROW( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IARROW ))\n#define IS_IARROW_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IARROW ))\n#define IARROW_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_IARROW, iArrowClass ))\n\nstruct _iArrow {\n\tClassmodel parent_class;\n\n\t/* Class fields.\n\t */\n\tiRegionInstance instance;\n\n\t/* Private ... build iobject caption here.\n\t */\n\tVipsBuf caption_buffer;\n};\n\ntypedef struct _iArrowClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} iArrowClass;\n\nGType iarrow_get_type( void );\n"
  },
  {
    "path": "src/icontainer.c",
    "content": "/* abstract base class for containers\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG_SANITY\n#define DEBUG_VERBOSE\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* Our signals. \n */\nenum {\n\tSIG_POS_CHANGED,\t/* Member has moved */\n\tSIG_CHILD_ADD,\t\t/* iContainer is about to gain a child */\n\tSIG_CHILD_REMOVE,\t/* iContainer is about to loose a child */\n\tSIG_CURRENT,\t\t/* Make child current of parent */\n\tSIG_CHILD_DETACH,\t/* Used as a pair to do reparent */\n\tSIG_CHILD_ATTACH,\n\tSIG_LAST\n};\n\nstatic iObjectClass *parent_class = NULL;\n\nstatic guint icontainer_signals[SIG_LAST] = { 0 };\n\nint\nicontainer_get_n_children( iContainer *icontainer )\n{\n\treturn( g_slist_length( icontainer->children ) );\n}\n\niContainer *\nicontainer_get_nth_child( iContainer *icontainer, int n )\n{\n\treturn( ICONTAINER( g_slist_nth_data( icontainer->children, n ) ) );\n}\n\nGSList *\nicontainer_get_children( iContainer *icontainer )\n{\n\treturn( g_slist_copy( icontainer->children ) );\n}\n\nvoid *\nicontainer_map( iContainer *icontainer, icontainer_map_fn fn, void *a, void *b )\n{\n\treturn( slist_map2( icontainer->children, (SListMap2Fn) fn, a, b ) );\n}\n\nvoid *\nicontainer_map3( iContainer *icontainer, \n\ticontainer_map3_fn fn, void *a, void *b, void *c )\n{\n\treturn( slist_map3( icontainer->children, (SListMap3Fn) fn, a, b, c ) );\n}\n\nvoid *\nicontainer_map4( iContainer *icontainer, \n\ticontainer_map4_fn fn, void *a, void *b, void *c, void *d )\n{\n\treturn( slist_map4( icontainer->children, \n\t\t(SListMap4Fn) fn, a, b, c, d ) );\n}\n\nvoid *\nicontainer_map5( iContainer *icontainer, \n\ticontainer_map5_fn fn, void *a, void *b, void *c, void *d, void *e )\n{\n\treturn( slist_map5( icontainer->children, \n\t\t(SListMap5Fn) fn, a, b, c, d, e ) );\n}\n\n/* Map in reverse order.\n */\nvoid *\nicontainer_map_rev( iContainer *icontainer, \n\ticontainer_map_fn fn, void *a, void *b )\n{\n\treturn( slist_map2_rev( icontainer->children, \n\t\t(SListMap2Fn) fn, a, b ) );\n}\n\n/* Apply a function to a tree of icontainers, bottom up.\n */\nvoid *\nicontainer_map_all( iContainer *icontainer, icontainer_map_fn fn, void *a )\n{\n\tiContainer *result;\n\n\tif( (result = icontainer_map( icontainer, \n\t\t(icontainer_map_fn) icontainer_map_all, (void *) fn, a )) )\n\t\treturn( result );\n\n\treturn( fn( icontainer, a, NULL ) );\n}\n\nvoid *\nicontainer_map2_all( iContainer *icontainer, \n\ticontainer_map_fn fn, void *a, void *b )\n{\n\tiContainer *result;\n\n\tif( (result = icontainer_map3( icontainer, \n\t\t(icontainer_map3_fn) icontainer_map2_all, (void *) fn, a, b )) )\n\t\treturn( result );\n\n\treturn( fn( icontainer, a, b ) );\n}\n\nvoid *\nicontainer_map3_all( iContainer *icontainer, \n\ticontainer_map3_fn fn, void *a, void *b, void *c )\n{\n\tiContainer *result;\n\n\tif( (result = icontainer_map4( icontainer, \n\t\t(icontainer_map4_fn) icontainer_map3_all, \n\t\t\t(void *) fn, a, b, c )) )\n\t\treturn( result );\n\n\treturn( fn( icontainer, a, b, c ) );\n}\n\nvoid *\nicontainer_map4_all( iContainer *icontainer, \n\ticontainer_map4_fn fn, void *a, void *b, void *c, void *d )\n{\n\tiContainer *result;\n\n\tif( (result = icontainer_map5( icontainer, \n\t\t(icontainer_map5_fn) icontainer_map4_all, \n\t\t\t(void *) fn, a, b, c, d )) )\n\t\treturn( result );\n\n\treturn( fn( icontainer, a, b, c, d ) );\n}\n\n/* Apply a function to the children of a icontainer.\n */\nvoid *\nicontainer_map_all_intrans( iContainer *icontainer, \n\ticontainer_map_fn fn, void *a )\n{\n\treturn( icontainer_map( icontainer, \n\t\t(icontainer_map_fn) icontainer_map_all, (void *) fn, a ) );\n}\n\nstatic void *\nicontainer_sanity_child( iContainer *child, iContainer *parent )\n{\n\tg_assert( IS_ICONTAINER( child ) );\n\tg_assert( IS_ICONTAINER( parent ) );\n\tg_assert( child->parent == parent );\n\tg_assert( child->pos >= 0 );\n\tg_assert( g_slist_find( parent->children, child ) );\n\n\tif( parent->child_hash )\n\t\tg_assert( g_hash_table_lookup( parent->child_hash, \n\t\t\tIOBJECT( child )->name ) );\n\n\treturn( NULL );\n}\n\nvoid\nicontainer_sanity( iContainer *icontainer )\n{\n\tg_assert( IS_ICONTAINER( icontainer ) );\n\n\tif( icontainer->parent )\n\t\ticontainer_sanity_child( icontainer, icontainer->parent );\n\ticontainer_map( icontainer, \n\t\t(icontainer_map_fn) icontainer_sanity_child, icontainer, NULL );\n}\n\nstatic gint\nicontainer_pos_compare( iContainer *a, iContainer *b )\n{\n        return( a->pos - b->pos );\n}\n\nvoid\nicontainer_pos_sort( iContainer *icontainer )\n{\n        icontainer->children = g_slist_sort( icontainer->children, \n\t\t(GCompareFunc) icontainer_pos_compare );\n\tiobject_changed( IOBJECT( icontainer ) );\n}\n\nstatic void *\nicontainer_pos_last_sub( iContainer *icontainer, int *max )\n{\n\tif( icontainer->pos > *max )\n\t\t*max = icontainer->pos;\n\n\treturn( NULL );\n}\n\nint\nicontainer_pos_last( iContainer *icontainer )\n{\n\tint max = -1;\n\n\ticontainer_map( icontainer,\n\t\t(icontainer_map_fn) icontainer_pos_last_sub, &max, NULL );\n\n\treturn( max );\n}\n\nstatic void *\nicontainer_pos_changed( iContainer *icontainer )\n{\n#ifdef DEBUG\n\tprintf( \"icontainer_pos_changed: \" );\n\tiobject_print( IOBJECT( icontainer ) );\n#endif /*DEBUG*/\n\n\tg_signal_emit( G_OBJECT( icontainer ), \n\t\ticontainer_signals[SIG_POS_CHANGED], 0 );\n\n\treturn( NULL );\n}\n\nstatic void *\nicontainer_pos_renumber_sub( iContainer *icontainer, int *n, GSList **changed )\n{\n\tif( icontainer->pos != *n ) {\n\t\ticontainer->pos = *n;\n\t\t*changed = g_slist_prepend( *changed, icontainer );\n\t}\n\n\t*n += 1;\n\n\treturn( NULL );\n}\n\n#ifdef DEBUG_VERBOSE\nstatic void *\nicontainer_print_element( iContainer *element, int *n )\n{\n\tprintf( \"\\t%3d) pos = %d \", *n, element->pos );\n\tiobject_print( IOBJECT( element ) );\n\t*n += 1;\n\n\treturn( NULL );\n}\n#endif /*DEBUG_VERBOSE*/\n\nvoid\nicontainer_pos_renumber( iContainer *icontainer )\n{\n\tint n = 0;\n\tGSList *changed;\n\n#ifdef DEBUG_VERBOSE\n{\n\tint i;\n\n\tprintf( \"icontainer_pos_renumber: \" );\n\tiobject_print( IOBJECT( icontainer ) );\n\tprintf( \"\\tbefore:\\n\" );\n\ti = 0;\n\ticontainer_map( icontainer, \n\t\t(icontainer_map_fn) icontainer_print_element, &i, NULL );\n}\n#endif /*DEBUG_VERBOSE*/\n\n\tchanged = NULL;\n\ticontainer_map( icontainer,\n\t\t(icontainer_map_fn) icontainer_pos_renumber_sub, &n, &changed );\n\n\t/* Tell all the children that have been renumbered.\n\t */\n#ifdef DEBUG_VERBOSE\n\tif( g_slist_length( changed ) > 1 ) {\n\t\tprintf( \"icontainer_pos_renumber: renumbering %d children! \",\n\t\t\tg_slist_length( changed ) );\n\t\tiobject_print( IOBJECT( icontainer ) );\n\t}\n#endif /*DEBUG_VERBOSE*/\n\tslist_map( changed,\n\t\t(SListMapFn) icontainer_pos_changed, NULL );\n\tg_slist_free( changed );\n\tiobject_changed( IOBJECT( icontainer ) );\n\n#ifdef DEBUG_VERBOSE\n{\n\tint i;\n\n\tprintf( \"icontainer_pos_renumber: \" );\n\tiobject_print( IOBJECT( icontainer ) );\n\tprintf( \"\\tafter:\\n\" );\n\ti = 0;\n\ticontainer_map( icontainer, \n\t\t(icontainer_map_fn) icontainer_print_element, &i, NULL );\n}\n#endif /*DEBUG_VERBOSE*/\n}\n\ngint\nicontainer_name_compare( iContainer *a, iContainer *b )\n{\n        return( strcasecmp( IOBJECT( a )->name, IOBJECT( b )->name ) );\n}\n\nvoid\nicontainer_custom_sort( iContainer *icontainer, GCompareFunc fn )\n{\n        icontainer->children = g_slist_sort( icontainer->children, fn );\n\ticontainer_pos_renumber( icontainer );\n\tiobject_changed( IOBJECT( icontainer ) );\n}\n\n/* Add a child.\n */\nvoid\nicontainer_child_add( iContainer *parent, iContainer *child, int pos )\n{\n\tg_assert( IS_ICONTAINER( parent ) );\n\tg_assert( IS_ICONTAINER( child ) );\n\n#ifdef DEBUG_SANITY\n\ticontainer_sanity( parent );\n\ticontainer_sanity( child );\n#endif /*DEBUG_SANITY*/\n\n\tg_signal_emit( G_OBJECT( parent ), \n\t\ticontainer_signals[SIG_CHILD_ADD], 0, child, pos );\n\n#ifdef DEBUG_SANITY\n\ticontainer_sanity( parent );\n\ticontainer_sanity( child );\n#endif /*DEBUG_SANITY*/\n}\n\n/* Add a child before another child. after == NULL means append.\n */\nvoid\nicontainer_child_add_before( iContainer *parent, \n\tiContainer *child, iContainer *before )\n{\n\tint pos;\n\n\tg_assert( !before || IS_ICONTAINER( before ) );\n\tg_assert( !before || before->parent == parent );\n\n\tpos = g_slist_index( parent->children, before );\n\ticontainer_child_add( parent, child, pos );\n}\n\n/* pos == 0 ... move to start\n * pos == -1 ... move to end\n * pos == n ... move before sibling at position n\n */\nvoid\nicontainer_child_move( iContainer *child, int pos )\n{\n\tiContainer *parent = child->parent;\n\n\tparent->children = g_slist_remove( parent->children, child );\n\n        if( pos >= 0 )\n                parent->children = g_slist_insert( parent->children,\n                        child, pos );\n        else\n                parent->children = g_slist_append( parent->children, child );\n\n        icontainer_pos_renumber( parent );\n\tiobject_changed( IOBJECT( child ) );\n}\n\nvoid *\nicontainer_child_remove( iContainer *child )\n{\n\tiContainer *parent;\n\n\tif( (parent = child->parent) ) {\n\t\tg_assert( ICONTAINER_IS_CHILD( parent, child ) );\n\n#ifdef DEBUG\n\t\tprintf( \"icontainer_child_remove: (child %p)\\n\", child );\n\t\tprintf( \"\\tchild: %s \\\"%s\\\"\\n\",\n\t\t\tG_OBJECT_TYPE_NAME( child ), \n\t\t\tNN( IOBJECT( child )->name ) );\n#endif /*DEBUG*/\n\n#ifdef DEBUG_SANITY\n\t\ticontainer_sanity( parent );\n\t\ticontainer_sanity( child );\n#endif /*DEBUG_SANITY*/\n\n\t\tg_signal_emit( G_OBJECT( parent ), \n\t\t\ticontainer_signals[SIG_CHILD_REMOVE], 0, child );\n\n#ifdef DEBUG_SANITY\n\t\ticontainer_sanity( parent );\n#endif /*DEBUG_SANITY*/\n\t}\n\n\treturn( NULL );\n}\n\nvoid \nicontainer_current( iContainer *parent, iContainer *child )\n{\n\tg_assert( parent );\n\tg_assert( !child || ICONTAINER_IS_CHILD( parent, child ) );\n\n\tif( parent->current == child )\n\t\treturn; \n\n#ifdef DEBUG\n\tprintf( \"icontainer_current: (child %p)\\n\", child );\n\tprintf( \"\\tchild: %s \\\"%s\\\"\\n\",\n\t\tG_OBJECT_TYPE_NAME( child ), \n\t\tNN( IOBJECT( child )->name ) );\n#endif /*DEBUG*/\n\n#ifdef DEBUG_SANITY\n\ticontainer_sanity( parent );\n\tif( child )\n\t\ticontainer_sanity( child );\n#endif /*DEBUG_SANITY*/\n\n\tg_signal_emit( G_OBJECT( parent ), \n\t\ticontainer_signals[SIG_CURRENT], 0, child );\n\n#ifdef DEBUG_SANITY\n\ticontainer_sanity( parent );\n\tif( child )\n\t\ticontainer_sanity( child );\n#endif /*DEBUG_SANITY*/\n}\n\niContainer *\nicontainer_next( iContainer *parent )\n{\n\tiContainer *child;\n\tint i;\n\n\tif( !parent->children ) \n\t\treturn( NULL ); \n\n\tif( !parent->current )\n\t\ti = 0;\n\telse\n\t\ti = g_slist_index( parent->children, parent->current ) + 1;\n\n\tif( !(child = g_slist_nth_data( parent->children, i )) )\n\t\tchild = ICONTAINER( parent->children->data );\n\n\ticontainer_current( parent, child );\n\n\treturn( child ); \n}\n\nvoid \nicontainer_reparent( iContainer *parent, iContainer *child, int pos )\n{\n\tiContainer *old_parent = child->parent;\n\n\tg_assert( parent );\n\tg_assert( child );\n\n#ifdef DEBUG_SANITY\n\ticontainer_sanity( old_parent );\n\ticontainer_sanity( parent );\n\ticontainer_sanity( child );\n#endif /*DEBUG_SANITY*/\n\n\t/* These must always happen as a pair.\n\t */\n\tg_signal_emit( G_OBJECT( old_parent ), \n\t\ticontainer_signals[SIG_CHILD_DETACH], 0, child );\n\tg_signal_emit( G_OBJECT( parent ), \n\t\ticontainer_signals[SIG_CHILD_ATTACH], 0, child, pos );\n\n        icontainer_pos_renumber( parent );\n\tiobject_changed( IOBJECT( parent ) );\n\tiobject_changed( IOBJECT( old_parent ) );\n\tiobject_changed( IOBJECT( child ) );\n\n#ifdef DEBUG_SANITY\n\ticontainer_sanity( old_parent );\n\ticontainer_sanity( parent );\n\ticontainer_sanity( child );\n#endif /*DEBUG_SANITY*/\n}\n\nstatic void\nicontainer_dispose( GObject *gobject )\n{\n\tiContainer *icontainer;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_ICONTAINER( gobject ) );\n\n\ticontainer = ICONTAINER( gobject );\n\n#ifdef DEBUG\n\tprintf( \"icontainer_dispose: (%p) %s \\\"%s\\\"\\n\",\n\t\ticontainer,\n\t\tG_OBJECT_TYPE_NAME( icontainer ), \n\t\tNN( IOBJECT( icontainer )->name ) );\n#endif /*DEBUG*/\n\n\ticontainer_map( icontainer,\n\t\t(icontainer_map_fn) icontainer_child_remove, NULL, NULL );\n\ticontainer_child_remove( icontainer );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\nicontainer_finalize( GObject *gobject )\n{\n\tiContainer *icontainer;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_ICONTAINER( gobject ) );\n\n\ticontainer = ICONTAINER( gobject );\n\n\tIM_FREEF( g_hash_table_destroy, icontainer->child_hash );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\nicontainer_info( iObject *iobject, VipsBuf *buf )\n{\n\tiContainer *icontainer = ICONTAINER( iobject );\n\n\tvips_buf_appendf( buf, \"pos = \\\"%d\\\"\\n\", icontainer->pos );\n\n\tIOBJECT_CLASS( parent_class )->info( iobject, buf );\n}\n\nstatic void\nicontainer_real_pos_changed( iContainer *icontainer )\n{\n}\n\nstatic void\nicontainer_link( iContainer *parent, iContainer *child, int pos )\n{\n        if( pos >= 0 ) \n                parent->children = g_slist_insert( parent->children,\n                        child, pos );\n        else\n                parent->children = g_slist_append( parent->children, child );\n        child->parent = parent;\n        child->pos = pos;\n\tif( parent->child_hash ) {\n\t\tg_assert( !g_hash_table_lookup( parent->child_hash, \n\t\t\tIOBJECT( child )->name ) );\n\n\t\tg_hash_table_insert( parent->child_hash, \n\t\t\tIOBJECT( child )->name, child );\n\t}\n}\n\nstatic void\nicontainer_real_child_add( iContainer *parent, iContainer *child, int pos )\n{\n\tiContainerClass *icontainer_class = ICONTAINER_GET_CLASS( child );\n\n        g_assert( IS_ICONTAINER( parent ) && IS_ICONTAINER( child ) );\n        g_assert( child->parent == NULL );\n\n#ifdef DEBUG\n\tprintf( \"icontainer_real_child_add:\\n\\tparent \" );\n\tiobject_print( IOBJECT( parent ) );\n\tprintf( \"\\tchild \" );\n\tiobject_print( IOBJECT( child ) );\n\tprintf( \"\\tpos = %d\\n\", pos );\n#endif /*DEBUG*/\n\n\ticontainer_link( parent, child, pos ); \n\n\tg_object_ref( G_OBJECT( child ) );\n\tiobject_sink( IOBJECT( child ) );\n\n\t/* Renumber to get all the pos set. \n\t */\n        icontainer_pos_renumber( parent );\n\tiobject_changed( IOBJECT( child ) );\n\n        /* We've made the link ... trigger the parent_add() on the child.\n         */\n        icontainer_class->parent_add( child );\n\n#ifdef DEBUG_VERBOSE\n        printf( \"icontainer_real_child_add: \" );\n\tiobject_print( IOBJECT( parent ) );\n#endif /*DEBUG_VERBOSE*/\n}\n\nstatic void\nicontainer_unlink( iContainer *child )\n{\n\tiContainer *parent = child->parent;\n\n\tparent->children = g_slist_remove( parent->children, child );\n\tchild->parent = NULL;\n\tif( parent->child_hash ) {\n\t\tg_assert( g_hash_table_lookup( parent->child_hash, \n\t\t\tIOBJECT( child )->name ) );\n\n\t\tg_hash_table_remove( parent->child_hash, \n\t\t\tIOBJECT( child )->name );\n\t}\n}\n\nstatic void \nicontainer_real_child_remove( iContainer *parent, iContainer *child )\n{\n\tiContainerClass *icontainer_child_class = ICONTAINER_GET_CLASS( child );\n\n\tg_assert( IS_ICONTAINER( parent ) && IS_ICONTAINER( child ) );\n\n#ifdef DEBUG\n\tprintf( \"icontainer_real_child_remove: parent %s \\\"%s\\\"; \"\n\t\t\"child %s \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ),\n\t\tG_OBJECT_TYPE_NAME( child ), NN( IOBJECT( child )->name ) );\n#endif /*DEBUG*/\n\n\tif( parent->current == child )\n\t\ticontainer_current( parent, NULL ); \n\n\t/* We're about to break the link ... trigger the parent_remove() on \n\t * the child.\n\t */\n\ticontainer_child_class->parent_remove( child );\n\n\ticontainer_unlink( child ); \n\n\tUNREF( child );\n\n\tiobject_changed( IOBJECT( parent ) );\n}\n\nstatic void\nicontainer_real_parent_add( iContainer *child )\n{\n#ifdef DEBUG\n\tprintf( \"icontainer_real_parent_add: child %s \\\"%s\\\"; \" \n\t\t\"parent %s \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( child ), \n\t\tNN( IOBJECT( child )->name ),\n\t\tG_OBJECT_TYPE_NAME( child->parent ), \n\t\tNN( IOBJECT( child->parent )->name ) );\n#endif /*DEBUG*/\n}\n\nstatic void\nicontainer_real_parent_remove( iContainer *child )\n{\n#ifdef DEBUG\n{\n\tiContainer *parent = child->parent;\n\n\tprintf( \"icontainer_real_parent_remove: child %s \\\"%s\\\"; \"\n\t\t\"parent %s \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( child ), NN( IOBJECT( child )->name ),\n\t\tG_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ) );\n}\n#endif /*DEBUG*/\n}\n\nstatic void \nicontainer_real_current( iContainer *parent, iContainer *child )\n{\n\tiContainer *old_current;\n\n\tg_assert( IS_ICONTAINER( parent ) );\n\tg_assert( !child || IS_ICONTAINER( child ) );\n\tg_assert( !child || ICONTAINER_IS_CHILD( parent, child ) );\n\n#ifdef DEBUG\n\tprintf( \"icontainer_real_current: parent %s \\\"%s\\\"; \"\n\t\t\"child %s \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ),\n\t\tchild ? G_OBJECT_TYPE_NAME( child ) : \"NULL\", \n\t\tchild ? NN( IOBJECT( child )->name ) : \"NULL\" );\n#endif /*DEBUG*/\n\n\told_current = parent->current;\n\tparent->current = child;\n\n\tif( old_current != child ) {\n\t\tif( old_current )\n\t\t\tiobject_changed( IOBJECT( old_current ) );\n\t\tif( child )\n\t\t\tiobject_changed( IOBJECT( child ) );\n\t\tiobject_changed( IOBJECT( parent ) );\n\t}\n\n\tif( child )\n\t\tmodel_front( MODEL( child ) );\n}\n\nstatic void\nicontainer_real_child_detach( iContainer *parent, iContainer *child )\n{\n        g_assert( IS_ICONTAINER( parent ) ); \n        g_assert( IS_ICONTAINER( child ) );\n        g_assert( child->parent != NULL );\n\tg_assert( ICONTAINER_IS_CHILD( parent, child ) );\n\n\ticontainer_unlink( child ); \n}\n\nstatic void\nicontainer_real_child_attach( iContainer *parent, iContainer *child, int pos )\n{\n        g_assert( IS_ICONTAINER( parent ) ); \n        g_assert( IS_ICONTAINER( child ) );\n        g_assert( child->parent == NULL );\n\n\ticontainer_link( parent, child, pos ); \n}\n\nstatic void\nicontainer_class_init( iContainerClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tiObjectClass *iobject_class = IOBJECT_CLASS( class );\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = icontainer_dispose;\n\tgobject_class->finalize = icontainer_finalize;\n\n\tiobject_class->info = icontainer_info;\n\n\tclass->pos_changed = icontainer_real_pos_changed;\n\tclass->child_add = icontainer_real_child_add;\n\tclass->child_remove = icontainer_real_child_remove;\n\tclass->parent_add = icontainer_real_parent_add;\n\tclass->parent_remove = icontainer_real_parent_remove;\n\tclass->current = icontainer_real_current;\n\tclass->child_detach = icontainer_real_child_detach;\n\tclass->child_attach = icontainer_real_child_attach;\n\n\t/* Create signals.\n\t */\n\ticontainer_signals[SIG_POS_CHANGED] = g_signal_new( \"pos_changed\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( iContainerClass, pos_changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\n\ticontainer_signals[SIG_CHILD_ADD] = g_signal_new( \"child_add\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( iContainerClass, child_add ),\n\t\tNULL, NULL,\n\t\tnip_VOID__OBJECT_INT,\n\t\tG_TYPE_NONE, 2,\n\t\tTYPE_ICONTAINER, GTK_TYPE_INT );\n\n\ticontainer_signals[SIG_CHILD_REMOVE] = g_signal_new( \"child_remove\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_LAST,\n\t\tG_STRUCT_OFFSET( iContainerClass, child_remove ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__OBJECT,\n\t\tG_TYPE_NONE, 1,\n\t\tTYPE_ICONTAINER );\n\n\ticontainer_signals[SIG_CURRENT] = g_signal_new( \"current\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_LAST,\n\t\tG_STRUCT_OFFSET( iContainerClass, current ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__OBJECT,\n\t\tG_TYPE_NONE, 1,\n\t\tTYPE_ICONTAINER );\n\n\ticontainer_signals[SIG_CHILD_DETACH] = g_signal_new( \"child_detach\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_LAST,\n\t\tG_STRUCT_OFFSET( iContainerClass, child_detach ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__OBJECT,\n\t\tG_TYPE_NONE, 1,\n\t\tTYPE_ICONTAINER );\n\n\ticontainer_signals[SIG_CHILD_ATTACH] = g_signal_new( \"child_attach\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( iContainerClass, child_attach ),\n\t\tNULL, NULL,\n\t\tnip_VOID__OBJECT_INT,\n\t\tG_TYPE_NONE, 2,\n\t\tTYPE_ICONTAINER, GTK_TYPE_INT );\n\n#ifdef DEBUG_SANITY\n\tprintf( \"*** DEBUG_SANITY is on ... expect slowness\\n\" );\n#endif /*DEBUG_SANITY*/\n}\n\nstatic void\nicontainer_init( iContainer *icontainer )\n{\n\t/* Init our instance fields.\n\t */\n\ticontainer->children = NULL;\n\ticontainer->pos = -1;\n\ticontainer->parent = NULL;\n\ticontainer->child_hash = NULL;\n}\n\nGType\nicontainer_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( iContainerClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) icontainer_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( iContainer ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) icontainer_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_IOBJECT, \n\t\t\t\"iContainer\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\n/* Put the container into lookup-by-child-name mode.\n */\nvoid\nicontainer_set_hash( iContainer *icontainer )\n{\n\t/* Can only do this once just after startup, and before there are any\n\t * children.\n\t */\n\tg_assert( !icontainer->children );\n\tg_assert( !icontainer->child_hash );\n\n\ticontainer->child_hash = g_hash_table_new( g_str_hash, g_str_equal );\n}\n\niContainer *\nicontainer_child_lookup( iContainer *parent, const char *name )\n{\n\tg_assert( parent->child_hash );\n\n\treturn( ICONTAINER( g_hash_table_lookup( parent->child_hash, name ) ) );\n}\n"
  },
  {
    "path": "src/icontainer.h",
    "content": "/* abstract base class for containers\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_ICONTAINER (icontainer_get_type())\n#define ICONTAINER( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_ICONTAINER, iContainer ))\n#define ICONTAINER_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_ICONTAINER, iContainerClass))\n#define IS_ICONTAINER( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_ICONTAINER ))\n#define IS_ICONTAINER_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_ICONTAINER ))\n#define ICONTAINER_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_ICONTAINER, iContainerClass ))\n\n/* Test for is C a child of P.\n */\n#define ICONTAINER_IS_CHILD( P, C ) \\\n\t(g_slist_find( ICONTAINER( P )->children, ICONTAINER( C ) ) && \\\n\tICONTAINER( C )->parent == ICONTAINER( P ))\n\nstruct _iContainer {\n\tiObject parent_object;\n\n\t/* My instance vars.\n\t */\n\tGSList *children;\t/* iContainers which are inside this one */\n\tint pos;\t\t/* Position in parent */\n\tiContainer *parent;\t/* iContainer we are inside */\n\tGHashTable *child_hash;\t/* Optional: hash of children by their name */\n\n\t/* Can have a currently selected child ... eg. the\n\t * current column in a workspace, or the current tab in a\n\t * workspacegroup.\n\t *\n\t * NULL if not relevant.\n\t */\n\tiContainer *current;\n\n\t/* Track the view here during reparent.\n\t */\n\tView *temp_view;\n};\n\ntypedef struct _iContainerClass {\n\tiObjectClass parent_class;\n\n\t/* \n\n\t\tpos_changed\tour pos has changed\n\n\t\tchild_add\ta child has been added to us\n\n\t\tchild_remove\ta child is about be removed from us\n\n\t\tparent_add\tparent has been attached\n\n\t\tparent_remove\tparent is about to be removed\n\n\t\tcurrent\t\tmake the current of parent\n\n\t\tchild_detach\ton old parent, unlink child\n\t\tchild_attach  \ton new_paerent, link on child\n\n\t\t\t\t\tthere are used as a pair to do \n\t\t\t\t\treparent -- the old parent gets a \n\t\t\t\t\tchance to detach in ::parent_detach, \n\t\t\t\t\tthe new parent attaches in \n\t\t\t\t\t::child_attach\n\n\t */\n\n\tvoid (*pos_changed)( iContainer *icontainer );\n\tvoid (*child_add)( iContainer *parent, iContainer *child, int );\n\tvoid (*child_remove)( iContainer *parent, iContainer *child );\n\tvoid (*parent_add)( iContainer *child );\n\tvoid (*parent_remove)( iContainer *child );\n\tvoid (*current)( iContainer *parent, iContainer *child );\n\tvoid (*child_detach)( iContainer *parent, iContainer *child );\n\tvoid (*child_attach)( iContainer *parent, iContainer *child, int );\n} iContainerClass;\n\ntypedef void *(*icontainer_map_fn)( iContainer *, \n\tvoid *, void * );\ntypedef void *(*icontainer_map3_fn)( iContainer *, \n\tvoid *, void *, void * );\ntypedef void *(*icontainer_map4_fn)( iContainer *, \n\tvoid *, void *, void *, void * );\ntypedef void *(*icontainer_map5_fn)( iContainer *, \n\tvoid *, void *, void *, void *, void * );\n\ntypedef gint (*icontainer_sort_fn)( iContainer *a, iContainer *b );\n\nint icontainer_get_n_children( iContainer *icontainer );\niContainer *icontainer_get_nth_child( iContainer *icontainer, int n );\nGSList *icontainer_get_children( iContainer *icontainer );\nvoid *icontainer_map( iContainer *icontainer, \n\ticontainer_map_fn fn, void *a, void *b );\nvoid *icontainer_map3( iContainer *icontainer, \n\ticontainer_map3_fn fn, void *a, void *b, void *c );\nvoid *icontainer_map4( iContainer *icontainer, \n\ticontainer_map4_fn fn, void *a, void *b, void *c, void *d );\nvoid *icontainer_map5( iContainer *icontainer, \n\ticontainer_map5_fn fn, void *a, void *b, void *c, void *d, void *e ); \nvoid *icontainer_map_rev( iContainer *icontainer, \n\ticontainer_map_fn fn, void *a, void *b );\nvoid *icontainer_map_all( iContainer *icontainer, \n\ticontainer_map_fn fn, void *a );\nvoid *icontainer_map2_all( iContainer *icontainer, \n\ticontainer_map_fn fn, void *a, void *b );\nvoid *icontainer_map3_all( iContainer *icontainer, \n\ticontainer_map3_fn fn, void *a, void *b, void *c );\nvoid *icontainer_map4_all( iContainer *icontainer, \n\ticontainer_map4_fn fn, void *a, void *b, void *c, void *d );\nvoid *icontainer_map_all_intrans( iContainer *icontainer, \n\ticontainer_map_fn fn, void *a );\n\nvoid icontainer_sanity( iContainer *icontainer );\n\nvoid icontainer_pos_sort( iContainer *icontainer );\nint icontainer_pos_last( iContainer *icontainer );\nvoid icontainer_pos_renumber( iContainer *icontainer );\nvoid icontainer_custom_sort( iContainer *icontainer, GCompareFunc fn );\ngint icontainer_name_compare( iContainer *a, iContainer *b );\n\nvoid icontainer_child_add( iContainer *icontainer, iContainer *child, int pos );\nvoid icontainer_child_add_before( iContainer *parent, \n\tiContainer *child, iContainer *before );\nvoid icontainer_child_move( iContainer *child, int pos );\nvoid *icontainer_child_remove( iContainer *child );\nvoid icontainer_current( iContainer *parent, iContainer *child );\niContainer *icontainer_next( iContainer *parent );\nvoid icontainer_reparent( iContainer *parent, iContainer *child, int pos );\n\nGType icontainer_get_type( void );\n\nvoid icontainer_set_hash( iContainer *icontainer );\niContainer *icontainer_child_lookup( iContainer *parent, const char *name );\n"
  },
  {
    "path": "src/idialog.c",
    "content": "/* make and manage base dialogs ... subclass off this for others\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#include \"ip.h\"\n\n/*\n#define DEBUG\n */\n\nstatic iWindowClass *parent_class = NULL;\n\n/* An OK button: label (can be a stock) plus a callback.\n */\ntypedef struct {\n\tchar *label;\n\tiWindowFn done_cb;\n} OKButton;\n\nstatic void *\nokbutton_free( OKButton *ok )\n{\n\tIM_FREEF( g_free, ok->label );\n\tok->done_cb = NULL;\n\tIM_FREEF( g_free, ok );\n\n\treturn( NULL );\n}\n\nstatic OKButton *\nokbutton_new( char *label, iWindowFn done_cb )\n{\n\tOKButton *ok;\n\n\tok = g_new( OKButton, 1 );\n\tok->label = g_strdup( label );\n\tok->done_cb = done_cb;\n\n\treturn( ok );\n}\n\n/* Handy destroy callback ... just free client.\n */\nvoid\nidialog_free_client( iDialog *idlg, void *client )\n{\n\tIM_FREE( client );\n}\n\n/* Notify our parent.\n */\nstatic void\nidialog_notify_parent( iDialog *idlg, iWindowResult result )\n{\n\tif( idlg->nfn ) {\n\t\tiWindowNotifyFn nfn = idlg->nfn;\n\t\t\n\t\tidlg->nfn = NULL;\n\t\tnfn( idlg->sys, result );\n\t}\n}\n\nstatic void *\nidialog_set_sensitive( GtkWidget *w, gboolean state )\n{\n\tgtk_widget_set_sensitive( w, state );\n\n\treturn( NULL );\n}\n\n/* Set OK sensitivities.\n */\nvoid\nidialog_set_ok_button_state( iDialog *idlg, gboolean state )\n{\n\tslist_map( idlg->ok_but_l, \n\t\t(SListMapFn) idialog_set_sensitive, GINT_TO_POINTER( state ) );\n}\n\n/* Set all the button sensitivities.\n */\nstatic void\nidialog_set_button_state( iDialog *idlg, gboolean state )\n{\n\tidialog_set_ok_button_state( idlg, state );\n\tif( idlg->but_cancel )\n\t\tgtk_widget_set_sensitive( idlg->but_cancel, state );\n\tif( idlg->but_help )\n\t\tgtk_widget_set_sensitive( idlg->but_help, state );\n}\n\n/* Sub-fn of below. Come back from a popdown notify.\n */\nstatic void\nidialog_popdown_notify( void *sys, iWindowResult result )\n{\n        iWindowSusp *susp = IWINDOW_SUSP( sys );\n\tiDialog *idlg = IDIALOG( susp->client );\n\n\tif( result == IWINDOW_YES ) \n\t\t/* If our caller hasn't been notified yet, post off a FALSE.\n\t\t */\n\t\tidialog_notify_parent( idlg, IWINDOW_NO );\n\n\t/* Pass result on to our suspension (ie. back to iwindow).\n\t */\n\tiwindow_susp_return( susp, result );\n\n\t/* Housekeeping.\n\t */\n\tiwindow_notify_return( IWINDOW( idlg ) );\n}\n\n/* Our popdown callback ... here from iwindow.\n */\nstatic void \nidialog_popdown_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys ) \n{\n\tiDialog *idlg = IDIALOG( client );\n        iWindowSusp *susp = iwindow_susp_new( NULL, iwnd, idlg, nfn, sys );\n\n#ifdef DEBUG\n\tprintf( \"idialog_popdown_cb: %s\\n\", IWINDOW( idlg )->title );\n#endif /*DEBUG*/\n\n\t/* Trigger user popdown.\n\t */\n\tiwindow_notify_send( IWINDOW( idlg ), \n\t\tidlg->popdown_cb, idlg->client, idialog_popdown_notify, susp );\n}\n\n/* Sub-fn of below. Come back from a done notify.\n */\nstatic void\nidialog_done_notify( void *sys, iWindowResult result )\n{\n\tiDialog *idlg = IDIALOG( sys );\n\n#ifdef DEBUG\n\tprintf( \"idialog_done_notify: %s\\n\", IWINDOW( idlg )->title );\n#endif /*DEBUG*/\n\n\tidialog_set_button_state( idlg, TRUE );\n\n\t/* If all ok, popdown and tell our parent.\n\t */\n\tif( result == IWINDOW_YES ) {\n\t\t/* Unless we're pinned up, that is.\n\t\t */\n\t\tif( !(idlg->tog_pin && \n\t\t\tgtk_toggle_button_get_active(\n\t\t\t\tGTK_TOGGLE_BUTTON( idlg->tog_pin ) )) ) {\n\t\t\tidialog_notify_parent( idlg, result );\n\t\t\tiwindow_kill( IWINDOW( idlg ) );\n\t\t}\n\t}\n\n\t/* Alert on failure.\n\t */\n\tif( result == IWINDOW_ERROR )\n\t\tiwindow_alert( GTK_WIDGET( idlg ), GTK_MESSAGE_ERROR );\n\n\t/* Clean up.\n\t */\n\tiwindow_notify_return( IWINDOW( idlg ) );\n}\n\n/* Make a DONE event happen. Used (for example) by the browse window to force\n * a done in the enclosing FSB on double click on icon. \n */\nvoid\nidialog_done_trigger( iDialog *idlg, int pos )\n{\n\tOKButton *ok = (OKButton *) g_slist_nth_data( idlg->ok_disp_l, pos );\n\n#ifdef DEBUG\n\tprintf( \"idialog_done_trigger: %s, %d\\n\", \n\t\tIWINDOW( idlg )->title, pos );\n#endif /*DEBUG*/\n\n\t/* Trigger user done callback.\n\t */\n\tg_assert( pos >= 0 );\n\tg_assert( ok->done_cb );\n\tidialog_set_button_state( idlg, FALSE );\n\tiwindow_notify_send( IWINDOW( idlg ), \n\t\tok->done_cb, idlg->client, idialog_done_notify, idlg );\n}\n\n/* Sub-fn of below.\n */\nstatic void\nidialog_cancel_notify( void *sys, iWindowResult result )\n{\n\tiDialog *idlg = IDIALOG( sys );\n\n#ifdef DEBUG\n\tprintf( \"idialog_cancel_notify: %s\\n\", IWINDOW( idlg )->title );\n#endif /*DEBUG*/\n\n\tidialog_set_button_state( idlg, TRUE );\n\n\t/* Send cancel message back to parent if our client cancel was OK.\n\t */\n\tif( result == IWINDOW_YES ) {\n\t\tidialog_notify_parent( idlg, IWINDOW_NO );\n\t\tiwindow_kill( IWINDOW( idlg ) );\n\t}\n\n\t/* Alert on error.\n\t */\n\tif( result == IWINDOW_ERROR )\n\t\tiwindow_alert( GTK_WIDGET( idlg ), GTK_MESSAGE_ERROR );\n\n\t/* Clean up.\n\t */\n\tiwindow_notify_return( IWINDOW( idlg ) );\n}\n\nstatic void\nidialog_cancel_trigger( iDialog *idlg )\n{\n#ifdef DEBUG\n        printf( \"idialog_cancel_trigger: %s\\n\", IWINDOW( idlg )->title );\n#endif /*DEBUG*/\n\n        /* Trigger user cancel function.\n         */\n\tidialog_set_button_state( idlg, FALSE );\n        iwindow_notify_send( IWINDOW( idlg ), \n\t\tidlg->cancel_cb, idlg->client, idialog_cancel_notify, idlg );\n}\n\n/* Button callbacks from gtk.\n */\nstatic void\nidialog_done_cb( GtkWidget *w, iDialog *idlg )\n{\n\tint pos = g_slist_index( idlg->ok_but_l, w );\n\n\tg_assert( pos != -1 );\n\n\tidialog_done_trigger( idlg, pos );\n}\n\nstatic void\nidialog_cancel_cb( GtkWidget *w, iDialog *idlg )\n{\n\tidialog_cancel_trigger( idlg );\n}\n\nstatic void\nidialog_help_cb( GtkWidget *w, iDialog *idlg )\n{\n\tif( idlg->help_tag )\n\t\tbox_help( GTK_WIDGET( idlg ), idlg->help_tag );\n}\n\nstatic void\nidialog_destroy( GtkObject *object )\n{\n\tiDialog *idlg;\n\n#ifdef DEBUG\n\tprintf( \"idialog_destroy\\n\" );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_IDIALOG( object ) );\n\n\tidlg = IDIALOG( object );\n\n#ifdef DEBUG\n\tprintf( \"... %s\\n\", IWINDOW( idlg )->title );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\n\tif( idlg->destroy_cb ) {\n\t\tidlg->destroy_cb( idlg, idlg->client );\n\t\tidlg->destroy_cb = NULL;\n\t}\n\n\tFREESID( idlg->destroy_sid, idlg->iobject );\n\tslist_map( idlg->ok_l, (SListMapFn) okbutton_free, NULL );\n\tIM_FREEF( g_slist_free, idlg->ok_l );\n\tIM_FREEF( g_slist_free, idlg->ok_disp_l );\n\tIM_FREEF( g_slist_free, idlg->ok_but_l );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\nidialog_realize( GtkWidget *widget )\n{\n\tiDialog *idlg = IDIALOG( widget );\n\n#ifdef DEBUG\n\tprintf( \"idialog_realize: %s\\n\", IWINDOW( idlg )->title );\n#endif /*DEBUG*/\n\n\tGTK_WIDGET_CLASS( parent_class )->realize( widget );\n\n\tif( idlg->entry )\n\t\tgtk_widget_grab_focus( GTK_WIDGET( idlg->entry ) );\n}\n\n/* The object we represent has been destroyed, kill us too.\n */\nstatic void\nidialog_iobject_destroy( iObject *iobject, iDialog *idlg )\n{\n#ifdef DEBUG\n\tprintf( \"idialog_iobject_destroy: %s\\n\", IWINDOW( idlg )->title );\n#endif /*DEBUG*/\n\n\t/* This object has gone.\n\t */\n\tidlg->iobject = NULL;\n\n\tiwindow_kill( IWINDOW( idlg ) );\n}\n\nstatic void *\nidialog_build_ok( OKButton *ok, iDialog *idlg )\n{\n\tGtkWidget *but;\n\n\tbut = build_button( ok->label, \n\t\tGTK_SIGNAL_FUNC( idialog_done_cb ), idlg );\n\tidlg->ok_disp_l = g_slist_prepend( idlg->ok_disp_l, ok );\n\tidlg->ok_but_l = g_slist_prepend( idlg->ok_but_l, but );\n\tgtk_box_pack_start( GTK_BOX( idlg->bb ), but, TRUE, TRUE, 0 );\n\tgtk_widget_show( but );\n\n\treturn( NULL );\n}\n\nstatic void *\nidialog_build_cancel( iDialog *idlg )\n{\n\tidlg->but_cancel = build_button( idlg->cancel_text,\n\t\tGTK_SIGNAL_FUNC( idialog_cancel_cb ), idlg );\n\tgtk_box_pack_start( GTK_BOX( idlg->bb ),\n\t\tidlg->but_cancel, TRUE, TRUE, 0 );\n\tgtk_widget_show( idlg->but_cancel );\n\n\treturn( NULL );\n}\n\n/* Set a button to be the dialog default. Turn off button_focus for complex\n * dialogs like file_chooser which have their on focus systems.\n */\nstatic void\nidialog_set_default( iDialog *idlg, GtkWidget *widget )\n{\n\tif( idlg->button_focus ) \n\t\tgtk_widget_grab_focus( widget );\n\n\tGTK_WIDGET_SET_FLAGS( widget, GTK_CAN_DEFAULT );\n\tgtk_window_set_default( GTK_WINDOW( idlg ), widget );\n}\n\nstatic void \nidialog_build( GtkWidget *widget )\n{\n\tiDialog *idlg = IDIALOG( widget );\n\tiWindow *iwnd = IWINDOW( idlg );\n\n#ifdef DEBUG\n\tprintf( \"idialog_build: %s\\n\", iwnd->title );\n#endif /*DEBUG*/\n\n\t/* Call all builds in superclasses.\n\t */\n\tif( IWINDOW_CLASS( parent_class )->build )\n\t\t(*IWINDOW_CLASS( parent_class )->build)( widget );\n\n\t/* delete_event and destroy handled by our superclass.\n\t */\n\tiwindow_set_popdown( iwnd, idialog_popdown_cb, idlg );\n\n        gtk_window_set_modal( GTK_WINDOW( idlg ), idlg->modal );\n\n        idlg->work = gtk_vbox_new( FALSE, 6 );\n        gtk_container_set_border_width( GTK_CONTAINER( idlg->work ), 12 );\n        gtk_box_pack_start( GTK_BOX( iwnd->work ), idlg->work, TRUE, TRUE, 0 );\n\n\tif( !idlg->nosep ) {\n\t\tGtkWidget *sep;\n\n\t\tsep = gtk_hseparator_new();\n\t\tgtk_box_pack_start( GTK_BOX( iwnd->work ), \n\t\t\tsep, FALSE, FALSE, 2 );\n\t\tgtk_widget_show( sep );\n\t}\n\n\tidlg->hb = gtk_hbox_new( FALSE, 6 );\n        gtk_container_set_border_width( GTK_CONTAINER( idlg->hb ), 12 );\n        gtk_box_pack_start( GTK_BOX( iwnd->work ), idlg->hb, FALSE, FALSE, 0 );\n        gtk_widget_show( idlg->hb );\n\n\tif( idlg->pinup ) {\n\t\tidlg->tog_pin = gtk_check_button_new_with_label( \n\t\t\t_( \"Pin up\" ) );\n\t\tset_tooltip( idlg->tog_pin, \n\t\t\t_( \"Check this to pin the dialog up\" ) );\n                gtk_box_pack_start( GTK_BOX( idlg->hb ),\n                        idlg->tog_pin, FALSE, FALSE, 0 );\n\t\tgtk_widget_show( idlg->tog_pin );\n\t}\n\n        idlg->bb = gtk_hbutton_box_new();\n        gtk_button_box_set_layout( GTK_BUTTON_BOX( idlg->bb ), \n\t\tGTK_BUTTONBOX_END );\n\tgtk_box_set_spacing( GTK_BOX( idlg->bb ), 6 );\n        gtk_box_pack_end( GTK_BOX( idlg->hb ), idlg->bb, FALSE, FALSE, 0 );\n        gtk_widget_show( idlg->bb );\n\n\t/* Default button order: \n\t *\n\t * Help        OK3 OK2 Cancel OK1\n\t *\n\t * win32 button order:\n\t *\n\t * OK1 OK2 OK3 Cancel Help\n\t */\n\n#ifdef OS_WIN32\n\n\t/* OK buttons.\n\t */\n\tslist_map( idlg->ok_l,\n\t\t(SListMapFn) idialog_build_ok, idlg );\n\n        if( idlg->cancel_cb ) {\n\t\tidialog_build_cancel( idlg );\n\n\t\t/* Cancel grabs default if it's the only button. Set focus\n\t\t * too; user build can change this later.\n\t\t */\n                if( !idlg->ok_l ) \n\t\t\tidialog_set_default( idlg, idlg->but_cancel );\n\t}\n\n        if( idlg->help_tag ) {\n                idlg->but_help = build_button( GTK_STOCK_HELP,\n\t\t\tGTK_SIGNAL_FUNC( idialog_help_cb ), idlg );\n                gtk_widget_show( idlg->but_help );\n        }\n\n#else /*!OS_WIN32*/\n\n        if( idlg->help_tag ) {\n                idlg->but_help = build_button( GTK_STOCK_HELP,\n\t\t\tGTK_SIGNAL_FUNC( idialog_help_cb ), idlg );\n                gtk_box_pack_end( GTK_BOX( idlg->bb ),\n                        idlg->but_help, TRUE, TRUE, 0 );\n\t\tgtk_button_box_set_child_secondary( GTK_BUTTON_BOX( idlg->bb ),\n\t\t\tidlg->but_help, TRUE );\n                gtk_widget_show( idlg->but_help );\n        }\n\n\t/* Add OK2, 3, etc.\n\t */\n\tif( idlg->ok_l && idlg->ok_l->next )\n\t\tslist_map_rev( idlg->ok_l->next,\n\t\t\t(SListMapFn) idialog_build_ok, idlg );\n\n        if( idlg->cancel_cb ) {\n\t\tidialog_build_cancel( idlg );\n\n\t\t/* Cancel grabs default if it's the only button. Set focus\n\t\t * too; user build can change this later.\n\t\t */\n                if( !idlg->ok_l ) \n\t\t\tidialog_set_default( idlg, idlg->but_cancel );\n\t}\n\n\t/* Make OK1\n\t */\n\tif( idlg->ok_l ) {\n\t\tOKButton *ok1 = (OKButton *) idlg->ok_l->data;\n\n\t\tidialog_build_ok( ok1, idlg );\n\t}\n\n#endif /*lots*/\n\n\t/* OK1 grabs the default.\n\t */\n\tif( idlg->ok_but_l ) \n\t\tidialog_set_default( idlg, idlg->ok_but_l->data );\n\n\t/* Escape triggers cancel, if there is a cancel.\n\t */\n\tif( idlg->cancel_cb )\n\t\tgtk_widget_add_accelerator( idlg->but_cancel,\n\t\t\t\"clicked\", iwnd->accel_group, GDK_Escape, 0, 0 );\n\telse {\n\t\t/* If there's just 1 OK, that gets Esc too.\n\t\t */\n\t\tif( idlg->ok_but_l &&\n\t\t\tg_slist_length( idlg->ok_but_l ) == 1 )\n\t\t\tgtk_widget_add_accelerator( \n\t\t\t\tGTK_WIDGET( idlg->ok_but_l->data ), \"clicked\", \n\t\t\t\tiwnd->accel_group, GDK_Escape, 0, 0 );\n\t}\n\n\t/* F1 triggers help.\n\t */\n\tif( idlg->but_help ) \n\t\tgtk_widget_add_accelerator( \n\t\t\tidlg->but_help,\n\t\t\t\"clicked\", iwnd->accel_group, GDK_F1, 0, 0 );\n\n\t/* Build user dialog contents.\n\t */\n\tif( idlg->build )\n\t\tidlg->build( iwnd, idlg->work, \n\t\t\tidlg->build_a, idlg->build_b, idlg->build_c );\n\n\tif( idlg->iobject )\n\t\tidlg->destroy_sid = g_signal_connect( idlg->iobject, \"destroy\", \n\t\t\tG_CALLBACK( idialog_iobject_destroy ), idlg );\n\n        gtk_widget_show( idlg->work );\n}\n\nstatic void\nidialog_class_init( iDialogClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tGtkWidgetClass *widget_class = (GtkWidgetClass *) class;\n\tiWindowClass *iwindow_class = (iWindowClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = idialog_destroy;\n\n\twidget_class->realize = idialog_realize;\n\n\tiwindow_class->build = idialog_build;\n\tiwindow_class->transient = TRUE;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n}\n\nstatic void\nidialog_init( iDialog *idlg )\n{\n#ifdef DEBUG\n\tprintf( \"idialog_init: %s\\n\", IWINDOW( idlg )->title );\n#endif /*DEBUG*/\n\n\t/* Init our instance fields.\n\t */\n\tidlg->iobject = NULL;\n        idlg->destroy_sid = 0;\n\n\tidlg->work = NULL;\n\n\tidlg->ok_l = NULL;\n\tidlg->ok_disp_l = NULL;\n\tidlg->ok_but_l = NULL;\n\n\tidlg->but_cancel = NULL;\n\tidlg->but_help = NULL;\n\tidlg->tog_pin = NULL;\n\n\tidlg->entry = NULL;\n\n\tidlg->modal = FALSE;\n\tidlg->pinup = FALSE;\n\tidlg->nosep = FALSE;\n\tidlg->button_focus = TRUE;\n\n\tidlg->help_tag = NULL;\n\n\tidlg->cancel_text = GTK_STOCK_CANCEL;\n\n\tidlg->cancel_cb = NULL;\n\tidlg->popdown_cb = NULL;\n\tidlg->destroy_cb = NULL;\n\tidlg->client = NULL;\n\n\tidlg->arg = NULL;\n\n\tidlg->nfn = iwindow_notify_null;\n\tidlg->sys = NULL;\n\n\tgtk_window_set_position( GTK_WINDOW( idlg ),\n\t\tGTK_WIN_POS_CENTER_ON_PARENT );\n}\n\nGtkType\nidialog_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"iDialog\",\n\t\t\tsizeof( iDialog ),\n\t\t\tsizeof( iDialogClass ),\n\t\t\t(GtkClassInitFunc) idialog_class_init,\n\t\t\t(GtkObjectInitFunc) idialog_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_IWINDOW, &info );\n\t}\n\n\treturn( type );\n}\n\nGtkWidget *\nidialog_new()\n{\n\tiDialog *idlg = gtk_type_new( TYPE_IDIALOG );\n\tGtkWindow *gwnd = GTK_WINDOW( idlg );\n\n\t/* Init gtk base class.\n\t */\n\tgwnd->type = GTK_WINDOW_TOPLEVEL;\n\n\treturn( GTK_WIDGET( idlg ) );\n}\n\nvoid \nidialog_set_iobject( iDialog *idlg, iObject *iobject )\n{\n\tidlg->iobject = iobject;\n}\n\nvoid \nidialog_set_pinup( iDialog *idlg, gboolean pinup )\n{\n\tidlg->pinup = pinup;\n\n\tif( idlg->tog_pin ) \n\t\tgtk_toggle_button_set_active( \n\t\t\tGTK_TOGGLE_BUTTON( idlg->tog_pin ), TRUE );\n}\n\nvoid \nidialog_set_modal( iDialog *idlg, gboolean modal )\n{\n\tidlg->modal = modal;\n}\n\nvoid \nidialog_set_nosep( iDialog *idlg, gboolean nosep )\n{\n\tidlg->nosep = nosep;\n}\n\nvoid \nidialog_set_button_focus( iDialog *idlg, gboolean button_focus )\n{\n\tidlg->button_focus = button_focus;\n}\n\nvoid \nidialog_set_help_tag( iDialog *idlg, const char *help_tag )\n{\n\tIM_SETSTR( idlg->help_tag, help_tag );\n}\n\nvoid \nidialog_set_callbacks( iDialog *idlg, \n\tiWindowFn cancel_cb, iWindowFn popdown_cb, \n\tiDialogFreeFn destroy_cb, void *client )\n{\n\tidlg->cancel_cb = cancel_cb;\n\tidlg->popdown_cb = popdown_cb;\n\tidlg->destroy_cb = destroy_cb;\n\tidlg->client = client;\n}\n\nvoid \nidialog_add_ok( iDialog *idlg, iWindowFn done_cb, const char *fmt, ... )\n{\n\tva_list ap;\n\tchar buf[1024];\n\n        va_start( ap, fmt );\n        (void) im_vsnprintf( buf, 1024, fmt, ap );\n        va_end( ap );\n\n\t/* So the last OK button added is the default one (and at the head of\n\t * the list). [OK1, OK2, OK3, OK4]\n\t */\n\tidlg->ok_l = g_slist_prepend( idlg->ok_l, \n\t\tokbutton_new( buf, done_cb ) );\n}\n\nvoid \nidialog_set_notify( iDialog *idlg, iWindowNotifyFn nfn, void *sys )\n{\n\tidlg->nfn = nfn;\n\tidlg->sys = sys;\n}\n\nvoid \nidialog_set_build( iDialog *idlg, \n\tiWindowBuildFn build, void *build_a, void *build_b, void *build_c )\n{\n\tidlg->build = build;\n\tidlg->build_a = build_a;\n\tidlg->build_b = build_b;\n\tidlg->build_c = build_c;\n}\n\nvoid \nidialog_set_cancel_text( iDialog *idlg, const char *cancel_text )\n{\n\tidlg->cancel_text = cancel_text;\n}\n\nvoid \nidialog_set_default_entry( iDialog *idlg, GtkEntry *entry )\n{\n\tgtk_entry_set_activates_default( entry, TRUE );\n\tidlg->entry = entry;\n}\n\n/* Set up an entry inside a dialog ... set tooltip, set start\n * value, link to OK button in enclosing dialog.\n */\nvoid\nidialog_init_entry( iDialog *idlg, GtkWidget *entry, \n\tconst char *tip, const char *fmt, ... )\n{\n\tva_list ap;\n\n\tva_start( ap, fmt );\n        set_gentryv( entry, fmt, ap );\n\tva_end( ap );\n        set_tooltip( entry, \"%s\", tip );\n\tidialog_set_default_entry( idlg, GTK_ENTRY( entry ) );\n}\n"
  },
  {
    "path": "src/idialog.h",
    "content": "/* make and manage dialogs ... subclass off this for dialog boxes\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#ifndef IDIALOG_H\n#define IDIALOG_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n#define TYPE_IDIALOG (idialog_get_type())\n#define IDIALOG( obj ) (GTK_CHECK_CAST( (obj), TYPE_IDIALOG, iDialog ))\n#define IDIALOG_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_IDIALOG, iDialogClass ))\n#define IS_IDIALOG( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IDIALOG ))\n#define IS_IDIALOG_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_IDIALOG ))\n\ntypedef struct _iDialog iDialog;\n\ntypedef void (*iDialogFreeFn)( iDialog *, void * );\n\nstruct _iDialog {\n\tiWindow parent_object;\n\n\t/* My instance vars.\n\t */\n\tiObject *iobject;\t\t/* Kill dialog if this obj goes */\n\tguint destroy_sid;\t\t/* Signal id for obj destroy */\n\n\tGtkWidget *work;\t\t/* Our work area */\n\tGtkWidget *hb;\t\t\t\n\tGtkWidget *bb;\n\n\tGSList *ok_l;\t\t\t/* List of OKbutton as set by user */\n\tGSList *ok_disp_l;\t\t/* List of OKbutton as displayed */\n\tGSList *ok_but_l;\t\t/* List of OK GtkButton as displayed */\n\n\tGtkWidget *but_cancel;\n\tGtkWidget *but_help;\n\tGtkWidget *tog_pin;\t\t/* Optional pinup widget */\n\n\tGtkEntry *entry;\t\t/* Last entry we added as default */\n\n\t/* Flags.\n\t */\n\tgboolean modal;\t\t\t/* Modal/non-modal */\n\tgboolean pinup;\t\t\t/* Stay up on OK */\n\tgboolean nosep;\t\t\t/* Suppress hseparator */\n\tgboolean button_focus;\t\t/* TRUE to focus buttons */\n\n\t/* Name of help tag ... if set, make a help button and link to display\n\t * of this.\n\t */\n\tchar *help_tag;\n\n\t/* What we label the cancel button as (if any). Usually\n\t * GTK_STOCK_CANCEL, but instant-apply dialogs should change this to\n\t * GTK_STOCK_CLOSE.\n\t */\n\tconst char *cancel_text;\n\n\t/* Per-instance build function.\n\t */\n\tiWindowBuildFn build;\n\tvoid *build_a, *build_b, *build_c;\n\n\t/* Our callbacks.\n\t */\n\tiWindowFn cancel_cb;\n\tiWindowFn popdown_cb;\n\tiDialogFreeFn destroy_cb;\t/* Called from _destroy() */\n\tvoid *client;\t\t\t/* Client data for callbacks */\n\n\tvoid *arg;\t\t\t/* Misc thing provided to client */\n\n\t/* Notify our parent when we finish.\n\t */\n\tiWindowNotifyFn nfn;\n\tvoid *sys;\n};\n\ntypedef struct _iDialogClass {\n\tiWindowClass parent_class;\n\n\t/* Our methods.\n\t */\n} iDialogClass;\n\nvoid idialog_free_client( iDialog *idlg, void *client );\n\nvoid idialog_set_ok_button_state( iDialog *idlg, gboolean state );\n\nGtkType idialog_get_type( void );\nGtkWidget *idialog_new( void );\n\nvoid idialog_set_iobject( iDialog *idlg, iObject *iobject );\nvoid idialog_set_modal( iDialog *, gboolean );\nvoid idialog_set_pinup( iDialog *idlg, gboolean pinup );\nvoid idialog_set_nosep( iDialog *, gboolean );\nvoid idialog_set_button_focus( iDialog *idlg, gboolean button_focus );\nvoid idialog_set_help_tag( iDialog *, const char *help_tag );\nvoid idialog_set_callbacks( iDialog *, \n\tiWindowFn cancel_cb, iWindowFn popdown_cb, \n\tiDialogFreeFn destroy_cb, void *client );\nvoid idialog_add_ok( iDialog *, iWindowFn done_cb, const char *fmt, ... )\n\t__attribute__((format(printf, 3, 4)));\nvoid idialog_set_notify( iDialog *, iWindowNotifyFn, void * );\nvoid idialog_set_build( iDialog *, iWindowBuildFn, void *, void *, void * );\nvoid idialog_set_cancel_text( iDialog *, const char *cancel_text );\nvoid idialog_set_default_entry( iDialog *idlg, GtkEntry *entry );\nvoid idialog_init_entry( iDialog *idlg, GtkWidget *entry, \n\tconst char *tip, const char *fmt, ... )\n\t__attribute__((format(printf, 4, 5)));\n\nvoid idialog_done_trigger( iDialog *idlg, int pos );\n\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n\n#endif /* IDIALOG_H */\n"
  },
  {
    "path": "src/iimage.c",
    "content": "/* an image class object in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic void\niimage_dispose( GObject *gobject )\n{\n\tiImage *iimage;\n\n#ifdef DEBUG\n\tprintf( \"iimage_dispose %p\\n\", gobject );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_IIMAGE( gobject ) );\n\n\tiimage = IIMAGE( gobject );\n\n\tslist_map( iimage->classmodels, \n\t\t(SListMapFn) classmodel_iimage_unlink, iimage );\n\tg_assert( !iimage->classmodels );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\niimage_finalize( GObject *gobject )\n{\n\tiImage *iimage;\n\n#ifdef DEBUG\n\tprintf( \"iimage_finalize\\n\" );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_IIMAGE( gobject ) );\n\n\tiimage = IIMAGE( gobject );\n\n\timage_value_destroy( &iimage->value );\n\tIM_FREEF( g_slist_free, iimage->views );\n\tvips_buf_destroy( &iimage->caption_buffer );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\n/* Return the main caption. \n */\nstatic const char *\niimage_generate_caption( iObject *iobject ) \n{\n\tiImage *iimage = IIMAGE( iobject );\n\tImageinfo *ii = iimage->value.ii;\n\tVipsBuf *buf = &iimage->caption_buffer;\n\n\tvips_buf_rewind( buf );\n\n\timage_value_caption( &iimage->value, buf );\n\n\tif( ii ) {\n\t\tvips_buf_appends( buf, \", \" );\n\t\tiobject_info( IOBJECT( iimage->value.ii ), buf );\n\t}\n\n\treturn( vips_buf_all( buf ) );\n}\n\nstatic void\niimage_info( iObject *iobject, VipsBuf *buf )\n{\n\tiImage *iimage = IIMAGE( iobject );\n\tImageinfo *ii = iimage->value.ii;\n\tIMAGE *im;\n\n\tif( ii && (im = imageinfo_get( FALSE, ii )) ) {\n\t\tchar *filename;\n\n\t\tif( im_header_get_typeof( im, ORIGINAL_FILENAME ) != 0 ) {\n\t\t\tif( !im_header_string( im, \n\t\t\t\tORIGINAL_FILENAME, &filename ) ) {\n\t\t\t\tvips_buf_appends( buf, \n\t\t\t\t\t_( \"Original filename\" ) );\n\t\t\t\tvips_buf_appendf( buf, \": %s\\n\", filename );\n\t\t\t}\n\t\t}\n\t}\n}\n\nstatic View *\niimage_view_new( Model *model, View *parent )\n{\n\treturn( iimageview_new() );\n}\n\nstatic void\niimage_edit( GtkWidget *parent, Model *model )\n{\n        iImage *iimage = IIMAGE( model );\n\n\tif( iimage->value.ii ) \n\t\t(void) imageview_new( iimage, parent );\n}\n\nvoid\niimage_header( GtkWidget *parent, Model *model )\n{\n        iImage *iimage = IIMAGE( model );\n\tRow *row = HEAPMODEL( iimage )->row;\n\tWorkspace *ws = row_get_workspace( row );\n\n\tGtkWidget *imageheader;\n\tchar txt[512];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\timageheader = imageheader_new( iimage );\n\trow_qualified_name_relative( ws->sym, row, &buf );\n\tiwindow_set_title( IWINDOW( imageheader ), \n\t\t_( \"Header for \\\"%s\\\"\" ), vips_buf_all( &buf ) );\n\tidialog_set_callbacks( IDIALOG( imageheader ), NULL, NULL, NULL, NULL );\n\tidialog_add_ok( IDIALOG( imageheader ), iwindow_true_cb, _( \"OK\" ) );\n\tiwindow_set_parent( IWINDOW( imageheader ), parent );\n\tidialog_set_iobject( IDIALOG( imageheader ), IOBJECT( iimage ) );\n\tiwindow_build( IWINDOW( imageheader ) );\n\n\tgtk_widget_show( imageheader );\n}\n\nstatic xmlNode *\niimage_save( Model *model, xmlNode *xnode )\n{\n\tiImage *iimage = IIMAGE( model );\n\txmlNode *xthis;\n\n\tif( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )\n\t\treturn( NULL );\n\n\t/* We always rebuild the value from the expr ... don't save.\n\t */\n\tif( !set_iprop( xthis, \"image_left\", iimage->image_left ) ||\n\t\t!set_iprop( xthis, \"image_top\", iimage->image_top ) ||\n\t\t!set_iprop( xthis, \"image_mag\", iimage->image_mag ) ||\n\t\t!set_sprop( xthis, \"show_status\",\n\t\t\tbool_to_char( iimage->show_status ) ) ||\n\t\t!set_sprop( xthis, \"show_paintbox\",\n\t\t\tbool_to_char( iimage->show_paintbox ) ) ||\n\t\t!set_sprop( xthis, \"show_convert\",\n\t\t\tbool_to_char( iimage->show_convert ) ) ||\n\t\t!set_sprop( xthis, \"show_rulers\",\n\t\t\tbool_to_char( iimage->show_rulers ) ) ||\n\t\t!set_dprop( xthis, \"scale\", iimage->scale ) ||\n\t\t!set_dprop( xthis, \"offset\", iimage->offset ) ||\n\t\t!set_sprop( xthis, \"falsecolour\", \n\t\t\tbool_to_char( iimage->falsecolour ) ) ||\n\t\t!set_sprop( xthis, \"type\", bool_to_char( iimage->type ) ) )\n\t\treturn( NULL );\n\n\treturn( xthis );\n}\n\nstatic gboolean\niimage_load( Model *model, \n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n        iImage *iimage = IIMAGE( model );\n\n\tg_assert( IS_RHS( parent ) );\n\n\t(void) get_iprop( xnode, \"image_left\", &iimage->image_left );\n\t(void) get_iprop( xnode, \"image_top\", &iimage->image_top );\n\t(void) get_iprop( xnode, \"image_mag\", &iimage->image_mag );\n\t(void) get_bprop( xnode, \"show_status\", &iimage->show_status );\n\t(void) get_bprop( xnode, \"show_paintbox\", &iimage->show_paintbox );\n\t(void) get_bprop( xnode, \"show_convert\", &iimage->show_convert );\n\t(void) get_bprop( xnode, \"show_rulers\", &iimage->show_rulers );\n\t(void) get_dprop( xnode, \"scale\", &iimage->scale );\n\t(void) get_dprop( xnode, \"offset\", &iimage->offset );\n\t(void) get_bprop( xnode, \"falsecolour\", &iimage->falsecolour );\n\t(void) get_bprop( xnode, \"type\", &iimage->type );\n\n\treturn( MODEL_CLASS( parent_class )->load( model, \n\t\tstate, parent, xnode ) );\n}\n\n/* Need to implement _update_heap(), as not all model fields are directly\n * editable ... some are set only from expr. See also iregion.c.\n */\nstatic void *\niimage_update_heap( Heapmodel *heapmodel )\n{\n\tExpr *expr = heapmodel->row->expr;\n        iImage *iimage = IIMAGE( heapmodel );\n\tImageValue *value = &iimage->value;\n\n\tPElement pe;\n\tImageinfo *ii;\n\n#ifdef DEBUG\n\tprintf( \"iimage_update_heap: \" );\n\trow_name_print( HEAPMODEL( iimage )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Read the heap into the model, over the top of the unapplied edits.\n\t */\n\tif( !class_get_exact( &expr->root, IOBJECT( heapmodel )->name, &pe ) )\n\t\treturn( FALSE );\n\tif( !class_get_member_image( &pe, MEMBER_VALUE, &ii ) )\n\t\treturn( FALSE );\n\timage_value_set( value, ii );\n\n\tIM_FREE( CLASSMODEL( iimage )->filename );\n\n        if( value->ii && imageinfo_is_from_file( value->ii ) ) \n                IM_SETSTR( CLASSMODEL( iimage )->filename, \n                        IOBJECT( value->ii )->name );\n\n\t/* Classmodel _update_heap() will do _instance_new() from the fixed up\n\t * model.\n\t */\n\treturn( HEAPMODEL_CLASS( parent_class )->update_heap( heapmodel ) );\n}\n\n/* Update iImage from heap.\n */\nstatic gboolean\niimage_class_get( Classmodel *classmodel, PElement *root )\n{\n        iImage *iimage = IIMAGE( classmodel );\n\tImageValue *value = &iimage->value;\n\n\tImageinfo *ii;\n\n#ifdef DEBUG\n\tprintf( \"iimage_class_get: \" );\n\trow_name_print( HEAPMODEL( iimage )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( !class_get_member_image( root, MEMBER_VALUE, &ii ) )\n\t\treturn( FALSE );\n\timage_value_set( value, ii );\n\n\t/* Try to update the filename for this row ... get from the meta if we\n\t * can.\n\t */\n\tIM_FREE( classmodel->filename );\n        if( ii ) {\n\t\tIMAGE *im;\n\t\tchar *filename;\n\n\t\tif( (im = imageinfo_get( FALSE, ii )) &&\n\t\t\tim_header_get_typeof( im, ORIGINAL_FILENAME ) != 0 ) {\n\t\t\tif( im_header_string( im, \n\t\t\t\tORIGINAL_FILENAME, &filename ) )\n\t\t\t\treturn( FALSE );\n\t\t}\n\t\telse if( imageinfo_is_from_file( ii ) )\n\t\t\tfilename = IOBJECT( ii )->name;\n\t\telse\n\t\t\tfilename = NULL;\n\n\t\tIM_SETSTR( classmodel->filename, filename ); \n\t}\n\n\treturn( CLASSMODEL_CLASS( parent_class )->class_get( \n\t\tclassmodel, root ) );\n}\n\n/* Make a new \"fn value\" application.\n */\nstatic gboolean\niimage_class_new( Classmodel *classmodel, PElement *fn, PElement *out )\n{\n\tHeap *heap = reduce_context->heap;\n        iImage *iimage = IIMAGE( classmodel );\n\tImageValue *value = &iimage->value;\n\n\tPElement rhs;\n\n#ifdef DEBUG\n\tprintf( \"iimage_class_new: \" );\n\trow_name_print( HEAPMODEL( iimage )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Make application nodes.\n\t */\n\theap_appl_init( out, fn );\n\tif( !heap_appl_add( heap, out, &rhs ) )\n\t\treturn( FALSE );\n\n\tPEPUTP( &rhs, ELEMENT_MANAGED, value->ii );\n\n\treturn( TRUE );\n}\n\nstatic gboolean\niimage_graphic_save( Classmodel *classmodel, \n\tGtkWidget *parent, const char *filename )\n{\n\tiImage *iimage = IIMAGE( classmodel );\n\tImageValue *value = &iimage->value;\n\tchar buf[FILENAME_MAX];\n\n\t/* Can't happen nested-ly, so a static is OK. \n\t */\n\tstatic GTimer *timer = NULL;\n\n\t/* We don't want $VAR etc. in the filename we pass down to the file\n\t * ops.\n\t */\n\tim_strncpy( buf, filename, FILENAME_MAX );\n\tpath_expand( buf );\n\n\t/* Append the mode string. This needs an expanded filename.\n\t */\n\tfilesel_add_mode( buf );\n\n\tif( !timer )\n\t\ttimer = g_timer_new();\n\tg_timer_reset( timer );\n\n\tif( value->ii )\n\t\tif( !imageinfo_write( value->ii, buf ) )\n\t\t\treturn( FALSE );\n\n\tmainw_recent_add( &mainw_recent_image, filename );\n\n\tif( main_option_time_save ) {\n\t\tdouble elapsed;\n\n\t\telapsed = g_timer_elapsed( timer, NULL );\n\t\terror_top( _( \"Save timer.\" ) );\n\t\terror_sub( _( \"Image save took %g seconds.\" ), elapsed );\n\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\ngboolean\niimage_replace( iImage *iimage, const char *filename )\n{\n\tRow *row = HEAPMODEL( iimage )->row;\n\tiText *itext = ITEXT( HEAPMODEL( iimage )->rhs->itext );\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tvips_buf_appends( &buf, \"Image_file \\\"\" );\n\tvips_buf_appendsc( &buf, TRUE, filename );\n\tvips_buf_appends( &buf, \"\\\"\" );\n\n\tif( itext_set_formula( itext, vips_buf_all( &buf ) ) ) {\n\t\titext_set_edited( itext, TRUE );\n\t\tworkspace_set_modified( row->ws, TRUE );\n\t\t(void) expr_dirty( row->expr, link_serial_new() );\n\n\t\tmainw_recent_add( &mainw_recent_image, filename );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic gboolean\niimage_graphic_replace( Classmodel *classmodel, \n\tGtkWidget *parent, const char *filename )\n{\n\treturn( iimage_replace( IIMAGE( classmodel ), filename ) );\n}\n\nstatic void\niimage_class_init( iImageClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tHeapmodelClass *heapmodel_class = (HeapmodelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->dispose = iimage_dispose;\n\tgobject_class->finalize = iimage_finalize;\n\n\tiobject_class->user_name = _( \"Image\" );\n\tiobject_class->generate_caption = iimage_generate_caption;\n\tiobject_class->info = iimage_info;\n\n\tmodel_class->view_new = iimage_view_new;\n\tmodel_class->edit = iimage_edit;\n\tmodel_class->header = iimage_header;\n\tmodel_class->save = iimage_save;\n\tmodel_class->load = iimage_load;\n\n\theapmodel_class->update_heap = iimage_update_heap;\n\n\tclassmodel_class->class_get = iimage_class_get;\n\tclassmodel_class->class_new = iimage_class_new;\n\n\tclassmodel_class->graphic_save = iimage_graphic_save;\n\tclassmodel_class->graphic_replace = iimage_graphic_replace;\n\n\tclassmodel_class->filetype = filesel_type_image;\n\tclassmodel_class->filetype_pref = \"IMAGE_FILE_TYPE\";\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\niimage_init( iImage *iimage )\n{\n\timage_value_init( &iimage->value, CLASSMODEL( iimage ) );\n\n\tiimage->classmodels = NULL;\n\n\tiimage->views = NULL;\n\n\tiimage->image_left = 0;\n\tiimage->image_top = 0;\n\tiimage->image_mag = 0;\n\n\tiimage->show_status = FALSE;\n\tiimage->show_paintbox = FALSE;\n\tiimage->show_convert = FALSE;\n\tiimage->show_rulers = FALSE;\n\n\tiimage->scale = 0.0;\n\tiimage->offset = 0.0;\n\tiimage->falsecolour = FALSE;\n\tiimage->type = TRUE;\n\n\tvips_buf_init_dynamic( &iimage->caption_buffer, MAX_LINELENGTH );\n\n\tiobject_set( IOBJECT( iimage ), CLASS_IMAGE, NULL );\n}\n\nGtkType\niimage_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( iImageClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) iimage_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( iImage ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) iimage_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"iImage\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/iimage.h",
    "content": "/* a ip image class in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_IIMAGE (iimage_get_type())\n#define IIMAGE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IIMAGE, iImage ))\n#define IIMAGE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_IIMAGE, iImageClass))\n#define IS_IIMAGE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IIMAGE ))\n#define IS_IIMAGE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IIMAGE ))\n#define IIMAGE_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_IIMAGE, iImageClass ))\n\nstruct _iImage {\n\tClassmodel parent_class;\n\n\t/* Class fields.\n\t */\n\tImageValue value;\n\n\t/* List of classmodel which have displays on us.\n\t */\n\tGSList *classmodels;\t\n\n\t/* List of popup imageview windows we've made. \n\t */\n\tGSList *views;\n\n\t/* Track display pos/size/etc. here.\n\t */\n\tint image_left, image_top;\t/* Scroll position */\n\tint image_mag;\t\t\t/* Scale */\n\n\t/* View attachments.\n\t */\n\tgboolean show_status;\n\tgboolean show_paintbox;\n\tgboolean show_convert;\n\tgboolean show_rulers;\t\n\n\t/* Bar settings we remember.\n\t */\n\tdouble scale, offset;\n\tgboolean falsecolour;\n\tgboolean type;\n\n\t/* Private ... build iobject caption here.\n\t */\n\tVipsBuf caption_buffer;\n};\n\ntypedef struct _iImageClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} iImageClass;\n\nGType iimage_get_type( void );\ngboolean iimage_replace( iImage *iimage, const char *filename );\nvoid iimage_header( GtkWidget *parent, Model *model );\n"
  },
  {
    "path": "src/iimageview.c",
    "content": "/* run the display for an image in a workspace \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GraphicviewClass *parent_class = NULL;\n\nstatic void\niimageview_realize( GtkWidget *widget )\n{\n\tGTK_WIDGET_CLASS( parent_class )->realize( widget );\n\n\t/* Mark us as a symbol drag-to widget. \n\t */\n\tset_symbol_drag_type( widget );\n}\n\nGtkWidget *\niimageview_drag_window_new( int width, int height )\n{\n\tGtkWidget *window;\n\n\twindow = gtk_window_new( GTK_WINDOW_POPUP );\n\tgtk_widget_set_app_paintable( GTK_WIDGET( window ), TRUE );\n\tgtk_widget_set_size_request( window, width, height );\n\tgtk_widget_realize( window );\n#ifdef HAVE_SET_OPACITY\n\tgdk_window_set_opacity( window->window, 0.5 );\n#endif /*HAVE_SET_OPACITY*/\n\n\treturn( window );\n}\n\nstatic void\niimageview_drag_begin( GtkWidget *widget, GdkDragContext *context )\n{\n\tiImageview *iimageview = IIMAGEVIEW( widget );\n\tConversion *conv = iimageview->conv;\n\tGtkWidget *window;\n\tImagedisplay *id;\n\n#ifdef DEBUG\n\tprintf( \"iimageview_drag_begin: \\n\" );\n#endif /*DEBUG*/\n\n\twindow = iimageview_drag_window_new( \n\t\tconv->canvas.width, conv->canvas.height );\n\tgtk_object_set_data_full( GTK_OBJECT( widget ),\n\t\t\"nip2-drag-window\", window,\n\t\t(GtkDestroyNotify) gtk_widget_destroy );\n\tid = imagedisplay_new( conv );\n\tgtk_container_add( GTK_CONTAINER( window ), GTK_WIDGET( id ) );\n\tgtk_widget_show( GTK_WIDGET( id ) );\n\tgtk_drag_set_icon_widget( context, window, -2, -2 );\n}\n\nstatic void\niimageview_drag_end( GtkWidget *widget, GdkDragContext *context )\n{\n#ifdef DEBUG\n\tprintf( \"iimageview_drag_end:\\n\" );\n#endif /*DEBUG*/\n\n\tgtk_object_set_data( GTK_OBJECT( widget ), \n\t\t\"nip2-drag-window\", NULL );\n}\n\nstatic void\niimageview_drag_data_get( GtkWidget *widget, GdkDragContext *context,\n\tGtkSelectionData *selection_data, guint info, guint time ) \n{\n#ifdef DEBUG\n\tprintf( \"iimageview_drag_data_get:\\n\" );\n#endif /*DEBUG*/\n\n\tif( info == TARGET_SYMBOL ) {\n\t\tiImageview *iimageview = IIMAGEVIEW( widget );\n\t\tiImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject );\n\t\tRow *row = HEAPMODEL( iimage )->row;\n\t\tchar txt[256];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\t/* Drag the fully-qualified row name.\n\t\t */\n\t\trow_qualified_name_relative( main_workspaceroot->sym, \n\t\t\trow, &buf );\n\t\tgtk_selection_data_set( selection_data,\n\t\t\tgdk_atom_intern( \"text/symbol\", FALSE ), 8, \n\t\t\t(guchar *) vips_buf_all( &buf ), \n\t\t\tstrlen( vips_buf_all( &buf ) ) );\n\t}\n}\n\nstatic void\niimageview_drag_data_received( GtkWidget *widget, GdkDragContext *context,\n\tgint x, gint y, GtkSelectionData *selection_data,\n\tguint info, guint time ) \n{\n\n#ifdef DEBUG\n\tprintf( \"iimageview_drag_data_received:\\n\" );\n#endif /*DEBUG*/\n\n\tif( info == TARGET_SYMBOL && selection_data->length > 0 && \n\t\tselection_data->format == 8 ) {\n\t\tconst char *from_row_path = (const char *) selection_data->data;\n\t\tiImageview *iimageview = IIMAGEVIEW( widget );\n\t\tiImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject );\n\t\tRow *row = HEAPMODEL( iimage )->row;\n\t\tRow *from_row;\n\n#ifdef DEBUG\n\t\tprintf( \" seen TARGET_SYMBOL \\\"%s\\\"\\n\", \n\t\t\tfrom_row_path );\n#endif /*DEBUG*/\n\n\t\t/* Block drags to ourselves ... pointless.\n\t\t */\n\t\tif( (from_row = row_parse_name( main_workspaceroot->sym,\n\t\t\tfrom_row_path )) && \n\t\t\tfrom_row != row ) {\n\t\t\tiText *itext = ITEXT( HEAPMODEL( iimage )->rhs->itext );\n\t\t\tchar txt[256];\n\t\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\t\t/* Qualify relative to us. We don't want to embed\n\t\t\t * workspace names unless we have to.\n\t\t\t */\n\t\t\tif( row->top_row->sym ) \n\t\t\t\trow_qualified_name_relative( row->top_row->sym, \n\t\t\t\t\tfrom_row, &buf );\n\n\t\t\tif( itext_set_formula( itext, vips_buf_all( &buf ) ) ) {\n\t\t\t\titext_set_edited( itext, TRUE );\n\t\t\t\t(void) expr_dirty( row->expr, \n\t\t\t\t\tlink_serial_new() );\n\t\t\t\tworkspace_set_modified( row->ws, TRUE );\n\t\t\t\tsymbol_recalculate_all();\n\t\t\t}\n\n\t\t\t/* Usually the drag-from row will be selected, very\n\t\t\t * annoying. Select the drag-to row.\n\t\t\t */\n\t\t\trow_select( row );\n\t\t}\n\t}\n}\n\n/* Not the same as model->edit :-( if this is a region, don't pop the region\n * edit box, pop a viewer on the image.\n */\nstatic void\niimageview_edit( GtkWidget *parent, iImageview *iimageview )\n{\n\tiImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject );\n\n\tif( IS_IREGION( iimage ) && iimage->value.ii ) \n\t\timageview_new( iimage, parent );\n\telse \n\t\tmodel_edit( parent, MODEL( iimage ) );\n}\n\nstatic void\niimageview_link( View *view, Model *model, View *parent )\n{\n\tiImageview *iimageview = IIMAGEVIEW( view );\n\n\tRowview *rview;\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\tif( (rview = ROWVIEW( parent->parent )) ) { \n\t\tRow *row = ROW( VOBJECT( rview )->iobject );\n\n\t\trowview_menu_attach( rview, GTK_WIDGET( iimageview->id ) );\n\n\t\tif( row->popup && row->top_row == row ) {\n\t\t\trow->popup = FALSE;\n\t\t\tiimageview_edit( GTK_WIDGET( view ), iimageview );\n\t\t}\n\t}\n}\n\nstatic void \niimageview_refresh( vObject *vobject )\n{\n\tiImageview *iimageview = IIMAGEVIEW( vobject );\n\tiImage *iimage = IIMAGE( vobject->iobject );\n\tRow *row = HEAPMODEL( iimage )->row;\n\n\tint w, h;\n\tgboolean enabled;\n\tdouble scale, offset;\n\tgboolean falsecolour, type;\n\n#ifdef DEBUG\n\tprintf( \"iimageview_refresh\\n\" );\n#endif /*DEBUG*/\n\n\tw = IM_MAX( GTK_WIDGET( iimageview->id )->requisition.width,\n\t\tDISPLAY_THUMBNAIL );\n\th = DISPLAY_THUMBNAIL;\n\tconversion_set_image( iimageview->conv, iimage->value.ii );\n\tgtk_widget_set_size_request( GTK_WIDGET( iimageview->id ), w, h );\n\tgtk_widget_queue_draw( GTK_WIDGET( iimageview->id ) );\n\n\tset_gcaption( iimageview->label, \"%s\", \n\t\tNN( IOBJECT( iimage )->caption ) );\n\n\t/* Set scale/offset for the thumbnail. Use the prefs setting, or if\n\t * there's a setting for this image, override with that.\n\t */\n\tenabled = DISPLAY_CONVERSION;\n\tscale = row->ws->scale;\n\toffset = row->ws->offset;\n\tfalsecolour = FALSE;\n\ttype = TRUE;\n\n\t/* If the image_width has been set, a viewer must have popped down and\n\t * set it, so the recorded settings must be valid.\n\t */\n\tif( MODEL( iimage )->window_width != -1 ) {\n\t\tenabled = iimage->show_convert;\n\t\tscale = iimage->scale;\n\t\toffset = iimage->offset;\n\t\tfalsecolour = iimage->falsecolour;\n\t\ttype = iimage->type;\n\t}\n\n\tconversion_set_params( iimageview->conv, \n\t\tenabled, scale, offset, falsecolour, type );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\niimageview_class_init( iImageviewClass *class )\n{\n\tGtkWidgetClass *widget_class = (GtkWidgetClass *) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\twidget_class->realize = iimageview_realize;\n\twidget_class->drag_begin = iimageview_drag_begin;\n\twidget_class->drag_end = iimageview_drag_end;\n\twidget_class->drag_data_get = iimageview_drag_data_get;\n\twidget_class->drag_data_received = iimageview_drag_data_received;\n\n\tvobject_class->refresh = iimageview_refresh;\n\n\tview_class->link = iimageview_link;\n}\n\nstatic void \niimageview_doubleclick_one_cb( GtkWidget *widget, GdkEvent *event, \n\tiImageview *iimageview )\n{\n\tHeapmodel *heapmodel = HEAPMODEL( VOBJECT( iimageview )->iobject );\n\tRow *row = heapmodel->row;\n\n\trow_select_modifier( row, event->button.state );\n}\n\nstatic void \niimageview_doubleclick_two_cb( GtkWidget *widget, GdkEvent *event, \n\tiImageview *iimageview )\n{\n\tiimageview_edit( widget, iimageview );\n}\n\nstatic gboolean\niimageview_filedrop( iImageview *iimageview, const char *file )\n{\n\tiImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject );\n\tgboolean result;\n\n\tif( (result = iimage_replace( iimage, file )) )\n\t\tsymbol_recalculate_all();\n\n\treturn( result );\n}\n\nstatic void\niimageview_tooltip_generate( GtkWidget *widget, \n\tVipsBuf *buf, iImageview *iimageview )\n{\n\tiImage *iimage = IIMAGE( VOBJECT( iimageview )->iobject );\n\tImageinfo *ii = iimage->value.ii;\n\tIMAGE *im = imageinfo_get( FALSE, ii );\n\n\tvips_buf_rewind( buf );\n\tvips_buf_appends( buf, vips_buf_all( &iimage->caption_buffer ) );\n\tif( im ) {\n\t\tdouble size = (double) im->Ysize * IM_IMAGE_SIZEOF_LINE( im );\n\n\t\tvips_buf_appends( buf, \", \" );\n\t\tvips_buf_append_size( buf, size );\n\t\tvips_buf_appendf( buf, \", %.3gx%.3g p/mm\", im->Xres, im->Yres );\n\t}\n}\n\nstatic void\niimageview_init( iImageview *iimageview )\n{\n\tGtkWidget *eb;\n\tGtkWidget *vbox;\n\n#ifdef DEBUG\n\tprintf( \"iimageview_init\\n\" );\n#endif /*DEBUG*/\n\n        eb = gtk_event_box_new();\n        gtk_box_pack_start( GTK_BOX( iimageview ), eb, FALSE, FALSE, 0 );\n\tvbox = gtk_vbox_new( FALSE, 0 );\n        gtk_container_add( GTK_CONTAINER( eb ), vbox );\n        gtk_widget_show( vbox );\n\n\tiimageview->conv = conversion_new( NULL );\n\tiimageview->conv->tile_size = 16;\n        iimageview->id = imagedisplay_new( iimageview->conv );\n\timagedisplay_set_shrink_to_fit( iimageview->id, TRUE );\n        gtk_box_pack_start( GTK_BOX( vbox ), \n\t\tGTK_WIDGET( iimageview->id ), FALSE, FALSE, 0 );\n\tgtk_widget_show( GTK_WIDGET( iimageview->id ) );\n\n\t/* Need these events in the enclosing workspaceview.\n\t */\n\tgtk_widget_add_events( GTK_WIDGET( iimageview->id ), \n\t\tGDK_POINTER_MOTION_MASK | \n\t\tGDK_POINTER_MOTION_HINT_MASK |\n\t\tGDK_BUTTON_PRESS_MASK | \n\t\tGDK_BUTTON_RELEASE_MASK ); \n\n\tiimageview->label = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( iimageview->label ), 0, 0.5 );\n        gtk_misc_set_padding( GTK_MISC( iimageview->label ), 2, 0 );\n        gtk_box_pack_start( GTK_BOX( vbox ), \n\t\tGTK_WIDGET( iimageview->label ), FALSE, FALSE, 0 );\n\tgtk_widget_show( GTK_WIDGET( iimageview->label ) );\n\n\t/* Set as file drop destination \n\t */\n\tfiledrop_register( GTK_WIDGET( iimageview ), \n\t\t(FiledropFunc) iimageview_filedrop, iimageview );\n\n\tdoubleclick_add( GTK_WIDGET( iimageview ), FALSE,\n\t\tDOUBLECLICK_FUNC( iimageview_doubleclick_one_cb ), iimageview,\n\t\tDOUBLECLICK_FUNC( iimageview_doubleclick_two_cb ), iimageview );\n\n        set_tooltip_generate( eb,\n\t\t(TooltipGenerateFn) iimageview_tooltip_generate, \n\t\tiimageview, NULL );\n\n\tgtk_widget_set_name( eb, \"caption_widget\" );\n        gtk_widget_show( GTK_WIDGET( eb ) );\n}\n\nGtkType\niimageview_get_type( void )\n{\n\tstatic GtkType iimageview_type = 0;\n\n\tif( !iimageview_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"iImageview\",\n\t\t\tsizeof( iImageview ),\n\t\t\tsizeof( iImageviewClass ),\n\t\t\t(GtkClassInitFunc) iimageview_class_init,\n\t\t\t(GtkObjectInitFunc) iimageview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tiimageview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info );\n\t}\n\n\treturn( iimageview_type );\n}\n\nView *\niimageview_new( void )\n{\n\tiImageview *iimageview = gtk_type_new( TYPE_IIMAGEVIEW );\n\n\treturn( VIEW( iimageview ) );\n}\n"
  },
  {
    "path": "src/iimageview.h",
    "content": "/* a iimageview in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_IIMAGEVIEW (iimageview_get_type())\n#define IIMAGEVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_IIMAGEVIEW, iImageview ))\n#define IIMAGEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_IIMAGEVIEW, iImageviewClass ))\n#define IS_IIMAGEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IIMAGEVIEW ))\n#define IS_IIMAGEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_IIMAGEVIEW ))\n\ntypedef struct _iImageview {\n\tGraphicview parent_object;\n\n        guint popup_sid;\t/* id for popup menu */\n\n\tImagedisplay *id;\n\tConversion *conv;\n\tGtkWidget *label;\n} iImageview;\n\ntypedef struct _iImageviewClass {\n\tGraphicviewClass parent_class;\n\n\t/* My methods.\n\t */\n} iImageviewClass;\n\nGtkWidget *iimageview_drag_window_new( int width, int height );\nGtkType iimageview_get_type( void );\nView *iimageview_new( void );\n"
  },
  {
    "path": "src/imagedisplay.c",
    "content": "/* Imagedisplay widget code ... display entire image, place this widget in a \n * scrolledwindow to get clipping/scrolling behaviour.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n/* Trace painting actions\n#define DEBUG_PAINT\n */\n\n/*\n#define DEBUG_GEO\n */\n\n#include \"ip.h\"\n\nenum {\n\tSIG_AREA_CHANGED,\t/* xywh area changed, canvas cods */\n\tSIG_LAST\n};\n\nstatic GtkDrawingAreaClass *parent_class = NULL;\n\nstatic guint imagedisplay_signals[SIG_LAST] = { 0 };\n\n/* Handy!\n */\nvoid\nimagedisplay_queue_draw_area( Imagedisplay *id, Rect *area )\n{\n#ifdef DEBUG_PAINT\n\tprintf( \"imagedisplay_queue_draw_area: \"\n\t\t\"left = %d, top = %d, width = %d, height = %d\\n\",\n\t\tarea->left, area->top, area->width, area->height );\n#endif /*DEBUG_PAINT*/\n\n\tgtk_widget_queue_draw_area( GTK_WIDGET( id ),\n\t\tarea->left, area->top, area->width, area->height ); \n}\n\n/* Repaint an area of the image.\n */\nstatic void\nimagedisplay_paint_image( Imagedisplay *id, Rect *area )\n{\n\tConversion *conv = id->conv;\n\n\tguchar *buf;\n\tint lsk;\n\n#ifdef DEBUG_PAINT\n\tg_print( \"imagedisplay_paint_image: at %d x %d, size %d x %d \",\n\t\tarea->left, area->top, area->width, area->height );\n\tgobject_print( G_OBJECT( id ) );\n#endif /*DEBUG_PAINT*/\n\n\t/* Request pixels. We ask the mask first, to get an idea of what's\n\t * currently in cache, then request tiles of pixels. We must always\n\t * request pixels, even if the mask is blank, because the request\n\t * will trigger a notify later which will reinvoke us.\n\t */\n\tif( conv->mreg &&\n\t\tim_prepare( conv->mreg, area ) ) {\n#ifdef DEBUG_PAINT\n\t\tprintf( \"imagedisplay_paint_image: mask paint error\\n\" );\n\t\tprintf( \"\\t%s\\n\", im_error_buffer() );\n#endif /*DEBUG_PAINT*/\n\n\t\treturn;\n\t}\n\tif( im_prepare( conv->ireg, area ) ) {\n#ifdef DEBUG_PAINT\n\t\tprintf( \"imagedisplay_paint_image: paint error\\n\" );\n\t\tprintf( \"\\t%s\\n\", im_error_buffer() );\n#endif /*DEBUG_PAINT*/\n\n\t\tim_error_clear();\n\n\t\treturn;\n\t}\n\n\t/* Is the mask all zero? Skip the paint.\n\t */\n\tif( conv->mreg ) {\n\t\tgboolean found;\n\t\tint x, y;\n\n\t\tbuf = (guchar *) \n\t\t\tIM_REGION_ADDR( conv->mreg, area->left, area->top );\n\t\tlsk = IM_REGION_LSKIP( conv->mreg );\n\t\tfound = FALSE;\n\n\t\tfor( y = 0; y < area->height; y++ ) {\n\t\t\tfor( x = 0; x < area->width; x++ )\n\t\t\t\tif( buf[x] ) {\n\t\t\t\t\tfound = TRUE;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\tif( found )\n\t\t\t\tbreak;\n\n\t\t\tbuf += lsk;\n\t\t}\n\n\t\tif( !found ) {\n#ifdef DEBUG_PAINT\n\t\t\tprintf( \"imagedisplay_paint_image: zero mask\\n\" );\n#endif /*DEBUG_PAINT*/\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/* Paint into window.\n\t */\n\n\tbuf = (guchar *) IM_REGION_ADDR( conv->ireg, area->left, area->top );\n\tlsk = IM_REGION_LSKIP( conv->ireg );\n\n\tif( conv->ireg->im->Bands == 3 )\n\t\tgdk_draw_rgb_image( GTK_WIDGET( id )->window,\n\t\t\tGTK_WIDGET( id )->style->white_gc,\n\t\t\tarea->left, area->top, area->width, area->height,\n\t\t\tGDK_RGB_DITHER_MAX,\n\t\t\tbuf, lsk );\n\telse if( conv->ireg->im->Bands == 1 )\n\t\tgdk_draw_gray_image( GTK_WIDGET( id )->window,\n\t\t\tGTK_WIDGET( id )->style->white_gc,\n\t\t\tarea->left, area->top, area->width, area->height,\n\t\t\tGDK_RGB_DITHER_MAX,\n\t\t\tbuf, lsk );\n}\n\n/* Paint an area with the background pattern.\n */\nstatic void\nimagedisplay_paint_background( Imagedisplay *id, Rect *expose )\n{\n#ifdef DEBUG_PAINT\n\tg_print( \"imagedisplay_paint_background: at %d x %d, size %d x %d\\n\",\n\t\texpose->left, expose->top, expose->width, expose->height );\n#endif /*DEBUG_PAINT*/\n\n\tgdk_draw_rectangle( GTK_WIDGET( id )->window, \n\t\tid->back_gc, TRUE,\n\t\texpose->left, expose->top, expose->width, expose->height );\n}\n\n/* Paint areas outside the image.\n */\nstatic void\nimagedisplay_paint_background_clipped( Imagedisplay *id, Rect *expose )\n{\n\tConversion *conv = id->conv;\n\tRect clip;\n\n#ifdef DEBUG_PAINT\n\tg_print( \"imagedisplay_paint_background_clipped: canvas %d x %d\\n\",\n\t\tconv->canvas.width, conv->canvas.height );\n#endif /*DEBUG_PAINT*/\n\n\t/* If the expose touches the image, we cut it into two parts:\n\t * everything to the right of the image, and everything strictly\n\t * below.\n\t */\n\tim_rect_intersectrect( expose, &conv->canvas, &clip );\n\tif( !im_rect_isempty( &clip ) ) {\n\t\tRect area;\n\n\t\tarea = *expose;\n\t\tarea.left = conv->canvas.width;\n\t\tarea.width -= clip.width;\n\t\tif( area.width > 0 )\n\t\t\timagedisplay_paint_background( id, &area );\n\n\t\tarea = *expose;\n\t\tarea.top = conv->canvas.height;\n\t\tarea.width = clip.width;\n\t\tarea.height -= clip.height;\n\t\tif( area.height > 0 )\n\t\t\timagedisplay_paint_background( id, &area );\n\t}\n\telse\n\t\timagedisplay_paint_background( id, expose );\n}\n\nstatic void\nimagedisplay_paint( Imagedisplay *id, Rect *area )\n{\n\tConversion *conv = id->conv;\n\tconst int tsize = conv->tile_size;\n\n\tRect clip;\n\tint xs, ys;\n\tint x, y;\n\n\t/* There's no image to paint.\n\t */\n\tif( !conv->ireg )\n\t\treturn;\n\n\t/* Clip non-image parts of the expose.\n\t */\n\tim_rect_intersectrect( area, &conv->canvas, &clip );\n\tif( im_rect_isempty( &clip ) )\n\t\treturn;\n\n#ifdef DEBUG_PAINT\n\tg_print( \"imagedisplay_paint: at %d x %d, size %d x %d\\n\",\n\t\tclip.left, clip.top, clip.width, clip.height );\n#endif /*DEBUG_PAINT*/\n\n\t/* Round left/top down to the start tile.\n\t */\n\txs = (clip.left / tsize) * tsize;\n\tys = (clip.top / tsize) * tsize;\n\n\t/* Now loop painting image tiles.\n\t */\n\tfor( y = ys; y < IM_RECT_BOTTOM( &clip ); y += tsize )\n\t\tfor( x = xs; x < IM_RECT_RIGHT( &clip ); x += tsize ) {\n\t\t\tRect tile;\n\t\t\tRect tile2;\n\n\t\t\ttile.left = x;\n\t\t\ttile.top = y;\n\t\t\ttile.width = conv->tile_size;\n\t\t\ttile.height = conv->tile_size;\n\t\t\tim_rect_intersectrect( &tile, &clip, &tile2 );\n\n\t\t\timagedisplay_paint_image( id, &tile2 );\n\t\t}\n}\n\n/* Expose signal handler.\n */\nstatic gint\nimagedisplay_expose( GtkWidget *widget, GdkEventExpose *event )\n{\n\tImagedisplay *id = IMAGEDISPLAY( widget );\n\n\tGdkRectangle *rect;\n\tint i, n;\n\n\tif( !GTK_WIDGET_DRAWABLE( id ) ||\n\t\tevent->area.width == 0 || \n\t\tevent->area.height == 0 ||\n\t\t!GTK_WIDGET( id )->window ||\n\t\t!GTK_WIDGET_VISIBLE( id ) )\n\t\treturn( FALSE );\n\n\tgdk_region_get_rectangles( event->region, &rect, &n );\n#ifdef DEBUG_PAINT\n\tg_print( \"imagedisplay_expose: %d rectangles\\n\", n ); \n#endif /*DEBUG_PAINT*/\n\tfor( i = 0; i < n; i++ ) {\n\t\tRect area;\n\n\t\tarea.left = rect[i].x;\n\t\tarea.top = rect[i].y;\n\t\tarea.width = rect[i].width;\n\t\tarea.height = rect[i].height;\n\n\t\t/* Clear to background. Always do this, to make sure we paint \n\t\t * outside the image area.\n\t\t */\n\t\timagedisplay_paint_background_clipped( id, &area );\n\n\t\t/* And paint pixels.\n\t\t */\n\t\timagedisplay_paint( id, &area );\n\t}\n\tg_free( rect );\n\n        return( FALSE );\n}\n\n/* Resize signal.\n */\nstatic gboolean\nimagedisplay_configure_event( GtkWidget *widget, GdkEventConfigure *event )\n{\n\tImagedisplay *id = IMAGEDISPLAY( widget );\n\n#ifdef DEBUG_GEO\n\tg_print( \"imagedisplay_configure_event: %d x %d:\\n\", \n\t\tevent->width, event->height );\n#endif /*DEBUG_GEO*/\n\n\t/* Note new size in visible hint. Except if parent is a viewport ...\n\t * if it's a viewport, someone else will have to track the visible\n\t * area.\n\t */\n\tif( !GTK_IS_VIEWPORT( gtk_widget_get_parent( widget ) ) ) { \n\t\tid->conv->visible.width = event->width;\n\t\tid->conv->visible.height = event->height;\n\t}\n\n\t/* Recalculate shrink to fit, if necessary.\n\t */\n\tif( id->shrink_to_fit ) {\n#ifdef DEBUG_GEO\n\t\tg_print( \"imagedisplay_configure_event_cb: shrink-to-fit\\n\" );\n#endif /*DEBUG_GEO*/\n\n\t\tconversion_set_mag( id->conv, 0 );\n\t}\n\n        return( FALSE );\n}\n\nstatic void\nimagedisplay_destroy( GtkObject *object )\n{\n\tImagedisplay *id = IMAGEDISPLAY( object );\n\n#ifdef DEBUG\n\tg_print( \"imagedisplay_destroy: \" );\n\tgobject_print( G_OBJECT( id ) );\n#endif /*DEBUG*/\n\n\tFREESID( id->changed_sid, id->conv );\n\tFREESID( id->area_changed_sid, id->conv );\n\tUNREF( id->conv );\n\n\tUNREF( id->back_gc );\n\tUNREF( id->top_gc );\n\tUNREF( id->bottom_gc );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\n/* Conversion has changed ... resize to fit.\n */\nstatic void\nimagedisplay_real_conversion_changed( Imagedisplay *id )\n{\n\tGtkRequisition *requisition = &GTK_WIDGET( id )->requisition;\n\tRect *canvas = &id->conv->canvas;\n\n\tg_assert( IS_IMAGEDISPLAY( id ) );\n\n#ifdef DEBUG\n\tg_print( \"imagedisplay_real_conversion_changed: \" );\n\tgobject_print( G_OBJECT( id ) );\n#endif /*DEBUG*/\n\n\t/* If we're in shrink-to-fit mode, do a shrink.\n\t * Otherwise resize to hold the new image.\n\t */\n\tif( id->shrink_to_fit )\n\t\tconversion_set_mag( id->conv, 0 );\n\telse if( requisition->width != canvas->width ||\n\t\trequisition->height != canvas->height ) {\n#ifdef DEBUG_GEO\n\t\tg_print( \"imagedisplay_real_conversion_\"\n\t\t\t\"changed: requesting new size \"\n\t\t\t\"%d x %d\\n\",\n\t\t\tid->conv->canvas.width,\n\t\t\tid->conv->canvas.height );\n#endif /*DEBUG_GEO*/\n\n\t\trequisition->width = canvas->width;\n\t\trequisition->height = canvas->height;\n\t\tgtk_widget_queue_resize( GTK_WIDGET( id ) );\n\t}\n}\n\nstatic void\nimagedisplay_real_area_changed( Imagedisplay *id, Rect *dirty )\n{\n\timagedisplay_queue_draw_area( id, dirty );\n}\n\nstatic void\nimagedisplay_realize( GtkWidget *widget )\n{\n\tImagedisplay *id = IMAGEDISPLAY( widget );\n\n\tGdkColor fg, bg;\n\n\tGTK_WIDGET_CLASS( parent_class )->realize( widget );\n\n\tgdk_window_set_back_pixmap( widget->window, NULL, FALSE );\n\tgtk_widget_set_double_buffered( widget, FALSE );\n\n\tid->back_gc = gdk_gc_new( widget->window );\n\tfg.red = fg.green = fg.blue = 0x90 << 8;\n\tbg.red = bg.green = bg.blue = 0xA0 << 8;\n\tgdk_gc_set_rgb_fg_color( id->back_gc, &fg );\n\tgdk_gc_set_rgb_bg_color( id->back_gc, &bg );\n\n\tid->top_gc = gdk_gc_new( widget->window );\n\tid->bottom_gc = gdk_gc_new( widget->window );\n}\n\n/* Init Imagedisplay class.\n */\nstatic void\nimagedisplay_class_init( ImagedisplayClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n        GtkWidgetClass *widget_class = (GtkWidgetClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n        object_class->destroy = imagedisplay_destroy;\n\n\twidget_class->expose_event = imagedisplay_expose;\n\twidget_class->configure_event = imagedisplay_configure_event;\n\twidget_class->realize = imagedisplay_realize;\n\n\tclass->conversion_changed = imagedisplay_real_conversion_changed;\n\tclass->area_changed = imagedisplay_real_area_changed;\n\n\timagedisplay_signals[SIG_AREA_CHANGED] = g_signal_new( \"area_changed\",\n\t\tG_OBJECT_CLASS_TYPE( class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ImagedisplayClass, area_changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__POINTER,\n\t\tG_TYPE_NONE, 1,\n\t\tG_TYPE_POINTER );\n}\n\nstatic void\nimagedisplay_init( Imagedisplay *id )\n{\n\tid->conv = NULL;\n\tid->changed_sid = 0;\n\tid->area_changed_sid = 0;\n\tid->shrink_to_fit = FALSE;\n\n\tid->back_gc = NULL;\n\tid->top_gc = NULL;\n\tid->bottom_gc = NULL;\n}\n\nGType\nimagedisplay_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ImagedisplayClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) imagedisplay_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Imagedisplay ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) imagedisplay_init,\n\t\t};\n\n\t\ttype = g_type_register_static( GTK_TYPE_DRAWING_AREA, \n\t\t\t\"Imagedisplay\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\n/* Conversion has changed ... repaint everything.\n */\nstatic void\nimagedisplay_conversion_changed_cb( Conversion *conv, Imagedisplay *id )\n{\n#ifdef DEBUG\n\tprintf( \"imagedisplay_conversion_changed_cb: \" );\n\tgobject_print( G_OBJECT( id ) );\n#endif /*DEBUG*/\n\n\tIMAGEDISPLAY_GET_CLASS( id )->conversion_changed( id );\n\n\tg_signal_emit( G_OBJECT( id ), \n\t\timagedisplay_signals[SIG_AREA_CHANGED], 0, &conv->canvas );\n}\n\n/* Part of the repaint has changed. \n */\nstatic void\nimagedisplay_conversion_area_changed_cb( Conversion *conv, \n\tRect *dirty, Imagedisplay *id )\n{\n#ifdef DEBUG\n\tprintf( \"imagedisplay_conversion_area_changed_cb: \" \n\t\t\"left = %d, top = %d, width = %d, height = %d, \",\n\t\tdirty->left, dirty->top, dirty->width, dirty->height );\n\tgobject_print( G_OBJECT( id ) );\n#endif /*DEBUG*/\n\n\tg_signal_emit( G_OBJECT( id ), \n\t\timagedisplay_signals[SIG_AREA_CHANGED], 0, dirty );\n}\n\n/* Install a conversion. Only allow this once.\n */\nvoid\nimagedisplay_set_conversion( Imagedisplay *id, Conversion *conv )\n{\n\tg_assert( !id->conv );\n\n\tif( conv ) {\n\t\tid->conv = conv;\n\t\tid->changed_sid = g_signal_connect( id->conv, \"changed\", \n\t\t\tG_CALLBACK( imagedisplay_conversion_changed_cb ), id );\n\t\tid->area_changed_sid = g_signal_connect( id->conv, \n\t\t\t\"area_changed\", \n\t\t\tG_CALLBACK( imagedisplay_conversion_area_changed_cb ), \n\t\t\tid );\n\t\tg_object_ref( G_OBJECT( conv ) );\n\t\tiobject_sink( IOBJECT( conv ) );\n\n\t\t/* Trigger a change on the conv so we update.\n\t\t */\n\t\tiobject_changed( IOBJECT( conv ) );\n\t}\n}\n\n/* Make a new Imagedisplay. Pass in the conversion we should show, conv can\n * be NULL ... wait for one to be installed.\n */\nImagedisplay *\nimagedisplay_new( Conversion *conv )\n{\n\tImagedisplay *id = g_object_new( TYPE_IMAGEDISPLAY, NULL );\n\n#ifdef DEBUG\n\tg_print( \"imagedisplay_new: \" );\n\tgobject_print( G_OBJECT( id ) );\n#endif /*DEBUG*/\n\n\timagedisplay_set_conversion( id, conv );\n\n\treturn( id );\n}\n\nvoid \nimagedisplay_set_shrink_to_fit( Imagedisplay *id, gboolean shrink_to_fit )\n{\n\tid->shrink_to_fit = shrink_to_fit;\n\n\tif( shrink_to_fit )\n\t\tconversion_set_mag( id->conv, 0 );\n}\n"
  },
  {
    "path": "src/imagedisplay.h",
    "content": "/* Imagedisplay widget stuff.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_IMAGEDISPLAY (imagedisplay_get_type())\n#define IMAGEDISPLAY( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IMAGEDISPLAY, Imagedisplay ))\n#define IMAGEDISPLAY_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_IMAGEDISPLAY, ImagedisplayClass))\n#define IS_IMAGEDISPLAY( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IMAGEDISPLAY ))\n#define IS_IMAGEDISPLAY_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEDISPLAY ))\n#define IMAGEDISPLAY_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), \\\n\t\tTYPE_IMAGEDISPLAY, ImagedisplayClass ))\n\n/* Display an entire image. Put in a scrolled window to see just part of it.\n */\nstruct _Imagedisplay {\n\tGtkDrawingArea parent_object;\n\n\t/* Image we display.\n\t */\n\tConversion *conv;\t\t/* Conversion we display */\n\tguint changed_sid;\t\t/* Watch conv with these */\n\tguint area_changed_sid; \n\tgboolean shrink_to_fit; \t/* Auto-shrink mode */\n\n\t/* GCs also used by region paint.\n\t */\n\tGdkGC *back_gc;\n\tGdkGC *top_gc;\n\tGdkGC *bottom_gc;\n};\n\n/* Class structure.\n */\ntypedef struct _ImagedisplayClass {\n\t/* Drawing area we paint in.\n\t */\n\tGtkDrawingAreaClass parent_class;\n\n\t/* Virtual methods.\n\t */\n\tvoid (*conversion_changed)( Imagedisplay * );\n\tvoid (*area_changed)( Imagedisplay *, Rect * );\n} ImagedisplayClass;\n\nvoid imagedisplay_queue_draw_area( Imagedisplay *id, Rect *area );\nGType imagedisplay_get_type( void );\nvoid imagedisplay_set_conversion( Imagedisplay *id, Conversion *conv );\nImagedisplay *imagedisplay_new( Conversion *conv );\nvoid imagedisplay_set_shrink_to_fit( Imagedisplay *id, gboolean shrink_to_fit );\n"
  },
  {
    "path": "src/imageheader.c",
    "content": "/* display an image header\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk \n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic iDialogClass *imageheader_parent_class = NULL;\n\n/* Our columns.\n */\nenum {\n\tNAME_COLUMN,\t\t\n\tVALUE_COLUMN,\t\n\tN_COLUMNS\n};\n\nstatic void\nimageheader_destroy( GtkObject *object )\n{\n\tImageheader *imageheader;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_IMAGEHEADER( object ) );\n\n\timageheader = IMAGEHEADER( object );\n\n\t/* My instance destroy stuff.\n\t */\n\tUNREF( imageheader->store );\n\n\tif( GTK_OBJECT_CLASS( imageheader_parent_class )->destroy )\n\t\tGTK_OBJECT_CLASS( imageheader_parent_class )->destroy( object );\n}\n\nstatic void *\nimageheader_add_item( IMAGE *im, \n\tconst char *field, GValue *value, Imageheader *imageheader )\n{\n\tchar txt[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tGtkTreeIter iter;\n\n\t/* Show the nicks for enums.\n\t */\n\tif( G_VALUE_HOLDS_ENUM( value ) ) \n\t\tvips_buf_appendf( &buf, \"%s\", \n\t\t\tvips_enum_nick( G_VALUE_TYPE( value ), \n\t\t\t\tg_value_get_enum( value ) ) );\n\telse {\n\t\tchar *value_str;\n\n\t\tvalue_str = g_strdup_value_contents( value );\n\t\tvips_buf_appendf( &buf, \"%s\", value_str );\n\t\tg_free( value_str );\n\t}\n\n\tgtk_list_store_append( imageheader->store, &iter );\n\tgtk_list_store_set( imageheader->store, &iter,\n\t\tNAME_COLUMN, field,\n\t\tVALUE_COLUMN, vips_buf_all( &buf ),\n\t\t-1 );\n\n\treturn( NULL );\n}\n\nstatic void\nimageheader_refresh( Imageheader *imageheader )\n{\n\tgtk_list_store_clear( imageheader->store );\n\n\tif( imageheader->iimage && \n\t\timageheader->iimage->value.ii ) {\n\t\tImageinfo *ii = imageheader->iimage->value.ii;\n\t\tIMAGE *im = imageinfo_get( FALSE, ii );\n\n\t\tim_header_map( im, \n\t\t\t(im_header_map_fn) imageheader_add_item,\n\t\t\timageheader );\n\n\t\tgtk_text_buffer_set_text( \n\t\t\tgtk_text_view_get_buffer( \n\t\t\t\tGTK_TEXT_VIEW( imageheader->history ) ),\n\t\t\tim_history_get( im ), -1 );\n\t}\n\telse {\n\t\tgtk_editable_delete_text( GTK_EDITABLE( imageheader->history ),\n\t\t\t0, -1 );\n\t}\n}\n\nstatic void\nimageheader_entry_changed_cb( GtkEditable *editable, \n\tImageheader *imageheader )\n{\n\tgtk_tree_model_filter_refilter( \n\t\tGTK_TREE_MODEL_FILTER( imageheader->filter ) );\n}\n\nstatic gboolean\nimageheader_visible_func( GtkTreeModel *model, GtkTreeIter *iter, \n\tgpointer data )\n{\n\tImageheader *imageheader = IMAGEHEADER( data );\n\tconst char *text = gtk_entry_get_text( \n\t\tGTK_ENTRY( imageheader->entry ) );\n\tchar *name;\n\tchar *value;\n\tgboolean found;\n\n\tfound = FALSE;\n\n\tgtk_tree_model_get( model, iter, NAME_COLUMN, &name, -1 );\n\tif( name ) {\n\t\tfound = my_strcasestr( name, text ) != NULL;\n\t\tg_free( name );\n\t}\n\n\tif( found )\n\t\treturn( TRUE );\n\n\tgtk_tree_model_get( model, iter, VALUE_COLUMN, &value, -1 );\n\tif( value ) {\n\t\tfound = my_strcasestr( value, text ) != NULL;\n\t\tg_free( value );\n\t}\n\n\treturn( found );\n}\n\nstatic void\nimageheader_build( GtkWidget *widget )\n{\n\tImageheader *imageheader = IMAGEHEADER( widget );\n\tiDialog *idlg = IDIALOG( widget );\n\tGtkCellRenderer *renderer;\n\tGtkTreeViewColumn *column;\n\n\tGtkWidget *top;\n\tGtkWidget *label;\n\tGtkWidget *swin;\n\tGtkWidget *pane;\n\tGtkWidget *vbox;\n\tPangoFontDescription *font_desc;\n\n#ifdef DEBUG\n\tprintf( \"imageheader_build: %s\\n\", IWINDOW( imageheader )->title );\n#endif /*DEBUG*/\n\n\t/* Call all builds in superclasses.\n\t */\n\tif( IWINDOW_CLASS( imageheader_parent_class )->build )\n\t\t(*IWINDOW_CLASS( imageheader_parent_class )->build)( widget );\n\n\tpane = gtk_vpaned_new();\n        gtk_box_pack_start( GTK_BOX( idlg->work ), pane, TRUE, TRUE, 2 );\n\n\tvbox = gtk_vbox_new( FALSE, 2 );\n\tgtk_paned_pack1( GTK_PANED( pane ), vbox, TRUE, FALSE );\n\n\ttop = gtk_hbox_new( FALSE, 12 );\n        gtk_box_pack_start( GTK_BOX( vbox ), top, FALSE, FALSE, 2 );\n\n\timageheader->entry = gtk_entry_new();\n        gtk_signal_connect( GTK_OBJECT( imageheader->entry ), \"changed\", \n\t\tGTK_SIGNAL_FUNC( imageheader_entry_changed_cb ), \n\t\timageheader );\n\tgtk_box_pack_end( GTK_BOX( top ), \n\t\timageheader->entry, FALSE, FALSE, 2 );\n\n\tlabel = gtk_image_new_from_stock( GTK_STOCK_FIND, GTK_ICON_SIZE_MENU );\n\tgtk_box_pack_end( GTK_BOX( top ), label, FALSE, FALSE, 0 );\n\n\tswin = gtk_scrolled_window_new( NULL, NULL );\n        gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ),\n\t\tGTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );\n        gtk_box_pack_start( GTK_BOX( vbox ), swin, TRUE, TRUE, 2 );\n\n\timageheader->store = gtk_list_store_new( N_COLUMNS, \n\t\tG_TYPE_STRING, \n\t\tG_TYPE_STRING );\n\n\timageheader->filter = gtk_tree_model_filter_new( \n\t\tGTK_TREE_MODEL( imageheader->store ), NULL );\n\tgtk_tree_model_filter_set_visible_func( \n\t\tGTK_TREE_MODEL_FILTER( imageheader->filter ), \n\t\timageheader_visible_func, imageheader, NULL );\n\n\timageheader->tree = gtk_tree_view_new_with_model( \n\t\tGTK_TREE_MODEL( imageheader->filter ) );\n\tgtk_tree_view_set_rules_hint( GTK_TREE_VIEW( imageheader->tree ),\n\t\tTRUE );\n\tgtk_container_add( GTK_CONTAINER( swin ), imageheader->tree );\n\n\trenderer = gtk_cell_renderer_text_new();\n\tcolumn = gtk_tree_view_column_new_with_attributes( _( \"Field\" ),\n\t\t   renderer, \"text\", NAME_COLUMN, NULL );\n\tgtk_tree_view_column_set_resizable( column, TRUE );\n\tgtk_tree_view_append_column( GTK_TREE_VIEW( imageheader->tree ), \n\t\tcolumn );\n\n\trenderer = gtk_cell_renderer_text_new();\n\tcolumn = gtk_tree_view_column_new_with_attributes( _( \"Value\" ),\n\t\t   renderer, \"text\", VALUE_COLUMN, NULL );\n\tgtk_tree_view_column_set_resizable( column, TRUE );\n\tgtk_tree_view_append_column( GTK_TREE_VIEW( imageheader->tree ), \n\t\tcolumn );\n\n\tvbox = gtk_vbox_new( FALSE, 2 );\n\tgtk_paned_pack2( GTK_PANED( pane ), vbox, TRUE, FALSE );\n\tlabel = gtk_label_new( _( \"Image history\" ) );\n\tgtk_misc_set_alignment( GTK_MISC( label ), 0.0, 0.5 );\n        gtk_box_pack_start( GTK_BOX( vbox ), label, FALSE, FALSE, 2 );\n\tswin = gtk_scrolled_window_new( NULL, NULL );\n\tgtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ),\n\t\tGTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );\n        gtk_box_pack_end( GTK_BOX( vbox ), swin, TRUE, TRUE, 2 );\n\timageheader->history = gtk_text_view_new();\n\tgtk_text_view_set_editable( GTK_TEXT_VIEW( imageheader->history ), \n\t\tFALSE );\n\tgtk_text_view_set_cursor_visible( GTK_TEXT_VIEW( imageheader->history ),\n\t\tFALSE );\n\tfont_desc = pango_font_description_from_string( \"Monospace\" );\n\tgtk_widget_modify_font( imageheader->history, font_desc );\n\tpango_font_description_free( font_desc );\n\tgtk_container_add( GTK_CONTAINER( swin ), imageheader->history );\n\n\timageheader_refresh( imageheader );\n\n        gtk_window_set_default_size( GTK_WINDOW( imageheader ), 550, 550 );\n\tgtk_paned_set_position( GTK_PANED( pane ), 350 );\n\n\tgtk_widget_show_all( idlg->work );\n}\n\nstatic void\nimageheader_class_init( ImageheaderClass *class )\n{\n\tGtkObjectClass *object_class;\n\tiWindowClass *iwindow_class;\n\n\tobject_class = (GtkObjectClass *) class;\n\tiwindow_class = (iWindowClass *) class;\n\n\tobject_class->destroy = imageheader_destroy;\n\tiwindow_class->build = imageheader_build;\n\n\timageheader_parent_class = g_type_class_peek_parent( class );\n}\n\nstatic void\nimageheader_init( Imageheader *imageheader )\n{\n#ifdef DEBUG\n\tprintf( \"imageheader_init: %s\\n\", IWINDOW( imageheader )->title );\n#endif /*DEBUG*/\n\n\timageheader->iimage = NULL;\n}\n\nGtkType\nimageheader_get_type( void )\n{\n\tstatic GtkType imageheader_type = 0;\n\n\tif( !imageheader_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Imageheader\",\n\t\t\tsizeof( Imageheader ),\n\t\t\tsizeof( ImageheaderClass ),\n\t\t\t(GtkClassInitFunc) imageheader_class_init,\n\t\t\t(GtkObjectInitFunc) imageheader_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\timageheader_type = gtk_type_unique( TYPE_IDIALOG, &info );\n\t}\n\n\treturn( imageheader_type );\n}\n\n/* Conversion has changed signal.\n */\nstatic void\nimageheader_ii_changed( Model *model, Imageheader *imageheader )\n{\n\tg_assert( IS_MODEL( model ) );\n\tg_assert( IS_IMAGEHEADER( imageheader ) );\n\n\timageheader_refresh( imageheader );\n}\n\nstatic void\nimageheader_link( Imageheader *imageheader, iImage *iimage )\n{\n\timageheader->iimage = iimage;\n\n\tlisten_add( G_OBJECT( imageheader ), (GObject **) &imageheader->iimage,\n\t\t\"changed\", G_CALLBACK( imageheader_ii_changed ) );\n}\n\nGtkWidget *\nimageheader_new( iImage *iimage )\n{\n\tImageheader *imageheader = gtk_type_new( TYPE_IMAGEHEADER );\n\n\timageheader_link( imageheader, iimage );\n\n\treturn( GTK_WIDGET( imageheader ) );\n}\n"
  },
  {
    "path": "src/imageheader.h",
    "content": "/* display an image header\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_IMAGEHEADER (imageheader_get_type())\n#define IMAGEHEADER( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_IMAGEHEADER, Imageheader ))\n#define IMAGEHEADER_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_IMAGEHEADER, ImageheaderClass ))\n#define IS_IMAGEHEADER( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IMAGEHEADER ))\n#define IS_IMAGEHEADER_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEHEADER ))\n\ntypedef struct _Imageheader {\n\tiDialog parent;\n\n\tiImage *iimage;\n\tGtkListStore *store;\t\t/* Model for list view */\n\tGtkTreeModel *filter;\t\t/* After filtering with search box */\n\tGtkWidget *tree;\t\t/* Displayed tree */\n\tGtkWidget *entry;\t\t/* Search widget */\n\tGtkWidget *history;\n} Imageheader;\n\ntypedef struct _ImageheaderClass {\n\tiDialogClass parent_class;\n\n\t/* My methods.\n\t */\n} ImageheaderClass;\n\nGtkType imageheader_get_type( void );\nGtkWidget *imageheader_new( iImage *iimage );\n"
  },
  {
    "path": "src/imageinfo.c",
    "content": "/* image management ... a layer over the VIPS IMAGE type\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n\njobs:\n\n- reference counting layer ... in Managed base class, plus links to heap \n  garbage collection\n\n- filesystem tracking: we stat open files and signal file_changed if we see a \n  change\n\n- cache: several open( \"fred.v\" )s share a single Imageinfo, provided their \n  mtimes are all the same\n\n- lookup table management ... if an operation can work with pixel lookup \n  tables (found by examining a flag in the VIPS function descriptor), then\n  instead of operating on the image, the operation runs on the LUT associated\n  with that image ... Imageinfo tracks the LUTs representing delayed eval\n\n- dependency tracking ... an imageinfo can require several other imageinfos\n  to be open for it to work properly; we follow these dependencies, and\n  delay destroying an imageinfo until it's not required by any others\n\n- temp file management ... we can make temp images on disc; we unlink() these\n  temps when they're no longer needed\n\n- imageinfo/expr association tracking ... we track when an expr \n  receives an imageinfo as its value; the info is used to get region views\n  to display in the right image ... see expr_real_new_value()\n\n- paint stuff: also undo/redo buffers, each with a \"*_changed\" signal\n\n */\n\n/* \n\nmore stuff:\n\nwhile we transition to vips8, also use imageinfo to wrap VipsImage\n\nmost of the jobs above are pushed down into vips8 now ... except for\n\n- reference counting layer ... in Managed base class\n\n- filesystem tracking: we stat open files and signal file_changed if we see a\n  change\n\n- cache: several open( \"fred.v\" )s share a single Imageinfo, provided their \n  mtimes are all the same\n\n */\n\n\n#include \"ip.h\"\n\n/*\n#define DEBUG\n#define DEBUG_MAKE\n#define DEBUG_RGB\n#define DEBUG_OPEN\n#define DEBUG_CHECK\n */\n\nstatic iContainerClass *imageinfogroup_parent_class = NULL;\n\nstatic void\nimageinfogroup_finalize( GObject *gobject )\n{\n\tImageinfogroup *imageinfogroup = IMAGEINFOGROUP( gobject );\n\n\tIM_FREEF( g_hash_table_destroy, imageinfogroup->filename_hash );\n\n\tG_OBJECT_CLASS( imageinfogroup_parent_class )->finalize( gobject );\n}\n\nstatic void\nimageinfogroup_child_add( iContainer *parent, iContainer *child, int pos )\n{\n\tImageinfogroup *imageinfogroup = IMAGEINFOGROUP( parent );\n\tImageinfo *imageinfo = IMAGEINFO( child );\n\tconst char *name = IOBJECT( imageinfo )->name;\n\tGSList *hits;\n\n\thits = (GSList *) g_hash_table_lookup( imageinfogroup->filename_hash,\n\t\tname );\n\thits = g_slist_prepend( hits, imageinfo );\n\tg_hash_table_insert( imageinfogroup->filename_hash, \n\t\t(gpointer) name, (gpointer) hits );\n\n\tICONTAINER_CLASS( imageinfogroup_parent_class )->\n\t\tchild_add( parent, child, pos );\n}\n\nstatic void \nimageinfogroup_child_remove( iContainer *parent, iContainer *child )\n{\n\tImageinfogroup *imageinfogroup = IMAGEINFOGROUP( parent );\n\tImageinfo *imageinfo = IMAGEINFO( child );\n\tconst char *name = IOBJECT( imageinfo )->name;\n\tGSList *hits;\n\n\thits = (GSList *) g_hash_table_lookup( imageinfogroup->filename_hash,\n\t\tname );\n\tg_assert( hits );\n\thits = g_slist_remove( hits, imageinfo );\n\n\t/* child is going away (probably), so we don't want to link hits back\n\t * on again with child->name as the key ... if possible, look down\n\t * hits for another name we can use instead.\n\t */\n\tif( hits ) {\n\t\tconst char *new_name = IOBJECT( hits->data )->name;\n\n\t\tg_hash_table_replace( imageinfogroup->filename_hash, \n\t\t\t(gpointer) new_name, (gpointer) hits );\n\t}\n\telse\n\t\tg_hash_table_remove( imageinfogroup->filename_hash,\n\t\t\t(gpointer) name );\n\n\tICONTAINER_CLASS( imageinfogroup_parent_class )->\n\t\tchild_remove( parent, child );\n}\n\nstatic void\nimageinfogroup_class_init( ImageinfogroupClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tiContainerClass *icontainer_class = ICONTAINER_CLASS( class );\n\n\timageinfogroup_parent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = imageinfogroup_finalize;\n\n\ticontainer_class->child_add = imageinfogroup_child_add;\n\ticontainer_class->child_remove = imageinfogroup_child_remove;\n}\n\nstatic void\nimageinfogroup_init( Imageinfogroup *imageinfogroup )\n{\n#ifdef DEBUG\n\tprintf( \"imageinfogroup_init\\n\" );\n#endif /*DEBUG*/\n\n\timageinfogroup->filename_hash = \n\t\tg_hash_table_new( g_str_hash, g_str_equal );\n}\n\nGType\nimageinfogroup_get_type( void )\n{\n\tstatic GType imageinfogroup_type = 0;\n\n\tif( !imageinfogroup_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ImageinfogroupClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) imageinfogroup_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Imageinfogroup ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) imageinfogroup_init,\n\t\t};\n\n\t\timageinfogroup_type = g_type_register_static( TYPE_ICONTAINER, \n\t\t\t\"Imageinfogroup\", &info, 0 );\n\t}\n\n\treturn( imageinfogroup_type );\n}\n\nImageinfogroup *\nimageinfogroup_new( void )\n{\n\tImageinfogroup *imageinfogroup = IMAGEINFOGROUP( \n\t\tg_object_new( TYPE_IMAGEINFOGROUP, NULL ) );\n\n\treturn( imageinfogroup );\n}\n\nstatic void *\nimageinfogroup_lookup_test( Imageinfo *imageinfo, struct stat *buf )\n{\n\tconst char *name = IOBJECT( imageinfo )->name;\n\n\tif( name && buf->st_mtime == imageinfo->mtime )\n\t\treturn( imageinfo );\n\n\treturn( NULL );\n}\n\n/* Look up by filename ... mtimes have to match too.\n */\nstatic Imageinfo *\nimageinfogroup_lookup( Imageinfogroup *imageinfogroup, const char *filename )\n{\n\tGSList *hits;\n\tImageinfo *imageinfo;\n\tstruct stat buf;\n\n\tif( stat( filename, &buf ) == 0 && \n\t\t(hits = (GSList *) g_hash_table_lookup( \n\t\t\timageinfogroup->filename_hash, filename )) &&\n\t\t(imageinfo = IMAGEINFO( slist_map( hits,\n\t\t\t(SListMapFn) imageinfogroup_lookup_test, &buf ) )) ) \n\t\treturn( imageinfo );\n\n\treturn( NULL );\n}\n\n/* Our signals. \n */\nenum {\n\tSIG_AREA_CHANGED,\t/* Area of image has changed: update screen */\n\tSIG_AREA_PAINTED,\t/* Area of image has been painted */\n\tSIG_UNDO_CHANGED,\t/* Undo/redo state has changed */\n\tSIG_FILE_CHANGED,\t/* Underlying file seems to have changed */\n\tSIG_INVALIDATE,\t\t/* IMAGE* has been invalidated */\n\tSIG_LAST\n};\n\nstatic ManagedClass *parent_class = NULL;\n\nstatic guint imageinfo_signals[SIG_LAST] = { 0 };\n\n#if defined(DEBUG) || defined(DEBUG_OPEN) || defined(DEBUG_RGB) || \\\n\tdefined(DEBUG_CHECK) || defined(DEBUG_MAKE) \nstatic void\nimageinfo_print( Imageinfo *imageinfo )\n{\n\tprintf( \" \\\"%s\\\" mtime = %d (%p)\\n\",\n\t\tIOBJECT( imageinfo )->name,\n\t\t(int) imageinfo->mtime,\n\t\timageinfo );\n}\n#endif\n\nvoid *\nimageinfo_area_changed( Imageinfo *imageinfo, Rect *dirty )\n{\n\tg_assert( IS_IMAGEINFO( imageinfo ) );\n\n#ifdef DEBUG\n\tprintf( \"imageinfo_area_changed: \"\n\t\t\"left = %d, top = %d, width = %d, height = %d\\n\",\n\t\tdirty->left, dirty->top, dirty->width, dirty->height );\n#endif /*DEBUG*/\n\n\tg_signal_emit( G_OBJECT( imageinfo ), \n\t\timageinfo_signals[SIG_AREA_CHANGED], 0, dirty );\n\n\treturn( NULL );\n}\n\nvoid *\nimageinfo_area_painted( Imageinfo *imageinfo, Rect *dirty )\n{\n\tg_assert( IS_IMAGEINFO( imageinfo ) );\n\n#ifdef DEBUG\n\tprintf( \"imageinfo_area_painted: left = %d, top = %d, \"\n\t\t\"width = %d, height = %d\\n\",\n\t\tdirty->left, dirty->top, dirty->width, dirty->height );\n#endif /*DEBUG*/\n\n\tg_signal_emit( G_OBJECT( imageinfo ), \n\t\timageinfo_signals[SIG_AREA_PAINTED], 0, dirty );\n\n\treturn( NULL );\n}\n\nstatic void *\nimageinfo_undo_changed( Imageinfo *imageinfo )\n{\n\tg_assert( IS_IMAGEINFO( imageinfo ) );\n\n\tg_signal_emit( G_OBJECT( imageinfo ), \n\t\timageinfo_signals[SIG_UNDO_CHANGED], 0 );\n\n\treturn( NULL );\n}\n\nstatic void *\nimageinfo_file_changed( Imageinfo *imageinfo )\n{\n\tg_assert( IS_IMAGEINFO( imageinfo ) );\n\n#ifdef DEBUG_CHECK\n\tprintf( \"imageinfo_file_changed:\" );\n\timageinfo_print( imageinfo );\n#endif /*DEBUG_CHECK*/\n\n\tg_signal_emit( G_OBJECT( imageinfo ), \n\t\timageinfo_signals[SIG_FILE_CHANGED], 0 );\n\n\treturn( NULL );\n}\n\nstatic void *\nimageinfo_invalidate( Imageinfo *imageinfo )\n{\n\tg_assert( IS_IMAGEINFO( imageinfo ) );\n\n#ifdef DEBUG_CHECK\n\tprintf( \"imageinfo_invalidate:\" );\n\timageinfo_print( imageinfo );\n#endif /*DEBUG_CHECK*/\n\n\tg_signal_emit( G_OBJECT( imageinfo ), \n\t\timageinfo_signals[SIG_INVALIDATE], 0 );\n\n\treturn( NULL );\n}\n\nvoid\nimageinfo_expr_add( Imageinfo *imageinfo, Expr *expr )\n{\n#ifdef DEBUG\n\tprintf( \"imageinfo_expr_add: \" );\n\texpr_name_print( expr );\n\tprintf( \"has imageinfo \\\"%s\\\" as value\\n\", imageinfo->im->filename );\n#endif /*DEBUG*/\n\n\tg_assert( !g_slist_find( imageinfo->exprs, expr ) );\n\tg_assert( !expr->imageinfo );\n\n\texpr->imageinfo = imageinfo;\n\timageinfo->exprs = g_slist_prepend( imageinfo->exprs, expr );\n}\n\nvoid *\nimageinfo_expr_remove( Expr *expr, Imageinfo *imageinfo )\n{\n#ifdef DEBUG\n\tprintf( \"imageinfo_expr_remove: \" );\n\texpr_name_print( expr );\n\tprintf( \"has lost imageinfo \\\"%s\\\" as value\\n\", \n\t\timageinfo->im->filename );\n#endif /*DEBUG*/\n\n\tg_assert( expr->imageinfo );\n\tg_assert( g_slist_find( imageinfo->exprs, expr ) );\n\tg_assert( expr->imageinfo == imageinfo );\n\n\texpr->imageinfo = NULL;\n\timageinfo->exprs = g_slist_remove( imageinfo->exprs, expr );\n\n\treturn( NULL );\n}\n\nGSList *\nimageinfo_expr_which( Imageinfo *imageinfo )\n{\n\treturn( imageinfo->exprs );\n}\n\n/* Find the underlying image in an imageinfo.\n */\nIMAGE *\nimageinfo_get_underlying( Imageinfo *imageinfo )\n{\n\tif( imageinfo->underlying )\n\t\treturn( imageinfo_get_underlying( imageinfo->underlying ) );\n\telse\n\t\treturn( imageinfo->im );\n}\n\n/* Free up an undo fragment. \n */\nstatic void\nimageinfo_undofragment_free( Undofragment *frag )\n{\n\tIM_FREEF( im_close, frag->im );\n\tIM_FREE( frag );\n}\n\n/* Free an undo buffer.\n */\nstatic void\nimageinfo_undobuffer_free( Undobuffer *undo )\n{\n\tslist_map( undo->frags, \n\t\t(SListMapFn) imageinfo_undofragment_free, NULL );\n\tIM_FREEF( g_slist_free, undo->frags );\n\tIM_FREE( undo );\n}\n\n/* Free all undo information attached to an imageinfo.\n */\nstatic void\nimageinfo_undo_free( Imageinfo *imageinfo )\n{\t\n\tslist_map( imageinfo->redo, \n\t\t(SListMapFn) imageinfo_undobuffer_free, NULL );\n\tIM_FREEF( g_slist_free, imageinfo->redo );\n\tslist_map( imageinfo->undo, \n\t\t(SListMapFn) imageinfo_undobuffer_free, NULL );\n\tIM_FREEF( g_slist_free, imageinfo->undo );\n\tIM_FREEF( imageinfo_undobuffer_free, imageinfo->cundo );\n}\n\nstatic void\nimageinfo_dispose_eval( Imageinfo *imageinfo )\n{\n\timageinfo->monitored = FALSE;\n\n\t/* Make sure any callbacks from the IMAGE stop working.\n\t */\n\tif( imageinfo->proxy ) {\n\t\timageinfo->proxy->imageinfo = NULL;\n\t\timageinfo->proxy = NULL;\n\t}\n}\n\nstatic void\nimageinfo_dispose( GObject *gobject )\n{\n\tImageinfo *imageinfo = IMAGEINFO( gobject );\n\n#ifdef DEBUG_OPEN\n\tprintf( \"imageinfo_dispose:\" );\n\timageinfo_print( imageinfo );\n#endif /*DEBUG_OPEN*/\n\n\tslist_map( imageinfo->exprs, \n\t\t(SListMapFn) imageinfo_expr_remove, imageinfo );\n\tg_assert( !imageinfo->exprs );\n\n\timageinfo_dispose_eval( imageinfo );\n\n\tIM_FREEF( g_source_remove, imageinfo->check_tid );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\n/* Final death!\n */\nstatic void \nimageinfo_finalize( GObject *gobject )\n{\n\tImageinfo *imageinfo = IMAGEINFO( gobject );\n\tgboolean isfile = imageinfo->im && im_isfile( imageinfo->im );\n\n#ifdef DEBUG_MAKE\n\tprintf( \"imageinfo_finalize:\" ); \n\timageinfo_print( imageinfo );\n#endif /*DEBUG_MAKE*/\n\n\tIM_FREEF( im_close, imageinfo->im );\n\tIM_FREEF( im_close, imageinfo->mapped_im );\n\tIM_FREEF( im_close, imageinfo->identity_lut );\n\n\tif( imageinfo->dfile && \n\t\timageinfo->delete_filename &&\n\t\tisfile ) {\n#ifdef DEBUG_OPEN\n\t\tprintf( \"imageinfo_destroy: unlinking \\\"%s\\\"\\n\", name );\n#endif /*DEBUG_OPEN*/\n\n\t\tunlinkf( \"%s\", imageinfo->delete_filename );\n\t\tiobject_changed( IOBJECT( main_imageinfogroup ) );\n\t}\n\n\tVIPS_FREE( imageinfo->delete_filename ); \n\n\tMANAGED_UNREF( imageinfo->underlying );\n\n\timageinfo_undo_free( imageinfo );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\n/* Make an info string about an imageinfo.\n */\nstatic void\nimageinfo_info( iObject *iobject, VipsBuf *buf )\n{\n\tImageinfo *imageinfo = IMAGEINFO( iobject );\n\n\tvips_buf_appendi( buf, imageinfo_get( FALSE, imageinfo ) );\n\n\t/* Don't chain up to parent->info(), we don't want all the other\n\t * stuff, this is going to be used for a caption.\n\t */\n}\n\nstatic void\nimageinfo_real_area_changed( Imageinfo *imageinfo, Rect *dirty )\n{\n}\n\nstatic void\nimageinfo_real_area_painted( Imageinfo *imageinfo, Rect *dirty )\n{\n\t/* Cache attaches to this signal and invalidates on paint. Trigger a\n\t * repaint in turn.\n\t */\n\timageinfo_area_changed( imageinfo, dirty );\n}\n\nstatic void\nimageinfo_real_undo_changed( Imageinfo *imageinfo )\n{\n}\n\nstatic void\nimageinfo_real_file_changed( Imageinfo *imageinfo )\n{\n}\n\nstatic void\nimageinfo_real_invalidate( Imageinfo *imageinfo )\n{\n}\n\nstatic void\nimageinfo_class_init( ImageinfoClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tiObjectClass *iobject_class = IOBJECT_CLASS( class );\n\tManagedClass *managed_class = MANAGED_CLASS( class );\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = imageinfo_dispose;\n\tgobject_class->finalize = imageinfo_finalize;\n\n\tiobject_class->info = imageinfo_info;\n\n\t/* Timeout on unreffed images.\n\t */\n\tmanaged_class->keepalive = 60.0;\n\n\tclass->area_changed = imageinfo_real_area_changed;\n\tclass->area_painted = imageinfo_real_area_painted;\n\tclass->undo_changed = imageinfo_real_undo_changed;\n\tclass->file_changed = imageinfo_real_file_changed;\n\tclass->invalidate = imageinfo_real_invalidate;\n\n\t/* Create signals.\n\t */\n\timageinfo_signals[SIG_AREA_CHANGED] = g_signal_new( \"area_changed\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ImageinfoClass, area_changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__POINTER,\n\t\tG_TYPE_NONE, 1,\n\t\tG_TYPE_POINTER );\n\timageinfo_signals[SIG_AREA_PAINTED] = g_signal_new( \"area_painted\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ImageinfoClass, area_painted ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__POINTER,\n\t\tG_TYPE_NONE, 1,\n\t\tG_TYPE_POINTER );\n\timageinfo_signals[SIG_UNDO_CHANGED] = g_signal_new( \"undo_changed\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ImageinfoClass, undo_changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\timageinfo_signals[SIG_FILE_CHANGED] = g_signal_new( \"file_changed\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ImageinfoClass, file_changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\timageinfo_signals[SIG_INVALIDATE] = g_signal_new( \"invalidate\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ImageinfoClass, invalidate ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n}\n\nstatic void\nimageinfo_init( Imageinfo *imageinfo )\n{\n#ifdef DEBUG_MAKE\n\tprintf( \"imageinfo_init: %p\\n\", imageinfo );\n#endif /*DEBUG_MAKE*/\n\n\timageinfo->im = NULL;\n\timageinfo->mapped_im = NULL;\n\timageinfo->identity_lut = NULL;\n\timageinfo->underlying = NULL;\n\timageinfo->proxy = NULL;\n\n\timageinfo->dfile = FALSE;\n\timageinfo->delete_filename = NULL; \n\timageinfo->from_file = FALSE;\n\timageinfo->mtime = 0;\n\timageinfo->exprs = NULL;\n\timageinfo->ok_to_paint = FALSE;\n\timageinfo->undo = NULL;\n\timageinfo->redo = NULL;\n\timageinfo->cundo = NULL;\n\n\timageinfo->monitored = FALSE;\n\n\timageinfo->check_mtime = 0;\n\timageinfo->check_tid = 0;\n}\n\nGType\nimageinfo_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ImageinfoClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) imageinfo_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Imageinfo ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) imageinfo_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_MANAGED, \n\t\t\t\"Imageinfo\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic int\nimageinfo_proxy_eval( Imageinfoproxy *proxy )\n{\n\tImageinfo *imageinfo = proxy->imageinfo;\n\n\tif( imageinfo && imageinfo->im->time ) \n\t\tif( progress_update_percent( imageinfo->im->time->percent,\n\t\t\timageinfo->im->time->eta ) ) \n\t\t\treturn( -1 );\n\n\treturn( 0 );\n}\n\nstatic int\nimageinfo_proxy_invalidate( Imageinfoproxy *proxy )\n{\n\tImageinfo *imageinfo = proxy->imageinfo;\n\n\tif( imageinfo ) \n\t\timageinfo_invalidate( imageinfo );\n\n\treturn( 0 );\n}\n\nstatic int\nimageinfo_proxy_preclose( Imageinfoproxy *proxy )\n{\n\tImageinfo *imageinfo = proxy->imageinfo;\n\n\t/* Remove everything related to progress.\n\t */\n\tif( imageinfo ) \n\t\timageinfo_dispose_eval( imageinfo );\n\n\treturn( 0 );\n}\n\n/* Add a proxy to track IMAGE events.\n */\nstatic void\nimageinfo_proxy_add( Imageinfo *imageinfo )\n{\n\t/* Only if we're running interactively.\n\t */\n\tif( main_option_batch )\n\t\treturn;\n\n\t/* Already being monitored?\n\t */\n\tif( imageinfo->monitored ) \n\t\treturn;\n\timageinfo->monitored = TRUE;\n\n        /* Need a proxy on IMAGE.\n         */ \n\tg_assert( !imageinfo->proxy );\n\tif( !(imageinfo->proxy = IM_NEW( imageinfo->im, Imageinfoproxy )) )\n\t\treturn;\n\timageinfo->proxy->im = imageinfo->im;\n\timageinfo->proxy->imageinfo = imageinfo;\n\n\t(void) im_add_eval_callback( imageinfo->im, \n\t\t(im_callback_fn) imageinfo_proxy_eval, \n\t\timageinfo->proxy, NULL );\n\n\t(void) im_add_invalidate_callback( imageinfo->im, \n\t\t(im_callback_fn) imageinfo_proxy_invalidate, \n\t\timageinfo->proxy, NULL );\n\n\t/* Has to be preclose, because we want to be sure we disconnect before \n\t * the proxy is freed on a close callback.\n\t */\n\t(void) im_add_preclose_callback( imageinfo->im, \n\t\t(im_callback_fn) imageinfo_proxy_preclose, \n\t\timageinfo->proxy, NULL );\n}\n\n/* Make a basic imageinfo. No refs, will be destroyed on next GC. If name is\n * NULL, make a temp name up; otherwise name needs to be unique.\n */\nImageinfo *\nimageinfo_new( Imageinfogroup *imageinfogroup, \n\tHeap *heap, IMAGE *im, const char *name )\n{\n\tImageinfo *imageinfo = \n\t\tIMAGEINFO( g_object_new( TYPE_IMAGEINFO, NULL ) );\n\tchar buf[FILENAME_MAX];\n\n#ifdef DEBUG_OPEN\n\tprintf( \"imageinfo_new: %p \\\"%s\\\"\\n\", imageinfo, im->filename );\n#endif /*DEBUG_OPEN*/\n\n\tmanaged_link_heap( MANAGED( imageinfo ), heap );\n\n\tif( !name ) {\n\t\tif( !temp_name( buf, \"v\" ) ) \n\t\t\t/* Will be freed on next GC.\n\t\t\t */\n\t\t\treturn( NULL );\n\n\t\tname = buf;\n\t}\n\tiobject_set( IOBJECT( imageinfo ), name, NULL );\n\n\t/* Only record the pointer when we know we will make the imageinfo\n\t * successfully.\n\t */\n\timageinfo->im = im;\n\n\ticontainer_child_add( ICONTAINER( imageinfogroup ),\n\t\tICONTAINER( imageinfo ), -1 );\n\timageinfo_proxy_add( imageinfo );\n\n\treturn( imageinfo );\n}\n\n/* An image is a result of a LUT operation on an earlier imageinfo.\n */\nvoid\nimageinfo_set_underlying( Imageinfo *top_imageinfo, Imageinfo *imageinfo )\n{\n\tg_assert( !top_imageinfo->underlying );\n\n\ttop_imageinfo->underlying = imageinfo;\n\tMANAGED_REF( top_imageinfo->underlying );\n}\n\n/* Make a temp image. Deleted on close. No refs: closed on next GC. If you\n * want it to stick around, ref it!\n */\nImageinfo *\nimageinfo_new_temp( Imageinfogroup *imageinfogroup, \n\tHeap *heap, const char *name, const char *mode )\n{\n\tIMAGE *im;\n\tchar tname[FILENAME_MAX];\n\tImageinfo *imageinfo;\n\n\tif( !temp_name( tname, \"v\" ) || \n\t\t!(im = im_open( tname, mode )) )\n\t\treturn( NULL );\n\tif( !(imageinfo = imageinfo_new( imageinfogroup, heap, im, name )) ) {\n\t\tim_close( im );\n\t\treturn( NULL );\n\t}\n\timageinfo->dfile = TRUE;\n\tVIPS_SETSTR( imageinfo->delete_filename, tname ); \n\n\treturn( imageinfo );\n}\n\n/* Need this context during imageinfo_open_image_input().\n */\ntypedef struct _ImageinfoOpen {\n\tImageinfogroup *imageinfogroup;\n\tHeap *heap;\n\tconst char *filename;\n\tGtkWidget *parent;\n} ImageinfoOpen;\n\n/* Open for read ... returns a non-heap pointer, destroy if it goes in the\n * heap.\n */\nstatic Imageinfo *\nimageinfo_open_image_input( const char *filename, ImageinfoOpen *open )\n{\n\tImageinfo *imageinfo;\n\tVipsFormatClass *format;\n\n\tif( !(format = vips_format_for_file( filename )) ) \n\t\treturn( NULL );\n\n\tif( strcmp( VIPS_OBJECT_CLASS( format )->nickname, \"vips\" ) == 0 ) {\n\t\tIMAGE *im;\n\n\t\tif( !(im = im_open( filename, \"r\" )) ) \n\t\t\treturn( NULL );\n\n\t\tif( !(imageinfo = imageinfo_new( open->imageinfogroup, \n\t\t\topen->heap, im, open->filename )) ) {\n\t\t\tim_close( im );\n\t\t\treturn( NULL );\n\t\t}\n\t\tMANAGED_REF( imageinfo );\n\n#ifdef DEBUG_OPEN\n\t\tprintf( \"imageinfo_open_image_input: opened VIPS \\\"%s\\\"\\n\", \n\t\t\tfilename );\n#endif /*DEBUG_OPEN*/\n\t}\n\telse {\n\t\tVipsFormatFlags flags = \n\t\t\tvips_format_get_flags( format, filename );\n\t\tconst char *mode = flags & VIPS_FORMAT_PARTIAL ? \"p\" : \"w\";\n\n\t\tif( !(imageinfo = imageinfo_new_temp( open->imageinfogroup, \n\t\t\topen->heap, open->filename, mode )) )\n\t\t\treturn( NULL );\n\t\tMANAGED_REF( imageinfo );\n\t\tif( format->load( filename, imageinfo->im ) ||\n\t\t\tim_histlin( imageinfo->im, \"im_copy %s %s\",\n\t\t\t\tfilename, imageinfo->im->filename ) ) {\n\t\t\tMANAGED_UNREF( imageinfo );\n\t\t\treturn( NULL );\n\t\t}\n\n#ifdef DEBUG_OPEN\n\t\tprintf( \"imageinfo_open_image_input: opened %s \\\"%s\\\"\\n\", \n\t\t\tVIPS_OBJECT_CLASS( format )->nickname, filename );\n#endif /*DEBUG_OPEN*/\n\t}\n\n\t/* Get ready for input.\n \t */\n\tif( im_pincheck( imageinfo->im ) ) \n\t\treturn( NULL );\n\n\t/* The rewind will have removed everything from the IMAGE. Reattach\n\t * progress.\n\t */\n\timageinfo_proxy_add( imageinfo );\n\n\t/* Attach the original filename ... pick this up again later as a\n\t * save default.\n\t */\n\tif( im_meta_set_string( imageinfo->im, ORIGINAL_FILENAME, filename ) )\n\t\treturn( NULL );\n\n\treturn( imageinfo );\n}\n\nImageinfo *\nimageinfo_new_from_pixbuf( Imageinfogroup *imageinfogroup, \n\tHeap *heap, GdkPixbuf *pixbuf ) \n{\n\tint width;\n\tint height;\n\tint bands;\n\tguchar *bytes;\n\tImageinfo *ii;\n\tsize_t vips_length;\n\n\twidth = gdk_pixbuf_get_width( pixbuf ); \n\theight = gdk_pixbuf_get_height( pixbuf ); \n\tbands = gdk_pixbuf_get_n_channels( pixbuf );\n\n\t/* 2.26 and later have gdk_pixbuf_get_pixels_with_length()\n\t * which would let us check the size, but we can't reslly use it yet.\n\t * Another time!\n\n\tguint length;\n\n\tbytes = gdk_pixbuf_get_pixels_with_length( pixbuf, &length ); \n\tif( vips_length != length ) {\n\t\terror_top( _( \"Unable to create image.\" ) );\n\t\terror_sub( _( \"vips expected %zd bytes, gdkpixbuf made %d\" ),\n\t\t\tvips_length, length ); \n\t\treturn( NULL );\n\t}\n\n\t */\n\n\tbytes = gdk_pixbuf_get_pixels( pixbuf ); \n\n\tif( !(ii = imageinfo_new_temp( imageinfogroup, heap, NULL, \"t\" )) )\n\t\treturn( NULL );\n\tim_initdesc( ii->im, width, height, bands, \n\t\tIM_BBITS_BYTE, IM_BANDFMT_UCHAR, IM_CODING_NONE, \n\t\tIM_TYPE_sRGB, 1.0, 1.0, 0, 0 );\n\tif( im_setupout( ii->im ) ) \n\t\treturn( NULL );\n\tvips_length = VIPS_IMAGE_SIZEOF_LINE( ii->im ) * height;\n\tmemcpy( ii->im->data, bytes, vips_length );\n\n\treturn( ii ); \n}\n\n/* Was this ii loaded from a file (ie. ->name contains a filename the user\n * might recognise).\n */\ngboolean \nimageinfo_is_from_file( Imageinfo *imageinfo )\n{\n\treturn( IOBJECT( imageinfo )->name && \n\t\timageinfo->from_file );\n}\n\nstatic gint\nimageinfo_attach_check_cb( Imageinfo *imageinfo )\n{\n\tif( imageinfo_is_from_file( imageinfo ) && \n\t\timageinfo->check_tid ) {\n\t\tstruct stat buf;\n\n\t\tif( !stat( IOBJECT( imageinfo )->name, &buf ) &&\n\t\t\tbuf.st_mtime != imageinfo->check_mtime ) {\n\t\t\timageinfo->check_mtime = buf.st_mtime;\n\t\t\timageinfo_file_changed( imageinfo );\n\t\t}\n\t}\n\n\treturn( TRUE );\n}\n\n/* Start checking this file for updates, signal reload if there is one.\n */\nstatic void\nimageinfo_attach_check( Imageinfo *imageinfo )\n{\n\tif( imageinfo_is_from_file( imageinfo ) && \n\t\t!imageinfo->check_tid ) {\n\t\tstruct stat buf;\n\n\t\t/* Need to be able to stat() to be able to track a file.\n\t\t */\n\t\tif( stat( IOBJECT( imageinfo )->name, &buf ) )\n\t\t\treturn;\n\n\t\timageinfo->mtime = buf.st_mtime;\n\t\timageinfo->check_mtime = imageinfo->mtime;\n\t\timageinfo->check_tid = g_timeout_add( 1000, \n\t\t\t(GSourceFunc) imageinfo_attach_check_cb, imageinfo );\n\n#ifdef DEBUG_CHECK\n\t\tprintf( \"imageinfo_attach_check: starting to check\" );\n\t\timageinfo_print( imageinfo );\n#endif /*DEBUG_CHECK*/\n\t}\n\telse\n\t\tIM_FREEF( g_source_remove, imageinfo->check_tid );\n}\n\n/* Open a filename for input. The filenmae can have an embedded mode. \n */\nImageinfo *\nimageinfo_new_input( Imageinfogroup *imageinfogroup, GtkWidget *parent,\n\tHeap *heap, const char *name )\n{\n\tImageinfo *imageinfo;\n\tImageinfoOpen open;\n\n\tif( (imageinfo = imageinfogroup_lookup( imageinfogroup, name )) ) {\n\t\t/* We always make a new non-heap pointer.\n\t\t */\n\t\tMANAGED_REF( imageinfo );\n\t\treturn( imageinfo );\n\t}\n\n\topen.imageinfogroup = imageinfogroup;\n\topen.heap = heap;\n\topen.filename = name;\n\topen.parent = parent;\n\n        if( !(imageinfo = (Imageinfo *) callv_string_filename( \n\t\t(callv_string_fn) imageinfo_open_image_input, \n\t\tname, &open, NULL, NULL )) ) {\n\t\terror_top( _( \"Unable to open image.\" ) );\n\t\terror_sub( _( \"Unable to open file \\\"%s\\\" as image.\" ), \n\t\t\tname );\n\t\terror_vips();\n                return( NULL );\n        }\n\n\timageinfo->from_file = TRUE;\n\timageinfo_attach_check( imageinfo );\n\n\treturn( imageinfo );\n}\n\n/* Add an identity lut, if this is a LUTtable image.\n */\nstatic IMAGE *\nimageinfo_get_identity_lut( Imageinfo *imageinfo )\n{\n\tif( imageinfo->im->Coding == IM_CODING_NONE && \n\t\timageinfo->im->BandFmt == IM_BANDFMT_UCHAR ) {\n\t\tif( !imageinfo->identity_lut ) {\n\t\t\tchar tname[FILENAME_MAX];\n\t\t\tIMAGE *im;\n\n\t\t\tif( !temp_name( tname, \"v\" ) || \n\t\t\t\t!(im = im_open( tname, \"p\" )) )\n\t\t\t\treturn( NULL );\n\t\t\timageinfo->identity_lut = im;\n\n\t\t\tif( im_identity( imageinfo->identity_lut, \n\t\t\t\timageinfo->im->Bands ) || \n\t\t\t\tim_histlin( imageinfo->identity_lut, \n\t\t\t\t\t\"im_identity %s %d\",\n\t\t\t\t\timageinfo->identity_lut->filename,\n\t\t\t\t\timageinfo->im->Bands ) ) \n\t\t\t\treturn( NULL );\n\t\t}\n\n\t\treturn( imageinfo->identity_lut );\n\t}\n\telse\n\t\treturn( NULL );\n}\n\nstatic IMAGE *\nimageinfo_get_mapped( Imageinfo *imageinfo )\n{\n\tif( !imageinfo->mapped_im ) {\n\t\tIMAGE *im = imageinfo_get_underlying( imageinfo );\n\t\tIMAGE *mapped_im;\n\t\tchar name[FILENAME_MAX];\n\t\tchar *argv[4];\n\n\t\tif( !temp_name( name, \"v\" ) || \n\t\t\t!(mapped_im = im_open( name, \"p\" )) ) \n\t\t\treturn( NULL );\n\t\targv[0] = im->filename;\n\t\targv[1] = mapped_im->filename;\n\t\targv[2] = imageinfo->im->filename;\n\t\targv[3] = NULL;\n\t\tif( im_maplut( im, mapped_im, imageinfo->im ) ||\n\t\t\tim_updatehist( mapped_im, \"im_maplut\", 3, argv ) ) {\n\t\t\tim_close( mapped_im );\n\t\t\terror_vips_all();\n\t\t\treturn( NULL );\n\t\t}\n\t\timageinfo->mapped_im = mapped_im;\n\t}\n\n\treturn( imageinfo->mapped_im );\n}\n\n/* Get a lut ... or not!\n */\nIMAGE *\nimageinfo_get( gboolean use_lut, Imageinfo *imageinfo )\n{\n\tif( !imageinfo ) \n\t\treturn( NULL );\n\n\tif( use_lut && imageinfo->underlying ) \n\t\treturn( imageinfo->im );\n\tif( use_lut && !imageinfo->underlying ) {\n\t\tIMAGE *lut;\n\n\t\tif( (lut = imageinfo_get_identity_lut( imageinfo )) )\n\t\t\treturn( lut );\n\t\telse\n\t\t\treturn( imageinfo->im );\n\t}\n\telse if( !use_lut && imageinfo->underlying )\n\t\treturn( imageinfo_get_mapped( imageinfo ) );\n\telse\n\t\treturn( imageinfo->im );\n}\n\n/* Do a set of II all refer to the same underlying image? Used to spot\n * LUTable optimisations.\n */\ngboolean\nimageinfo_same_underlying( Imageinfo *imageinfo[], int n )\n{\n\tint i;\n\n\tif( n < 2 )\n\t\treturn( TRUE );\n\telse {\n\t\tIMAGE *first = imageinfo_get_underlying( imageinfo[0] );\n\n\t\tfor( i = 1; i < n; i++ )\n\t\t\tif( imageinfo_get_underlying( imageinfo[i] ) != first )\n\t\t\t\treturn( FALSE );\n\n\t\treturn( TRUE );\n\t}\n}\n\n/* Write to a filename.\n */\ngboolean\nimageinfo_write( Imageinfo *imageinfo, const char *name )\n{\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo );\n\n\tif( vips_format_write( im, name ) ) {\n\t\tchar filename[FILENAME_MAX];\n\t\tchar mode[FILENAME_MAX];\n\n\t\tim_filename_split( name, filename, mode );\n\t\terror_top( _( \"Unable to write to file.\" ) );\n\t\terror_sub( _( \"Error writing image to file \\\"%s\\\".\" ), \n\t\t\tfilename );\n\t\terror_vips();\n\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic gboolean\nimageinfo_make_paintable( Imageinfo *imageinfo )\n{\t\n\tprogress_begin();\n\tif( im_rwcheck( imageinfo->im ) ) {\n\t\tprogress_end();\n\t\terror_top( _( \"Unable to paint on image.\" ) );\n\t\terror_sub( _( \"Unable to get write permission for \"\n\t\t\t\"file \\\"%s\\\".\\nCheck permission settings.\" ), \n\t\t\timageinfo->im->filename );\n\t\terror_vips();\n\t\treturn( FALSE );\n\t}\n\tprogress_end();\n\n\timageinfo->ok_to_paint = TRUE;\n\n\treturn( TRUE );\n}\n\nstatic void\nimageinfo_check_paintable_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tImageinfo *imageinfo = IMAGEINFO( client );\n\n\tif( !imageinfo_make_paintable( imageinfo ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tnfn( sys, IWINDOW_YES );\n}\n\n/* Check painting is OK. nfn() called on \"ok!\". Returns FALSE if it's\n * not immediately obvious that we can paint.\n */\ngboolean\nimageinfo_check_paintable( Imageinfo *imageinfo, GtkWidget *parent,\n\tiWindowNotifyFn nfn, void *sys )\n{\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo );\n\n\tif( im &&\n\t\tim_isfile( im ) && \n\t\t!imageinfo->dfile && \n\t\t!imageinfo->ok_to_paint ) {\n\t\tiDialog *idlg;\n\n\t\tidlg = box_yesno( parent,\n\t\t\timageinfo_check_paintable_cb, \n\t\t\t\tiwindow_true_cb, imageinfo,\n\t\t\tnfn, sys,\n\t\t\t_( \"Modify\" ),\n\t\t\t_( \"Modify disc file?\" ),\n\t\t\t_( \"This image is being shown directly from the \"\n\t\t\t\"disc file:\\n\\n\"\n\t\t\t\"   %s\\n\\n\"\n\t\t\t\"If you paint on this file, it will be permanently \"\n\t\t\t\"changed. If something goes wrong, you may lose work. \"\n\t\t\t\"Are you sure you want to modify this file?\" ),\n\t\t\tIOBJECT( imageinfo )->name );\n\t\tidialog_set_iobject( idlg, IOBJECT( imageinfo ) );\n\n\t\treturn( FALSE );\n\t}\n\telse if( im &&\n\t\t!im_isfile( im ) && \n\t\t!imageinfo->ok_to_paint ) {\n\t\tif( !imageinfo_make_paintable( imageinfo ) ) {\n\t\t\tnfn( sys, IWINDOW_ERROR );\n\t\t\treturn( FALSE );\n\t\t}\n\t}\n\n\tnfn( sys, IWINDOW_YES );\n\n\treturn( TRUE );\n}\n\n/* Try to get an Imageinfo from a symbol.\n */\nImageinfo *\nimageinfo_sym_image( Symbol *sym )\n{\n        PElement *root = &sym->expr->root;\n\n        if( sym->type == SYM_VALUE && PEISIMAGE( root ) )\n                return( PEGETII( root ) );\n        else\n                return( NULL );\n}\n\nstatic Undofragment *\nimageinfo_undofragment_new( Undobuffer *undo )\n{\n\tUndofragment *frag = INEW( NULL, Undofragment );\n\n\tfrag->undo = undo;\n\tfrag->im = NULL;\n\n\treturn( frag );\n}\n\nstatic Undobuffer *\nimageinfo_undobuffer_new( Imageinfo *imageinfo )\n{\t\n\tUndobuffer *undo = INEW( NULL, Undobuffer );\n\n\tundo->imageinfo = imageinfo;\n\tundo->frags = NULL;\n\n\t/* No pixels in bounding box at the moment.\n\t */\n\tundo->bbox.left = 0;\n\tundo->bbox.top = 0;\n\tundo->bbox.width = 0;\n\tundo->bbox.height = 0;\n\n\treturn( undo );\n}\n\n/* Grab from the image into an IMAGE buffer. Always grab to memory.\n */\nstatic IMAGE *\nimageinfo_undo_grab_area( IMAGE *im, Rect *dirty )\n{\n\tIMAGE *save;\n\n\t/* Make new image to extract to. \n\t */\n\tif( !(save = im_open( \"undo buffer\", \"t\" )) )\n\t\treturn( NULL );\n\n\t/* Try to extract from im.\n\t */\n\tif( im_extract_area( im, save, \n\t\tdirty->left, dirty->top, dirty->width, dirty->height ) ) {\n\t\tim_close( save );\n\t\terror_vips_all();\n\t\treturn( NULL );\n\t}\n\n\treturn( save );\n}\n\n/* Grab into an undo fragment. Add frag to frag list on undo buffer, expand\n * bounding box.\n */\nstatic Undofragment *\nimageinfo_undo_grab( Undobuffer *undo, Rect *dirty )\n{\n\tImageinfo *imageinfo = undo->imageinfo;\n\tUndofragment *frag = imageinfo_undofragment_new( undo );\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo ); \n\tRect bbox;\n\n\t/* Try to extract from im. Memory allocation happens at this\n\t * point, so we must be careful!\n\t */\n\tif( !(frag->im = imageinfo_undo_grab_area( im, dirty )) ) {\n\t\timageinfo_undofragment_free( frag );\n\t\terror_vips_all();\n\t\treturn( NULL );\n\t}\n\n\t/* Note position of this frag.\n\t */\n\tfrag->pos = *dirty;\n\n\t/* Add frag to frag list on undo buffer.\n\t */\n\tundo->frags = g_slist_prepend( undo->frags, frag );\n\n\t/* Find bounding box for saved pixels.\n\t */\n\tim_rect_unionrect( dirty, &undo->bbox, &bbox );\n\tundo->bbox = bbox;\n\n\t/* Return new frag.\n\t */\n\treturn( frag );\n}\n\n/* Trim the undo buffer if we have more than x items on it.\n */\nstatic void\nimageinfo_undo_trim( Imageinfo *imageinfo )\n{\n\tint max = PAINTBOX_MAX_UNDO;\n\tint len = g_slist_length( imageinfo->undo );\n\n\tif( max >= 0 && len > max ) {\n\t\tGSList *l;\n\t\tint i;\n\n\t\tl = g_slist_reverse( imageinfo->undo );\n\n\t\tfor( i = 0; i < len - max; i++ ) {\n\t\t\tUndobuffer *undo = (Undobuffer *) l->data;\n\n\t\t\timageinfo_undobuffer_free( undo );\n\t\t\tl = g_slist_remove( l, undo );\n\t\t}\n\n\t\timageinfo->undo = g_slist_reverse( l );\n\t}\n\n#ifdef DEBUG\n\tprintf( \"imageinfo_undo_trim: %d items in undo buffer\\n\", \n\t\tg_slist_length( imageinfo->undo ) );\n#endif /*DEBUG*/\n}\n\n/* Mark the start or end of an undo session. Copy current undo information \n * to the undo buffers and NULL out the current undo pointer. Junk all redo\n * information: this new undo action makes all that out of date.\n */\nvoid\nimageinfo_undo_mark( Imageinfo *imageinfo )\n{\n\t/* Is there an existing undo save area?\n\t */\n\tif( imageinfo->cundo ) {\n\t\t/* Left over from the last undo save. Copy to undo save list\n\t\t * and get ready for new undo buffer.\n\t\t */\n\t\timageinfo->undo = \n\t\t\tg_slist_prepend( imageinfo->undo, imageinfo->cundo );\n\t\timageinfo->cundo = NULL;\n\t}\n\n\t/* Junk all redo information. \n\t */\n\tslist_map( imageinfo->redo, \n\t\t(SListMapFn) imageinfo_undobuffer_free, NULL );\n\tIM_FREEF( g_slist_free, imageinfo->redo );\n\n\t/* Trim undo buffer.\n\t */\n\timageinfo_undo_trim( imageinfo );\n\n\t/* Update menus.\n\t */\n\timageinfo_undo_changed( imageinfo );\n}\n\n/* Add to the undo buffer. If there is no undo buffer currently under\n * construction, make a new one. If there is an existing undo buffer, try to\n * grow it left/right/up/down so as to just enclose the new bounding box. We\n * assume that our dirty areas are not going to be disconnected. Is this\n * always true? No - if you move smudge or smear quickly, you can get\n * non-overlapping areas. However: if you do lots of little operations in more\n * or less the same place (surely the usual case), then this technique will be\n * far better.\n */\nstatic gboolean\nimageinfo_undo_add( Imageinfo *imageinfo, Rect *dirty )\n{\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo ); \n\tUndobuffer *undo = imageinfo->cundo;\n\tRect over, image, clipped;\n\n\t/* Undo disabled? Do nothing.\n\t */\n\tif( PAINTBOX_MAX_UNDO == 0 )\n\t\treturn( TRUE );\n\n\t/* Clip dirty against image size. \n\t */\n\timage.left = 0;\n\timage.top = 0;\n\timage.width = im->Xsize;\n\timage.height = im->Ysize;\n\tim_rect_intersectrect( &image, dirty, &clipped );\n\n\t/* Is there anything left? If not, can return immediately.\n\t */\n\tif( im_rect_isempty( &clipped ) )\n\t\treturn( TRUE );\n\n\tif( !undo ) {\n\t\t/* No current undo buffer ... start a new one for this action.\n\t\t */\n\t\tif( !(imageinfo->cundo = undo = \n\t\t\timageinfo_undobuffer_new( imageinfo )) )\n\t\t\treturn( FALSE );\n\n\t\treturn( imageinfo_undo_grab( undo, &clipped ) != NULL );\n\t}\n\n\t/* Existing stuff we are to add to. Try to expand our undo\n\t * area to just enclose the new bounding box. We assume that\n\t * there is an overlap between the new and old stuff.\n\t */\n\n\t/* Do we need to expand our saved area to the right?\n\t */\n\tif( IM_RECT_RIGHT( &clipped ) > IM_RECT_RIGHT( &undo->bbox ) ) {\n\t\t/* Expand to the right. Calculate the section we need\n\t\t * to add to our bounding box.\n\t\t */\n\t\tover.left = IM_RECT_RIGHT( &undo->bbox );\n\t\tover.top = undo->bbox.top;\n\t\tover.width = IM_RECT_RIGHT( &clipped ) - \n\t\t\tIM_RECT_RIGHT( &undo->bbox );\n\t\tover.height = undo->bbox.height;\n\n\t\t/* Grab new fragment.\n\t\t */\n\t\tif( !imageinfo_undo_grab( undo, &over ) )\n\t\t\treturn( FALSE );\n\t}\n\n\t/* Do we need to expand our saved area to the left?\n\t */\n\tif( undo->bbox.left > clipped.left ) {\n\t\tover.left = clipped.left;\n\t\tover.top = undo->bbox.top;\n\t\tover.width = undo->bbox.left - clipped.left;\n\t\tover.height = undo->bbox.height;\n\n\t\tif( !imageinfo_undo_grab( undo, &over ) )\n\t\t\treturn( FALSE );\n\t}\n\n\t/* Do we need to expand our saved area upwards?\n\t */\n\tif( undo->bbox.top > clipped.top ) {\n\t\tover.left = undo->bbox.left;\n\t\tover.top = clipped.top;\n\t\tover.width = undo->bbox.width;\n\t\tover.height = undo->bbox.top - clipped.top;\n\n\t\tif( !imageinfo_undo_grab( undo, &over ) )\n\t\t\treturn( FALSE );\n\t}\n\n\t/* Do we need to expand our saved area downwards?\n\t */\n\tif( IM_RECT_BOTTOM( &clipped ) > IM_RECT_BOTTOM( &undo->bbox ) ) {\n\t\tover.left = undo->bbox.left;\n\t\tover.top = IM_RECT_BOTTOM( &undo->bbox );\n\t\tover.width = undo->bbox.width;\n\t\tover.height = IM_RECT_BOTTOM( &clipped ) - \n\t\t\tIM_RECT_BOTTOM( &undo->bbox );\n\n\t\tif( !imageinfo_undo_grab( undo, &over ) )\n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Paste an undo fragment back into the image.\n */\nstatic void *\nimageinfo_undofragment_paste( Undofragment *frag )\n{\n\tUndobuffer *undo = frag->undo;\n\tImageinfo *imageinfo = undo->imageinfo;\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo ); \n\n\tim_insertplace( im, frag->im, frag->pos.left, frag->pos.top );\n\timageinfo_area_painted( imageinfo, &frag->pos );\n\n\treturn( NULL );\n}\n\n/* Paste a whole undo buffer back into the image.\n */\nstatic void\nimageinfo_undobuffer_paste( Undobuffer *undo )\n{\n\tslist_map( undo->frags, \n\t\t(SListMapFn) imageinfo_undofragment_paste, NULL );\n}\n\n/* Undo a paint action.\n */\ngboolean\nimageinfo_undo( Imageinfo *imageinfo )\n{\n\tUndobuffer *undo;\n\n\t/* Find the undo action we are to perform.\n\t */\n\tif( !imageinfo->undo )\n\t\treturn( TRUE );\n\tundo = (Undobuffer *) imageinfo->undo->data;\n\n\t/* We are going to undo the first action on the undo list. We must\n\t * save the area under the first undo action to the redo list. Do\n\t * the save, even if undo is disabled.\n\t */\n\tif( !imageinfo_undo_add( imageinfo, &undo->bbox ) ) \n\t\treturn( FALSE );\n\n\t/* Add new undo area.\n\t */\n\timageinfo->redo = g_slist_prepend( imageinfo->redo, imageinfo->cundo );\n\timageinfo->cundo = NULL;\n\n\t/* Paint undo back.\n\t */\n\timageinfo_undobuffer_paste( undo );\n\n\t/* Junk the undo action we have performed.\n\t */\n\timageinfo->undo = g_slist_remove( imageinfo->undo, undo );\n\timageinfo_undobuffer_free( undo );\n\n\t/* Trim undo buffer.\n\t */\n\timageinfo_undo_trim( imageinfo );\n\n\t/* Update menus.\n\t */\n\timageinfo_undo_changed( imageinfo );\n\n\treturn( TRUE );\n}\n\n/* Redo a paint action, if possible.\n */\ngboolean\nimageinfo_redo( Imageinfo *imageinfo )\n{\n\tUndobuffer *undo;\n\n\t/* Find the redo action we are to perform.\n\t */\n\tif( !imageinfo->redo )\n\t\treturn( TRUE );\n\tundo = (Undobuffer *) imageinfo->redo->data;\n\n\t/* We are going to redo the first action on the redo list. We must\n\t * save the area under the first redo action to the undo list. Save\n\t * even if undo is disabled.\n\t */\n\tif( !imageinfo_undo_add( imageinfo, &undo->bbox ) ) \n\t\treturn( FALSE );\n\n\t/* Add this new buffer to the undo list.\n\t */\n\timageinfo->undo = g_slist_prepend( imageinfo->undo, imageinfo->cundo );\n\timageinfo->cundo = NULL;\n\n\t/* Paint redo back.\n\t */\n\timageinfo_undobuffer_paste( undo );\n\n\t/* We can junk the head of the undo list now.\n\t */\n\timageinfo->redo = g_slist_remove( imageinfo->redo, undo );\n\timageinfo_undobuffer_free( undo );\n\n\t/* Trim undo buffer.\n\t */\n\timageinfo_undo_trim( imageinfo );\n\n\t/* Update menus.\n\t */\n\timageinfo_undo_changed( imageinfo );\n\n\treturn( TRUE );\n}\n\nvoid\nimageinfo_undo_clear( Imageinfo *imageinfo )\n{\n\timageinfo_undo_free( imageinfo );\n\timageinfo_undo_changed( imageinfo );\n}\n\nstatic int\nimageinfo_draw_point_cb( IMAGE *im, int x, int y, void *a, void *b, void *c )\n{\n\tIMAGE *mask = (IMAGE *) a;\n\tPEL *ink = (PEL *) b;\n\n\treturn( im_draw_mask( im, mask, \n\t\tx - mask->Xsize / 2, y - mask->Ysize / 2, ink ) );\n}\n\n/* Draw a line.\n */\ngboolean\nimageinfo_paint_line( Imageinfo *imageinfo, \n\tImageinfo *ink, Imageinfo *mask,\n\tint x1, int y1, int x2, int y2 )\n{\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo ); \n\tIMAGE *ink_im = imageinfo_get( FALSE, ink );\n\tIMAGE *mask_im = imageinfo_get( FALSE, mask );\n\tPEL *data = (PEL *) ink_im->data;\n\tRect dirty, p1, p2, image, clipped;\n\n\tp1.width = mask_im->Xsize;\n\tp1.height = mask_im->Ysize;\n\tp1.left = x1 - mask_im->Xsize / 2;\n\tp1.top = y1 - mask_im->Ysize / 2;\n\tp2.width = mask_im->Xsize;\n\tp2.height = mask_im->Ysize;\n\tp2.left = x2 - mask_im->Xsize / 2;\n\tp2.top = y2 - mask_im->Ysize / 2;\n\tim_rect_unionrect( &p1, &p2, &dirty );\n\n\timage.left = 0;\n\timage.top = 0;\n\timage.width = im->Xsize;\n\timage.height = im->Ysize;\n\tim_rect_intersectrect( &dirty, &image, &clipped );\n\n\tif( im_rect_isempty( &clipped ) )\n\t\treturn( TRUE );\n\n\tif( !imageinfo_undo_add( imageinfo, &clipped ) ) \n\t\treturn( FALSE );\n\n\tif( im_draw_line_user( im, x1, y1, x2, y2, \n\t\t(VipsPlotFn) imageinfo_draw_point_cb, mask_im, data, NULL ) ) {\n\t\terror_vips_all();\n\t\treturn( FALSE );\n\t}\n\n\timageinfo_area_painted( imageinfo, &dirty );\n\n\treturn( TRUE );\n}\n\n/* Smudge a line.\n */\ngboolean\nimageinfo_paint_smudge( Imageinfo *imageinfo, \n\tRect *oper, int x1, int y1, int x2, int y2 )\n{\t\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo ); \n\tRect p1, p2, dirty;\n\n\t/* Calculate bounding box for smudge.\n\t */\n\tp1 = *oper;\n\tp1.left += x1;\n\tp1.top += y1;\n\tp2 = *oper;\n\tp2.left += x2;\n\tp2.top += y2;\n\tim_rect_unionrect( &p1, &p2, &dirty );\n\tif( !imageinfo_undo_add( imageinfo, &dirty ) )\n\t\treturn( FALSE );\n\n\t/* Smudge line connecting old and new points. \n\t */\n\tif( im_draw_line_user( im, x1, y1, x2, y2, \n\t\t(VipsPlotFn) im_smudge, oper, NULL, NULL ) ) {\n\t\terror_vips_all();\n\t\treturn( FALSE );\n\t}\n\n\timageinfo_area_painted( imageinfo, &dirty );\n\n\treturn( TRUE );\n}\n\n/* Flood an area.\n */\ngboolean\nimageinfo_paint_flood( Imageinfo *imageinfo, Imageinfo *ink, \n\tint x, int y, gboolean blob )\n{\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo ); \n\tIMAGE *ink_im = imageinfo_get( FALSE, ink );\n\tPEL *data = (PEL *) ink_im->data;\n\tRect dirty;\n\tint result;\n\n\t/* Save undo area. We have to save the entire image since we don't know\n\t * how much the flood will change :(\n\t */\n\tdirty.left = 0;\n\tdirty.top = 0;\n\tdirty.width = im->Xsize;\n\tdirty.height = im->Ysize;\n\tif( !imageinfo_undo_add( imageinfo, &dirty ) ) \n\t\treturn( FALSE );\n\n\t/* Flood!\n\t */\n\tif( blob )\n\t\tresult = im_flood_blob( im, x, y, data, &dirty );\n\telse\n\t\tresult = im_flood( im, x, y, data, &dirty );\n\tif( result ) {\n\t\terror_vips_all();\n\t\treturn( FALSE );\n\t}\n\n\timageinfo_area_painted( imageinfo, &dirty );\n\n\treturn( TRUE );\n}\n\ngboolean\nimageinfo_paint_dropper( Imageinfo *imageinfo, Imageinfo *ink, int x, int y )\n{\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo ); \n\tIMAGE *ink_im = imageinfo_get( FALSE, ink );\n\tPEL *data = (PEL *) ink_im->data;\n\tRect dirty;\n\n\tif( im_readpoint( im, x, y, data ) ) {\n\t\terror_vips_all();\n\t\treturn( FALSE );\n\t}\n\tim_invalidate( ink_im );\n\n\tdirty.left = 0;\n\tdirty.top = 0;\n\tdirty.width = ink_im->Xsize;\n\tdirty.height = ink_im->Ysize;\n\n\timageinfo_area_painted( ink, &dirty );\n\n\treturn( TRUE );\n}\n\n/* Fill a rect.\n */\ngboolean\nimageinfo_paint_rect( Imageinfo *imageinfo, Imageinfo *ink, Rect *area )\n{\t\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo ); \n\tIMAGE *ink_im = imageinfo_get( FALSE, ink );\n\tPEL *data = (PEL *) ink_im->data;\n\n\tif( !imageinfo_undo_add( imageinfo, area ) )\n\t\treturn( FALSE );\n\n\tif( im_draw_rect( im, \n\t\tarea->left, area->top, area->width, area->height, 1, data ) ) {\n\t\terror_vips_all();\n\t\treturn( FALSE );\n\t}\n\n\timageinfo_area_painted( imageinfo, area );\n\n\treturn( TRUE );\n}\n\n/* Paint text into imageinfo, return width/height in tarea.\n */\ngboolean\nimageinfo_paint_text( Imageinfo *imageinfo, \n\tconst char *font_name, const char *text, Rect *tarea )\n{\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo );\n\n\tif( im_text( im, text, font_name, 0, 0, get_dpi() ) ) {\n\t\terror_top( _( \"Unable to paint text.\" ) );\n\t\terror_sub( _( \"Unable to paint text \\\"%s\\\" in font \\\"%s\\\".\" ), \n\t\t\ttext, font_name );\n\t\terror_vips();\n\n\t\treturn( FALSE );\n\t}\n\n\ttarea->left = 0;\n\ttarea->top = 0;\n\ttarea->width = im->Xsize;\n\ttarea->height = im->Ysize;\n\n\treturn( TRUE );\n}\n\n/* Draw a nib mask. Radius 0 means a single-pixel mask.\n */\ngboolean\nimageinfo_paint_nib( Imageinfo *imageinfo, int radius )\n{\n\tstatic PEL ink[1] = { 255 };\n\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo );\n\n\tif( radius ) {\n\t\tint r2 = radius * 2;\n\t\tIMAGE *t;\n\n\t\tif( !(t = im_open( \"imageinfo_paint_nib\", \"p\" )) ) {\n\t\t\terror_vips();\n\t\t\treturn( FALSE );\n\t\t}\n\t\tif( im_black( t, 2 * (r2 + 1), 2 * (r2 + 1), 1 ) ||\n\t\t\tim_draw_circle( t, r2, r2, r2, 1, ink ) ||\n\t\t\tim_shrink( t, im, 2, 2 ) ) {\n\t\t\tim_close( t );\n\t\t\terror_vips();\n\t\t\treturn( FALSE );\n\t\t}\n\t\tim_close( t );\n\t}\n\telse {\n\t\tif( im_black( im, 1, 1, 1 ) ||\n\t\t\tim_draw_circle( im, 0, 0, 0, 1, ink ) )\n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Paint a mask.\n */\ngboolean\nimageinfo_paint_mask( Imageinfo *imageinfo, \n\tImageinfo *ink, Imageinfo *mask, int x, int y )\n{\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo ); \n\tIMAGE *ink_im = imageinfo_get( FALSE, ink );\n\tIMAGE *mask_im = imageinfo_get( FALSE, mask );\n\tRect dirty, image, clipped;\n\n\tdirty.left = x;\n\tdirty.top = y;\n\tdirty.width = mask_im->Xsize;\n\tdirty.height = mask_im->Ysize;\n\timage.left = 0;\n\timage.top = 0;\n\timage.width = im->Xsize;\n\timage.height = im->Ysize;\n\tim_rect_intersectrect( &dirty, &image, &clipped );\n\n\tif( im_rect_isempty( &clipped ) )\n\t\treturn( TRUE );\n\n\tif( !imageinfo_undo_add( imageinfo, &clipped ) ) \n\t\treturn( FALSE );\n\n\tif( im_plotmask( im, 0, 0, \n\t\t(PEL *) ink_im->data, (PEL *) mask_im->data, &dirty ) ) {\n\t\terror_vips_all();\n\t\treturn( FALSE );\n\t}\n\n\timageinfo_area_painted( imageinfo, &dirty );\n\n\treturn( TRUE );\n}\n\n/* Print a pixel. Output has to be parseable by imageinfo_from_text().\n */\nvoid \nimageinfo_to_text( Imageinfo *imageinfo, VipsBuf *buf )\n{\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo );\n\tPEL *p = (PEL *) im->data;\n\tint i;\n\n#define PRINT_INT( T, I ) vips_buf_appendf( buf, \"%d\", ((T *)p)[I] );\n#define PRINT_FLOAT( T, I ) vips_buf_appendg( buf, ((T *)p)[I] );\n\n\tfor( i = 0; i < im->Bands; i++ ) {\n\t\tif( i )\n\t\t\tvips_buf_appends( buf, \", \" );\n\n\t\tswitch( im->BandFmt ) {\n\t\tcase IM_BANDFMT_UCHAR:\n\t\t\tPRINT_INT( unsigned char, i );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_CHAR:\n\t\t\tPRINT_INT( char, i );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_USHORT:\n\t\t\tPRINT_INT( unsigned short, i );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_SHORT:\n\t\t\tPRINT_INT( short, i );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_UINT:\n\t\t\tPRINT_INT( unsigned int, i );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_INT:\n\t\t\tPRINT_INT( int, i );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_FLOAT:\n\t\t\tPRINT_FLOAT( float, i );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_COMPLEX:\n\t\t\tvips_buf_appends( buf, \"(\" );\n\t\t\tPRINT_FLOAT( float, (i << 1) );\n\t\t\tvips_buf_appends( buf, \", \" );\n\t\t\tPRINT_FLOAT( float, (i << 1) + 1 );\n\t\t\tvips_buf_appends( buf, \")\" );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_DOUBLE:\n\t\t\tPRINT_FLOAT( double, i );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_DPCOMPLEX:\n\t\t\tvips_buf_appends( buf, \"(\" );\n\t\t\tPRINT_FLOAT( double, i << 1 );\n\t\t\tvips_buf_appends( buf, \", \" );\n\t\t\tPRINT_FLOAT( double, (i << 1) + 1 );\n\t\t\tvips_buf_appends( buf, \")\" );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tvips_buf_appends( buf, \"???\" );\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/* Set band i to value.\n */\nstatic void\nimageinfo_from_text_band( Imageinfo *imageinfo, int i, double re, double im )\n{\n\tIMAGE *image = imageinfo_get( FALSE, imageinfo );\n\tPEL *p = (PEL *) image->data;\n\tdouble mod = sqrt( re*re + im*im );\n\n\tif( i < 0 || i >= image->Bands )\n\t\treturn;\n\n#define SET_INT( T, I, X ) (((T *)p)[I] = (T) IM_RINT(X)) \n#define SET_FLOAT( T, I, X ) (((T *)p)[I] = (T) (X)) \n\n\tswitch( image->BandFmt ) {\n\tcase IM_BANDFMT_UCHAR:\n\t\tSET_INT( unsigned char, i, mod );\n\t\tbreak;\n\t\t\n\tcase IM_BANDFMT_CHAR:\n\t\tSET_INT( char, i, mod );\n\t\tbreak;\n\t\t\n\tcase IM_BANDFMT_USHORT:\n\t\tSET_INT( unsigned short, i, mod );\n\t\tbreak;\n\t\t\n\tcase IM_BANDFMT_SHORT:\n\t\tSET_INT( short, i, mod );\n\t\tbreak;\n\t\t\n\tcase IM_BANDFMT_UINT:\n\t\tSET_INT( unsigned int, i, mod );\n\t\tbreak;\n\t\t\n\tcase IM_BANDFMT_INT:\n\t\tSET_INT( int, i, mod );\n\t\tbreak;\n\t\t\n\tcase IM_BANDFMT_FLOAT:\n\t\tSET_FLOAT( float, i, mod );\n\t\tbreak;\n\t\t\n\tcase IM_BANDFMT_COMPLEX:\n\t\tSET_FLOAT( float, (i << 1), re );\n\t\tSET_FLOAT( float, (i << 1) + 1, im );\n\t\tbreak;\n\t\t\n\tcase IM_BANDFMT_DOUBLE:\n\t\tSET_FLOAT( double, i, mod );\n\t\tbreak;\n\t\t\n\tcase IM_BANDFMT_DPCOMPLEX:\n\t\tSET_FLOAT( double, i << 1, re );\n\t\tSET_FLOAT( double, (i << 1) + 1, im );\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n/* Parse a string to an imageinfo.\n * Strings are from imageinfo_to_text(), ie. of the form:\n *\n *\t50, 0, 0\n *\t(12,13), (14,15)\n *\n */\ngboolean\nimageinfo_from_text( Imageinfo *imageinfo, const char *text )\n{\n\tchar buf[MAX_LINELENGTH];\n\tchar *p;\n\tint i;\n\tRect dirty;\n\n#ifdef DEBUG_RGB\n\tprintf( \"imageinfo_from_text: in: \\\"\\%s\\\"\\n\", text );\n#endif /*DEBUG_RGB*/\n\n\tim_strncpy( buf, text, MAX_LINELENGTH );\n\n\tfor( i = 0, p = buf; p += strspn( p, WHITESPACE ), *p; i++ ) {\n\t\tdouble re, im;\n\n\t\tif( p[0] == '(' ) {\n\t\t\t/* Complex constant.\n\t\t\t */\n\t\t\tre = g_ascii_strtod( p + 1, NULL );\n\t\t\tp = break_token( p, \",\" );\n\t\t\tim = g_ascii_strtod( p, NULL );\n\t\t\tp = break_token( p, \")\" );\n\t\t}\n\t\telse {\n\t\t\t/* Real constant.\n\t\t\t */\n\t\t\tre = g_ascii_strtod( p, NULL );\n\t\t\tim = 0;\n\t\t}\n\n\t\tp = break_token( p, \",\" );\n\n\t\timageinfo_from_text_band( imageinfo, i, re, im );\n\t}\n\n#ifdef DEBUG_RGB\n{\n\tchar txt[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tprintf( \"imageinfo_from_text: out: \" );\n\timageinfo_to_text( imageinfo, &buf );\n\tprintf( \"%s\\n\", vips_buf_all( &buf ) );\n}\n#endif /*DEBUG_RGB*/\n\n\tdirty.left = 0;\n\tdirty.top = 0;\n\tdirty.width = 1;\n\tdirty.height = 1;\n\timageinfo_area_painted( imageinfo, &dirty );\n\n\treturn( TRUE );\n}\n\n/* Get the image as display RGB in rgb[0-2].\n */\nvoid\nimageinfo_to_rgb( Imageinfo *imageinfo, double *rgb )\n{\n\tConversion *conv;\n\tRect area;\n\tPEL *p;\n\tint i;\n\n#ifdef DEBUG_RGB\n{\n\tchar txt[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tprintf( \"imageinfo_to_rgb: in: \" );\n\timageinfo_to_text( imageinfo, &buf );\n\tprintf( \"%s\\n\", vips_buf_all( &buf ) );\n}\n#endif /*DEBUG_RGB*/\n\n\t/* Make a temporary conv ... we hold the ref.\n\t */\n\tconv = conversion_new( NULL );\n\tconversion_set_synchronous( conv, TRUE );\n\tconversion_set_image( conv, imageinfo );\n\tg_object_ref( G_OBJECT( conv ) );\n\tiobject_sink( IOBJECT( conv ) );\n\n\tarea.left = 0;\n\tarea.top = 0;\n\tarea.width = 1;\n\tarea.height = 1;\n\n\tif( im_prepare( conv->ireg, &area ) ) {\n\t\tUNREF( conv );\n\t\treturn;\n\t}\n        p = (PEL *) IM_REGION_ADDR( conv->ireg, area.left, area.top );\n\n\tif( imageinfo->im->Bands < 3 ) \n\t\tfor( i = 0; i < 3; i++ )\n\t\t\trgb[i] = p[0] / 255.0;\n\telse \n\t\tfor( i = 0; i < 3; i++ )\n\t\t\trgb[i] = p[i] / 255.0;\n\n#ifdef DEBUG_RGB\n\tprintf( \"imageinfo_to_rgb: out: r = %g, g = %g, b = %g\\n\", \n\t\trgb[0], rgb[1], rgb[2] );\n#endif /*DEBUG_RGB*/\n\n\tUNREF( conv );\n}\n\n/* Try to overwrite an imageinfo with a display RGB colour.\n */\nvoid\nimageinfo_from_rgb( Imageinfo *imageinfo, double *rgb )\n{\n\tImageinfogroup *imageinfogroup = \n\t\tIMAGEINFOGROUP( ICONTAINER( imageinfo )->parent );\n\tIMAGE *im = imageinfo_get( FALSE, imageinfo );\n\tImageinfo *in, *out;\n\tIMAGE *t1, *t2;\n\tint i;\n\tRect dirty;\n\n\t/* Interchange format is sRGB.\n\n\t\tFIXME ... should let other displays be used here, see\n\t\t../scraps/calibrate.[hc]\n\n\t */\n\tstruct im_col_display *display = im_col_displays( 7 );\n\n#ifdef DEBUG_RGB\n\tprintf( \"imageinfo_from_rgb: in: r = %g, g = %g, b = %g\\n\", \n\t\trgb[0], rgb[1], rgb[2] );\n#endif /*DEBUG_RGB*/\n\n\t/* Make 1 pixel images for conversion.\n\t */\n\tin = imageinfo_new_temp( imageinfogroup, \n\t\treduce_context->heap, NULL, \"t\" );\n\tout = imageinfo_new_temp( imageinfogroup, \n\t\treduce_context->heap, NULL, \"t\" );\n\tif( !in || !out )\n\t\treturn;\n\tif( !(t1 = im_open_local( out->im, \"imageinfo_from_rgb:1\", \"t\" )) ||\n\t\t!(t2 = im_open_local( out->im, \"imageinfo_from_rgb:1\", \"t\" )) )\n\t\treturn;\n\n\t/* Fill in with rgb.\n\t */\n\tim_initdesc( in->im, 1, 1, 3, \n\t\tIM_BBITS_BYTE, IM_BANDFMT_UCHAR, IM_CODING_NONE, \n\t\tIM_TYPE_sRGB, 1.0, 1.0, 0, 0 );\n\tif( im_setupout( in->im ) ) \n\t\treturn;\n\tfor( i = 0; i < 3; i++ )\n\t\t((PEL *) in->im->data)[i] = IM_RINT( rgb[i] * 255.0 );\n\n\t/* To imageinfo->type. Make sure we get a float ... except for LABQ\n\t * and RAD.\n\t */\n\tif( im->Coding == IM_CODING_LABQ ) {\n\t\tif( im_disp2Lab( in->im, t1, display ) ||\n\t\t\tim_Lab2LabQ( t1, out->im ) )\n\t\t\treturn;\n\t}\n\telse if( im->Coding == IM_CODING_RAD ) {\n\t\tif( im_disp2XYZ( in->im, t1, display ) ||\n\t\t\tim_float2rad( t1, out->im ) )\n\t\t\treturn;\n\t}\n\telse if( im->Coding == IM_CODING_NONE ) {\n\t\tswitch( im->Type ) {\n\t\tcase IM_TYPE_XYZ:\n\t\t\tif( im_disp2XYZ( in->im, out->im, display ) )\n\t\t\t\treturn;\n\t\t\tbreak;\n\n\t\tcase IM_TYPE_YXY:\n\t\t\tif( im_disp2XYZ( in->im, t1, display ) ||\n\t\t\t\tim_XYZ2Yxy( t1, out->im ) )\n\t\t\t\treturn;\n\t\t\tbreak;\n\n\t\tcase IM_TYPE_LAB:\n\t\t\tif( im_disp2Lab( in->im, out->im, display ) )\n\t\t\t\treturn;\n\t\t\tbreak;\n\n\t\tcase IM_TYPE_LCH:\n\t\t\tif( im_disp2Lab( in->im, t1, display ) ||\n\t\t\t\tim_Lab2LCh( t1, out->im ) )\n\t\t\t\treturn;\n\t\t\tbreak;\n\n\t\tcase IM_TYPE_UCS:\n\t\t\tif( im_disp2Lab( in->im, t1, display ) ||\n\t\t\t\tim_Lab2LCh( t1, t2 ) ||\n\t\t\t\tim_LCh2UCS( t2, out->im ) )\n\t\t\t\treturn;\n\t\t\tbreak;\n\n\t\tcase IM_TYPE_RGB16:\n\t\tcase IM_TYPE_GREY16:\n\t\t\tif( im_lintra( 1.0 / 256.0, in->im, 0.0, out->im ) )\n\t\t\t\treturn;\n\t\t\tbreak;\n\n\t\tcase IM_TYPE_RGB:\n\t\tcase IM_TYPE_sRGB:\n\t\tdefault:\n\t\t\tif( im_clip2fmt( in->im, out->im, IM_BANDFMT_FLOAT ) )\n\t\t\t\treturn;\n\t\t\tbreak;\n\t\t}\n\t}\n\n#define SET( TYPE, i ) ((TYPE *) im->data)[i] = ((float *) out->im->data)[i];\n\n\t/* Now ... overwrite imageinfo.\n\t */\n\tif( im->Coding == IM_CODING_LABQ ||\n\t\tim->Coding == IM_CODING_RAD ) {\n\t\tfor( i = 0; i < im->Bands; i++ ) \n\t\t\t((PEL *) im->data)[i] = ((PEL *) out->im->data)[i];\n\t}\n\telse {\n\t\tfor( i = 0; i < im->Bands; i++ )\n\t\t\tswitch( im->BandFmt ) {\n\t\t\tcase IM_BANDFMT_UCHAR:          \n\t\t\t\tSET( unsigned char, i ); \n\t\t\t\tbreak;\n\n\t\t\tcase IM_BANDFMT_CHAR:           \n\t\t\t\tSET( signed char, i ); \n\t\t\t\tbreak;\n\n\t\t\tcase IM_BANDFMT_USHORT:         \n\t\t\t\tSET( unsigned short, i ); \n\t\t\t\tbreak;\n\n\t\t\tcase IM_BANDFMT_SHORT:          \n\t\t\t\tSET( signed short, i ); \n\t\t\t\tbreak;\n\n\t\t\tcase IM_BANDFMT_UINT:           \n\t\t\t\tSET( unsigned int, i ); \n\t\t\t\tbreak;\n\n\t\t\tcase IM_BANDFMT_INT:            \n\t\t\t\tSET( signed int, i );  \n\t\t\t\tbreak;\n\n\t\t\tcase IM_BANDFMT_FLOAT:          \n\t\t\t\tSET( float, i ); \n\t\t\t\tbreak;\n\n\t\t\tcase IM_BANDFMT_DOUBLE:         \n\t\t\t\tSET( double, i ); \n\t\t\t\tbreak;\n\n\t\t\tcase IM_BANDFMT_COMPLEX:        \n\t\t\t\tSET( float, i * 2 ); \n\t\t\t\tSET( float, i * 2 + 1 ); \n\t\t\t\tbreak;\n\n\t\t\tcase IM_BANDFMT_DPCOMPLEX:      \n\t\t\t\tSET( double, i * 2 ); \n\t\t\t\tSET( double, i * 2 + 1 ); \n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tg_assert( FALSE );\n\t\t\t}\n\t}\n\tim_invalidate( im );\n\n#ifdef DEBUG_RGB\n{\n\tchar txt[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tprintf( \"imageinfo_from_rgb: out: \" );\n\timageinfo_to_text( imageinfo, &buf );\n\tprintf( \"%s\\n\", vips_buf_all( &buf ) );\n}\n#endif /*DEBUG_RGB*/\n\n\tdirty.left = 0;\n\tdirty.top = 0;\n\tdirty.width = 1;\n\tdirty.height = 1;\n\timageinfo_area_painted( imageinfo, &dirty );\n}\n\n/* Widgets for colour edit.\n */\ntypedef struct _ColourEdit {\n\tiDialog *idlg;\n\n\tImageinfo *imageinfo;\n\tGtkWidget *colour_widget;\n} ColourEdit;\n\n/* Done button hit.\n */\nstatic void\nimageinfo_colour_done_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tColourEdit *eds = (ColourEdit *) client;\n\tImageinfo *imageinfo = eds->imageinfo;\n\tdouble rgb[4];\n\n\tgtk_color_selection_get_color( \n\t\tGTK_COLOR_SELECTION( eds->colour_widget ), rgb );\n\n\t/* This will emit \"area_painted\" on our imageinfo.\n\t */\n\timageinfo_from_rgb( imageinfo, rgb );\n\n\tnfn( sys, IWINDOW_YES );\n}\n\n/* Build the insides of colour edit.\n */\nstatic void\nimageinfo_colour_buildedit( iDialog *idlg, GtkWidget *work, ColourEdit *eds )\n{\n\tImageinfo *imageinfo = eds->imageinfo;\n\tdouble rgb[4];\n\n\teds->colour_widget = gtk_color_selection_new();\n\tgtk_color_selection_set_has_opacity_control( \n\t\tGTK_COLOR_SELECTION( eds->colour_widget ), FALSE );\n\timageinfo_to_rgb( imageinfo, rgb );\n\tgtk_color_selection_set_color( \n\t\tGTK_COLOR_SELECTION( eds->colour_widget ), rgb );\n        gtk_box_pack_start( GTK_BOX( work ), \n\t\teds->colour_widget, TRUE, TRUE, 2 );\n\n        gtk_widget_show_all( work );\n}\n\nvoid\nimageinfo_colour_edit( GtkWidget *parent, Imageinfo *imageinfo )\n{\n\tColourEdit *eds = INEW( NULL, ColourEdit );\n\tGtkWidget *idlg;\n\n\teds->imageinfo = imageinfo;\n\n\tidlg = idialog_new();\n\tiwindow_set_title( IWINDOW( idlg ), \"Edit Colour\" );\n\tidialog_set_build( IDIALOG( idlg ), \n\t\t(iWindowBuildFn) imageinfo_colour_buildedit, eds, NULL, NULL );\n\tidialog_set_callbacks( IDIALOG( idlg ), \n\t\tiwindow_true_cb, NULL, idialog_free_client, eds );\n\tidialog_add_ok( IDIALOG( idlg ), \n\t\timageinfo_colour_done_cb, \"Set Colour\" );\n\tiwindow_set_parent( IWINDOW( idlg ), parent );\n\tidialog_set_iobject( IDIALOG( idlg ), IOBJECT( imageinfo ) );\n\tiwindow_build( IWINDOW( idlg ) );\n\n\tgtk_widget_show( GTK_WIDGET( idlg ) );\n}\n"
  },
  {
    "path": "src/imageinfo.h",
    "content": "/* Decls for imageinfo.c\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* Meta we attach for the filename we loaded from.\n */\n#define ORIGINAL_FILENAME \"original-filename\"\n\n/* Group imageinfo with this.\n */\n\n#define TYPE_IMAGEINFOGROUP (imageinfogroup_get_type())\n#define IMAGEINFOGROUP( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), \\\n\t\tTYPE_IMAGEINFOGROUP, Imageinfogroup ))\n#define IMAGEINFOGROUP_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_IMAGEINFOGROUP, ImageinfogroupClass))\n#define IS_IMAGEINFOGROUP( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IMAGEINFOGROUP ))\n#define IS_IMAGEINFOGROUP_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEINFOGROUP ))\n#define IMAGEINFOGROUP_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), \\\n\t\tTYPE_IMAGEINFOGROUP, ImageinfogroupClass ))\n\ntypedef struct _Imageinfogroup {\n\tiContainer parent_object;\n\n\t/* Hash from filename to list of imageinfo. We can't use the\n\t * icontainer hash, since our filenames are not unique (we can have\n\t * the same file loaded several times, if some other application is\n\t * changing our files behind our back).\n\t */\n\tGHashTable *filename_hash;\n} Imageinfogroup;\n\ntypedef struct _ImageinfogroupClass {\n\tiContainerClass parent_class;\n\n} ImageinfogroupClass;\n\nGType imageinfogroup_get_type( void );\nImageinfogroup *imageinfogroup_new( void );\n\n/* An image.\n */\n\n#define TYPE_IMAGEINFO (imageinfo_get_type())\n#define IMAGEINFO( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IMAGEINFO, Imageinfo ))\n#define IMAGEINFO_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_IMAGEINFO, ImageinfoClass))\n#define IS_IMAGEINFO( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IMAGEINFO ))\n#define IS_IMAGEINFO_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEINFO ))\n#define IMAGEINFO_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_IMAGEINFO, ImageinfoClass ))\n\n/* A fragment of an undo buffer.\n */\ntypedef struct _Undofragment {\n\tstruct _Undobuffer *undo;\t/* Main undo area */\n\tIMAGE *im;\t\t\t/* Old area */\n\tRect pos;\t\t\t/* Where we took it from */\n} Undofragment;\n\n/* Hold a list of the above, a bounding box for this list and a link back to\n * the main imageinfo.\n */\ntypedef struct _Undobuffer {\n\tstruct _Imageinfo *imageinfo;\t/* Main paint area */\n\tGSList *frags;\t\t\t/* List of paint fragments */\n\tRect bbox;\t\t\t/* Bounding box for frags */\n} Undobuffer;\n\n/* Attach one of these to any IMAGE we monitor. It has the same lifetime as\n * the IMAGE and gets zapped by the imageinfo on dispose. This lets us spot\n * IMAGE events after the holding Imageinfo has gone.\n */\ntypedef struct _Imageinfoproxy {\n\tIMAGE *im;\n\tImageinfo *imageinfo;\n} Imageinfoproxy;\n\n/* A VIPS image wrapped up nicely.\n */\nstruct _Imageinfo {\n\tManaged parent_object;\n\n\tIMAGE *im;\t\t/* Image we manage, LUT if delayed */\n\tIMAGE *mapped_im;\t/* Cache image mapped-thru-lut here */\n\tIMAGE *identity_lut;\t/* For base images, keep an id lut if poss */\n\tImageinfo *underlying;\t/* If we're a LUT, the image we are a LUT of */\n\tImageinfoproxy *proxy;\t/* Proxy for IMAGE callbacks */\n\n\tgboolean dfile;\t\t/* delete_file on final close */\n\tchar *delete_filename;  /* and the file we delete */\n\n\tgboolean from_file;\t/* Set if ->name is a user file */\n\ttime_t mtime;\t\t/* What mtime was when we loaded this file */\n\n\t/* Exprs which are thought to have this image as their value. See\n\t * expr_value_new().\n\t */\n\tGSList *exprs;\n\n\t/* Set if we've checked with the user that it's OK to paint on this\n\t * imageinfo.\n\t */\n\tgboolean ok_to_paint;\n\n\t/* Undo/redo buffers.\n\t */\n\tGSList *undo;\t\t\t/* List of undo buffers */\n\tGSList *redo;\t\t\t/* List of redo buffers */\n\tUndobuffer *cundo;\t\t/* Current buffer */\n\n\t/* Have we attached progress stuff to this ii?\n\t */\n\tgboolean monitored;\n\n\t/* If we're from a file, the timestamp on the file we loaded from ...\n\t * used to spot changes.\n\t */\n\ttime_t check_mtime;\n\tguint check_tid;\n};\n\ntypedef struct _ImageinfoClass {\n\tManagedClass parent_class;\n\n\t/* An area of the screen needs repainting. This can happen for regions\n\t * being dragged, for example, and doesn't always mean pixels have\n\t * changed.\n\t */\n\tvoid (*area_changed)( Imageinfo *, Rect * );\n\n\t/* An area of the image has been paintboxed ... invalidate caches and\n\t * trigger area_changed.\n\t */\n\tvoid (*area_painted)( Imageinfo *, Rect * );\n\n\t/* Our IMAGE* has signaled \"invalidate\". This can happen indirectly:\n\t * if we paint on an image, im_invalidate() will trigger on that image\n\t * and all derived images.\n\t */\n\tvoid (*invalidate)( Imageinfo * );\n\n\t/* Update undo/redo button sensitivities.\n\t */\n\tvoid (*undo_changed)( Imageinfo * );\n\n\t/* The underlying file has changed ... higher levels should try to \n\t * reload.\n\t */\n\tvoid (*file_changed)( Imageinfo * );\n} ImageinfoClass;\n\nvoid *imageinfo_area_changed( Imageinfo *imageinfo, Rect *dirty );\nvoid *imageinfo_area_painted( Imageinfo *imageinfo, Rect *dirty );\n\nvoid *imageinfo_expr_remove( Expr *expr, Imageinfo *imageinfo );\nvoid imageinfo_expr_add( Imageinfo *imageinfo, Expr *expr );\nGSList *imageinfo_expr_which( Imageinfo *imageinfo );\nIMAGE *imageinfo_get_underlying( Imageinfo *imageinfo );\n\nGType imageinfo_get_type( void );\nImageinfo *imageinfo_new( Imageinfogroup *imageinfogroup, \n\tHeap *heap, IMAGE *im, const char *name );\nImageinfo *imageinfo_new_temp( Imageinfogroup *imageinfogroup, \n\tHeap *heap, const char *name, const char *mode );\nImageinfo *imageinfo_new_from_pixbuf( Imageinfogroup *imageinfogroup, \n\tHeap *heap, GdkPixbuf *pixbuf );\nvoid imageinfo_set_underlying( Imageinfo *top_imageinfo, Imageinfo *imageinfo );\ngboolean imageinfo_is_from_file( Imageinfo *imageinfo );\nImageinfo *imageinfo_new_input( Imageinfogroup *imageinfogroup, \n\tGtkWidget *parent, Heap *heap, const char *name );\n\nIMAGE *imageinfo_get( gboolean use_lut, Imageinfo *imageinfo );\ngboolean imageinfo_same_underlying( Imageinfo *imageinfo[], int n );\n\ngboolean imageinfo_write( Imageinfo *imageinfo, const char *filename );\ngboolean imageinfo_check_paintable( Imageinfo *imageinfo, \n\tGtkWidget *parent, iWindowNotifyFn nfn, void *sys );\n\nvoid imageinfo_note( Symbol *sym, Imageinfo *imageinfo );\nvoid imageinfo_forget( Symbol *sym, Imageinfo *imageinfo );\nGSList *imageinfo_which( Imageinfo *im );\n\nvoid imageinfo_make_sub( Imageinfo *out, int n, Imageinfo **in );\nvoid imageinfo_mark( Imageinfo *imageinfo );\n\nImageinfo *imageinfo_sym_image( Symbol *sym );\n\nvoid imageinfo_undo_mark( Imageinfo *imageinfo );\ngboolean imageinfo_undo( Imageinfo *imageinfo );\ngboolean imageinfo_redo( Imageinfo *imageinfo );\nvoid imageinfo_undo_clear( Imageinfo *imageinfo );\n\ngboolean imageinfo_paint_line( Imageinfo *imageinfo, \n\tImageinfo *ink, Imageinfo *mask, \n\tint x1, int y1, int x2, int y2 );\ngboolean imageinfo_paint_flood( Imageinfo *imageinfo, Imageinfo *ink,  \n\tint x, int y, gboolean blob );\ngboolean imageinfo_paint_smudge( Imageinfo *imageinfo, \n\tRect *oper, int x1, int y1, int x2, int y2 );\ngboolean imageinfo_paint_dropper( Imageinfo *imageinfo, Imageinfo *ink, \n\tint x, int iy );\ngboolean imageinfo_paint_rect( Imageinfo *imageinfo, Imageinfo *ink, \n\tRect *area );\ngboolean imageinfo_paint_text( Imageinfo *imageinfo, \n\tconst char *font_name, const char *text, Rect *tarea );\ngboolean imageinfo_paint_nib( Imageinfo *imageinfo, int nib_radius );\ngboolean imageinfo_paint_mask( Imageinfo *imageinfo, \n\tImageinfo *ink, Imageinfo *mask, int x, int y );\n\nvoid imageinfo_to_text( Imageinfo *imageinfo, VipsBuf *buf );\ngboolean imageinfo_from_text( Imageinfo *imageinfo, const char *text );\nvoid imageinfo_to_rgb( Imageinfo *imageinfo, double *rgb );\nvoid imageinfo_from_rgb( Imageinfo *imageinfo, double *rgb );\nvoid imageinfo_colour_edit( GtkWidget *parent, Imageinfo *imageinfo );\n\n"
  },
  {
    "path": "src/imagemodel.c",
    "content": "/* All the model stuff for an imageview window.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* Our signals. \n */\nenum {\n\tSIG_IMAGEINFO_CHANGED,\t/* Imageinfo we hold has been replaced */\n\tSIG_LAST\n};\n\nstatic iObjectClass *parent_class = NULL;\n\nstatic guint imagemodel_signals[SIG_LAST] = { 0 };\n\nvoid *\nimagemodel_imageinfo_changed( Imagemodel *imagemodel )\n{\n#ifdef DEBUG\n\tprintf( \"imagemodel_imageinfo_changed: \" );\n\tiobject_print( IOBJECT( imagemodel ) );\n#endif /*DEBUG*/\n\n\tg_signal_emit( G_OBJECT( imagemodel ), \n\t\timagemodel_signals[SIG_IMAGEINFO_CHANGED], 0 );\n\n\treturn( NULL );\n}\n\n/* Is a state a paint state, ie. one which might alter the image? We warn\n * before going to one of these.\n */\ngboolean\nimagemodel_state_paint( ImagemodelState state )\n{\n\tstatic gboolean state_paint[IMAGEMODEL_LAST] = {\n\t\tFALSE,\t\t/* IMAGEMODEL_SELECT */\n\t\tFALSE,\t\t/* IMAGEMODEL_PAN */\n\t\tFALSE,\t\t/* IMAGEMODEL_MAGIN */\n\t\tFALSE,\t\t/* IMAGEMODEL_MAGOUT */\n\t\tFALSE,\t\t/* IMAGEMODEL_DROPPER */\n\t\tTRUE,\t\t/* IMAGEMODEL_PEN */\n\t\tTRUE,\t\t/* IMAGEMODEL_LINE */\n\t\tTRUE,\t\t/* IMAGEMODEL_RECT */\n\t\tTRUE,\t\t/* IMAGEMODEL_FLOOD */\n\t\tTRUE,\t\t/* IMAGEMODEL_BLOB */\n\t\tTRUE,\t\t/* IMAGEMODEL_TEXT */\n\t\tTRUE\t\t/* IMAGEMODEL_SMUDGE */\n\t};\n\n\tg_assert( state < IMAGEMODEL_LAST );\n\n\treturn( state_paint[state] );\n}\n\n#ifdef DEBUG\nstatic const char *\nimagemodel_state( ImagemodelState state )\n{\n\tswitch( state ) {\n\tcase IMAGEMODEL_SELECT: \treturn( \"IMAGEMODEL_SELECT\" );\n\tcase IMAGEMODEL_PAN: \t\treturn( \"IMAGEMODEL_PAN\" );\n\tcase IMAGEMODEL_MAGIN: \t\treturn( \"IMAGEMODEL_MAGIN\" );\n\tcase IMAGEMODEL_MAGOUT:\t\treturn( \"IMAGEMODEL_MAGOUT\" );\n\tcase IMAGEMODEL_DROPPER: \treturn( \"IMAGEMODEL_DROPPER\" );\n\tcase IMAGEMODEL_PEN: \t\treturn( \"IMAGEMODEL_PEN\" );\n\tcase IMAGEMODEL_LINE: \t\treturn( \"IMAGEMODEL_LINE\" );\n\tcase IMAGEMODEL_RECT: \t\treturn( \"IMAGEMODEL_RECT\" );\n\tcase IMAGEMODEL_FLOOD: \t\treturn( \"IMAGEMODEL_FLOOD\" );\n\tcase IMAGEMODEL_BLOB: \t\treturn( \"IMAGEMODEL_BLOB\" );\n\tcase IMAGEMODEL_TEXT: \t\treturn( \"IMAGEMODEL_TEXT\" );\n\tcase IMAGEMODEL_SMUDGE: \treturn( \"IMAGEMODEL_SMUDGE\" );\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n}\n#endif /*DEBUG*/\n\nstatic void\nimagemodel_dispose( GObject *gobject )\n{\n\tImagemodel *imagemodel;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_IMAGEMODEL( gobject ) );\n\n\timagemodel = IMAGEMODEL( gobject );\n\n#ifdef DEBUG\n\tprintf( \"imagemodel_dispose %p: \", imagemodel );\n\tiobject_print( IOBJECT( imagemodel ) );\n#endif /*DEBUG*/\n\n\tFREESID( imagemodel->iimage_changed_sid, imagemodel->iimage ); \n\tFREESID( imagemodel->iimage_destroy_sid, imagemodel->iimage ); \n\tFREESID( imagemodel->conv_changed_sid, imagemodel->conv );\n\tFREESID( imagemodel->conv_imageinfo_changed_sid, imagemodel->conv );\n\tUNREF( imagemodel->conv );\n\tMANAGED_UNREF( imagemodel->ink );\n\tIM_FREE( imagemodel->font_name );\n\tIM_FREE( imagemodel->text );\n\tMANAGED_UNREF( imagemodel->text_mask );\n\tMANAGED_UNREF( imagemodel->nib );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\nimagemodel_changed( iObject *iobject )\n{\n\tImagemodel *imagemodel = IMAGEMODEL( iobject );\n\n#ifdef DEBUG\n\tprintf( \"imagemodel_changed: state = %s \", \n\t\timagemodel_state( imagemodel->state ) );\n\tiobject_print( IOBJECT( imagemodel ) );\n#endif /*DEBUG*/\n\n\tconversion_set_params( imagemodel->conv,\n\t\timagemodel->show_convert,\n\t\timagemodel->scale, imagemodel->offset,\n\t\timagemodel->falsecolour, imagemodel->type );\n\n\t/* Update prefs.\n\t */\n\tprefs_set( \"DISPLAY_RULERS\", \n\t\t\"%s\", bool_to_char( imagemodel->show_rulers ) );\n\tprefs_set( \"DISPLAY_STATUS\", \n\t\t\"%s\", bool_to_char( imagemodel->show_status ) );\n\tprefs_set( \"DISPLAY_CONVERSION\", \n\t\t\"%s\", bool_to_char( imagemodel->show_convert ) );\n\n\t/* If the paint bar is on, we want to be in synchronous paint\n\t * mode. Even if we're not painting, we need this for\n\t * undo/redo to work.\n\t */\n\tconversion_set_synchronous( imagemodel->conv, \n\t\timagemodel->show_paintbox );\n\n\tIOBJECT_CLASS( parent_class )->changed( iobject );\n}\n\nstatic void\nimagemodel_class_init( ImagemodelClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = imagemodel_dispose;\n\n\tiobject_class->changed = imagemodel_changed;\n\n\timagemodel_signals[SIG_IMAGEINFO_CHANGED] = g_signal_new( \n\t\t\"imageinfo_changed\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ImagemodelClass, imageinfo_changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n}\n\n/* Remake the ink image to match ii.\n */\nstatic void\nimagemodel_refresh_ink( Imagemodel *imagemodel, Imageinfo *ii )\n{\n\tIMAGE *main_im = imageinfo_get( FALSE, ii );\n\tIMAGE *ink_im = imageinfo_get( FALSE, imagemodel->ink );\n\n\tif( ink_im &&\n\t\tink_im->Bands == main_im->Bands &&\n\t\tink_im->BandFmt == main_im->BandFmt &&\n\t\tink_im->Coding == main_im->Coding &&\n\t\tink_im->Type == main_im->Type ) \n\t\treturn;\n\n\tMANAGED_UNREF( imagemodel->ink );\n\n\tif( (imagemodel->ink = imageinfo_new_temp( \n\t\tmain_imageinfogroup, \n\t\treduce_context->heap, NULL, \"t\" )) ) {\n\t\tMANAGED_REF( imagemodel->ink );\n\t\tim_initdesc( imagemodel->ink->im, \n\t\t\t1, 1, main_im->Bands, \n\t\t\tmain_im->Bbits, main_im->BandFmt, \n\t\t\tmain_im->Coding, main_im->Type, \n\t\t\t1.0, 1.0, 0, 0 );\n\t\tif( im_setupout( imagemodel->ink->im ) ) \n\t\t\tMANAGED_UNREF( imagemodel->ink );\n\t}\n\n\tif( imagemodel->ink && imagemodel->ink->im && \n\t\timagemodel->ink->im->data )\n\t\tmemset( imagemodel->ink->im->data, 0, \n\t\t\tIM_IMAGE_SIZEOF_LINE( imagemodel->ink->im ) );\n}\n\nstatic void\nimagemodel_conv_changed_cb( Conversion *conv, Imagemodel *imagemodel )\n{\n\tif( conv->ii )\n\t\timagemodel_refresh_ink( imagemodel, conv->ii );\n\n\tiobject_changed( IOBJECT( imagemodel ) );\n}\n\nstatic void\nimagemodel_conv_imageinfo_changed_cb( Conversion *conv, Imagemodel *imagemodel )\n{\n\timagemodel_imageinfo_changed( imagemodel );\n}\n\nstatic void\nimagemodel_init( Imagemodel *imagemodel )\n{\n\timagemodel->iimage = NULL;\n\timagemodel->iimage_changed_sid = 0;\n\timagemodel->iimage_destroy_sid = 0;\n\n\timagemodel->conv = conversion_new( NULL );\n\tg_object_ref( G_OBJECT( imagemodel->conv ) );\n\tiobject_sink( IOBJECT( imagemodel->conv ) );\n\n\timagemodel->conv_changed_sid = g_signal_connect( \n\t\tG_OBJECT( imagemodel->conv ), \"changed\", \n\t\tG_CALLBACK( imagemodel_conv_changed_cb ), imagemodel );\n\timagemodel->conv_imageinfo_changed_sid = g_signal_connect( \n\t\tG_OBJECT( imagemodel->conv ), \"imageinfo_changed\", \n\t\tG_CALLBACK( imagemodel_conv_imageinfo_changed_cb ), \n\t\timagemodel );\n\n\timagemodel->conv->priority = 1;\n\n\timagemodel->show_rulers = DISPLAY_RULERS;\n\timagemodel->rulers_mm = FALSE;\n\timagemodel->rulers_offset = FALSE;\n\n\timagemodel->show_status = DISPLAY_STATUS;\n\n\timagemodel->show_paintbox = FALSE;\n\timagemodel->nib_radius = 0;\n\timagemodel->nib = NULL;\n\timagemodel->ink = NULL;\n\timagemodel->font_name = im_strdup( NULL, PAINTBOX_FONT );\n\timagemodel->text = NULL;\n\timagemodel->text_mask = NULL;\n\n\timagemodel->show_convert = DISPLAY_CONVERSION;\n\timagemodel->scale = 1.0;\n\timagemodel->offset = 0.0;\n\timagemodel->falsecolour = FALSE;\n\timagemodel->type = TRUE;\n}\n\nGType\nimagemodel_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ImagemodelClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) imagemodel_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Imagemodel ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) imagemodel_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_IOBJECT, \n\t\t\t\"Imagemodel\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\nimagemodel_iimage_destroy_cb( iImage *iimage, Imagemodel *imagemodel )\n{\n\timagemodel->iimage = NULL;\n\timagemodel->iimage_destroy_sid = 0;\n\timagemodel->iimage_changed_sid = 0;\n}\n\nstatic void\nimagemodel_iimage_changed_cb( iImage *iimage, Imagemodel *imagemodel )\n{\n\tconversion_set_image( imagemodel->conv, iimage->value.ii );\n}\n\nstatic void\nimagemodel_link( Imagemodel *imagemodel, iImage *iimage )\n{\n\tRow *row = HEAPMODEL( iimage )->row;\n\n\timagemodel->iimage = iimage;\n\timagemodel->iimage_destroy_sid = g_signal_connect( G_OBJECT( iimage ), \n\t\t\"destroy\", \n\t\tG_CALLBACK( imagemodel_iimage_destroy_cb ), imagemodel );\n\timagemodel->iimage_changed_sid = g_signal_connect( G_OBJECT( iimage ), \n\t\t\"changed\", \n\t\tG_CALLBACK( imagemodel_iimage_changed_cb ), imagemodel );\n\timagemodel->scale = row->ws->scale;\n\timagemodel->offset = row->ws->offset;\n\n\t/* Install image.\n\t */\n\tconversion_set_image( imagemodel->conv, iimage->value.ii );\n\n\t/* Set name ... handy for debugging.\n\t */\n\tiobject_set( IOBJECT( imagemodel ), \n\t\trow_name( HEAPMODEL( iimage )->row ), NULL );\n}\n\nImagemodel *\nimagemodel_new( iImage *iimage )\n{\n\tImagemodel *imagemodel;\n\n\timagemodel = g_object_new( TYPE_IMAGEMODEL, NULL );\n\n\tif( iimage )\n\t\timagemodel_link( imagemodel, iimage );\n\n#ifdef DEBUG\n\tprintf( \"imagemodel_new: \" );\n\tiobject_print( IOBJECT( imagemodel ) );\n#endif /*DEBUG*/\n\n\treturn( imagemodel );\n}\n\n/* Callback for check_paintable() in imagemodel_set_state. \n */\nstatic void\nimagemodel_set_paintbox_cb( void *client, iWindowResult result )\n{\n\tImagemodel *imagemodel = IMAGEMODEL( client );\n\n#ifdef DEBUG\n\tprintf( \"imagemodel_set_paintbox_cb: pend_state = %s\\n\", \n\t\timagemodel_state( imagemodel->pend_state ) );\n#endif /*DEBUG*/\n\n\tif( result == IWINDOW_YES ) {\n\t\timagemodel_set_paintbox( imagemodel, TRUE );\n\n\t\tif( imagemodel->state != imagemodel->pend_state ) {\n\t\t\timagemodel->state = imagemodel->pend_state;\n\t\t\tiobject_changed( IOBJECT( imagemodel ) );\n\t\t}\n\t}\n}\n\n/* Set the viewer state. We can't always do this immediately, we may need to\n * ask the user if the change is OK. Return TRUE if we were able to make the\n * change now.\n */\ngboolean\nimagemodel_set_state( Imagemodel *imagemodel, ImagemodelState state, \n\tGtkWidget *parent )\n{\n\tgboolean changed = FALSE;\n\n#ifdef DEBUG\n\tprintf( \"imagemodel_set_state: %s\\n\", imagemodel_state( state ) );\n#endif /*DEBUG*/\n\n\tif( state != imagemodel->state && imagemodel_state_paint( state ) ) {\n\t\t/* Check and warn on this image first.\n\t\t */\n\t\timagemodel->pend_state = state;\n\t\timageinfo_check_paintable( imagemodel->conv->ii, \n\t\t\tparent, imagemodel_set_paintbox_cb, imagemodel );\n\n\t\t/* We may not have set the state yet ... signal \"changed\" \n\t\t * to flick whatever asked for this change (eg. View\n\t\t * menu) back to the old state.\n\t\t */\n\t\tchanged = TRUE;\n\t}\n\telse if( state != imagemodel->state ) {\n\t\timagemodel->state = state;\n\t\tchanged = TRUE;\n\t}\n\n\tif( changed )\n\t\tiobject_changed( IOBJECT( imagemodel ) );\n\n\treturn( imagemodel->state == state );\n}\n\nvoid\nimagemodel_set_rulers( Imagemodel *imagemodel, gboolean show_rulers )\n{\n\tif( imagemodel->show_rulers != show_rulers ) {\n\t\timagemodel->show_rulers = show_rulers;\n\t\tiobject_changed( IOBJECT( imagemodel ) );\n\t}\n}\n\nvoid\nimagemodel_set_paintbox( Imagemodel *imagemodel, gboolean show_paintbox )\n{\n\tif( imagemodel->show_paintbox != show_paintbox ) {\n#ifdef DEBUG\n\t\tprintf( \"imagemodel_set_paintbox: \" );\n\t\tiobject_print( IOBJECT( imagemodel ) );\n#endif /*DEBUG*/\n\n\t\timagemodel->show_paintbox = show_paintbox;\n\n\t\t/* If the paint bar is off, we want to not be in a paint mode.\n\t\t */\n\t\tif( !imagemodel->show_paintbox && \n\t\t\timagemodel_state_paint( imagemodel->state ) )\n\t\t\timagemodel_set_state( imagemodel, \n\t\t\t\tIMAGEMODEL_SELECT, NULL );\n\n\t\tiobject_changed( IOBJECT( imagemodel ) );\n\t}\n}\n\nvoid\nimagemodel_set_status( Imagemodel *imagemodel, gboolean show_status )\n{\n\tif( imagemodel->show_status != show_status ) {\n\t\timagemodel->show_status = show_status;\n\t\tiobject_changed( IOBJECT( imagemodel ) );\n\t}\n}\n\nvoid\nimagemodel_set_convert( Imagemodel *imagemodel, gboolean show_convert )\n{\n\tif( imagemodel->show_convert != show_convert ) {\n\t\timagemodel->show_convert = show_convert;\n\t\tiobject_changed( IOBJECT( imagemodel ) );\n\t}\n}\n\n/* Update the text_mask. imagemodel->text is kept up to date with what's in the\n * paintbox text widget, call this just before a paint action to render the\n * mask.\n */\ngboolean\nimagemodel_refresh_text( Imagemodel *imagemodel )\n{\n\tconst char *text = imagemodel->text;\n\n\tif( !text || strspn( text, WHITESPACE ) == strlen( text ) ) {\n\t\terror_top( _( \"No text specified.\" ) );\n\t\terror_sub( _( \"Enter some text to paint in the entry widget at \"\n\t\t\t\"the top of the window.\" ) );\n\t\treturn( FALSE );\n\t}\n\n\tMANAGED_UNREF( imagemodel->text_mask );\n\n\tif( !(imagemodel->text_mask = imageinfo_new_temp( main_imageinfogroup, \n\t\t\treduce_context->heap, NULL, \"t\" )) ) \n\t\treturn( FALSE );\n\n\tMANAGED_REF( imagemodel->text_mask );\n\n\tif( !imageinfo_paint_text( imagemodel->text_mask, \n\t\timagemodel->font_name, imagemodel->text, \n\t\t&imagemodel->text_area ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\ngboolean\nimagemodel_refresh_nib( Imagemodel *imagemodel )\n{\n\tMANAGED_UNREF( imagemodel->nib );\n\n\tif( !(imagemodel->nib = imageinfo_new_temp( main_imageinfogroup, \n\t\t\treduce_context->heap, NULL, \"t\" )) ) \n\t\treturn( FALSE );\n\n\tMANAGED_REF( imagemodel->nib );\n\n\tif( !imageinfo_paint_nib( imagemodel->nib, imagemodel->nib_radius ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* After a paint action: mark all subsequent things dirty, recalc if prefs say\n * so.\n */\nvoid\nimagemodel_paint_recalc( Imagemodel *imagemodel )\n{\n\tClassmodel *classmodel = CLASSMODEL( imagemodel->iimage );\n\tRow *row = HEAPMODEL( classmodel )->row;\n\n#ifdef DEBUG\n\tprintf( \"imagemodel_paint_recalc: \" );\n\tiobject_print( IOBJECT( imagemodel ) );\n#endif /*DEBUG*/\n\n\texpr_dirty_intrans( row->expr, link_serial_new() );\n\n\tif( PAINTBOX_RECOMP )\n\t\tsymbol_recalculate_all();\n}\n"
  },
  {
    "path": "src/imagemodel.h",
    "content": "/* All the model stuff for the widgets making up a single imageview window. \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_IMAGEMODEL (imagemodel_get_type())\n#define IMAGEMODEL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IMAGEMODEL, Imagemodel ))\n#define IMAGEMODEL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_IMAGEMODEL, ImagemodelClass))\n#define IS_IMAGEMODEL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IMAGEMODEL ))\n#define IS_IMAGEMODEL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEMODEL ))\n#define IMAGEMODEL_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_IMAGEMODEL, ImagemodelClass ))\n\n/* Input states.\n */\ntypedef enum _ImagemodelState {\n\tIMAGEMODEL_SELECT = 0,\t\t/* Pointer */\n\tIMAGEMODEL_PAN,\t\t\t/* Hand panner */\n\tIMAGEMODEL_MAGIN,\t\t/* Zoom in */\n\tIMAGEMODEL_MAGOUT,\t\t/* Zoom out */\n\tIMAGEMODEL_DROPPER,\t\t/* Ink dropper */\n\tIMAGEMODEL_PEN,\t\t\t/* Pen */\n\tIMAGEMODEL_LINE,\t\t/* Line drawing tool */\n\tIMAGEMODEL_RECT,\t\t/* Rectangle tool */\n\tIMAGEMODEL_FLOOD,\t\t/* Flood-fill tool */\n\tIMAGEMODEL_BLOB,\t\t/* Blob flood-fill tool */\n\tIMAGEMODEL_TEXT,\t\t/* Text tool */\n\tIMAGEMODEL_SMUDGE,\t\t/* Blur */\n\tIMAGEMODEL_LAST\t\n} ImagemodelState;\n\nstruct _Imagemodel {\n\tiObject parent_class;\n\n\t/* Context.\n\t */\n\tiImage *iimage;\t\t\t/* iImage we represent, if any */\n\tguint iimage_changed_sid;\n\tguint iimage_destroy_sid;\n\n\t/* State held in sub-objects.\n\t */\n\tConversion *conv;\t\t/* Conversion to screen */\n\tguint conv_changed_sid;\n\tguint conv_imageinfo_changed_sid;\n\tRect visible;\t\t\t/* Visible part of canvas */\n\n\t/* Input state.\n\t */\n\tImagemodelState state;\n\tImagemodelState save_state; \t/* Old state, during temp actions */\n\tImagemodelState pend_state; \t/* To-be state, during delayed switch */\n\n\t/* Rulers.\n\t */\n\tgboolean show_rulers;\n\tgboolean rulers_mm;\n\tgboolean rulers_offset;\n\n\t/* Status bar.\n\t */\n\tgboolean show_status;\t\n\n\t/* Paintbox.\n\t */\n\tgboolean show_paintbox;\t\t/* Visible/not */\n\tint nib_radius;\t\t\t/* Selected radius */\n\tImageinfo *nib;\t\t\t/* Generated nib mask */\n\tImageinfo *ink;\t\t\t/* 1x1 pixel ink image */\n\tchar *font_name;\t\t/* Selected font name */\n\tchar *text; \t\t\t/* Text to render */\n\tImageinfo *text_mask; \t\t/* As a bitmap */\n\tRect text_area; \t\t/* Text geometry */\n\n\t/* Display control bar.\n\t */\n\tgboolean show_convert;\n\tdouble scale;\t\t\t/* Contrast/brightness */\n\tdouble offset;\n\tgboolean falsecolour;\t\t/* False colour display on */\n\tgboolean type;\t\t\t/* Interpret type field */\n};\n\ntypedef struct _ImagemodelClass {\n\tiObjectClass parent_class;\n\n\t/* Imagemodel has a new imageinfo.\n\t */\n\tvoid (*imageinfo_changed)( Imagemodel * );\n} ImagemodelClass;\n\nvoid *imagemodel_imageinfo_changed( Imagemodel *imagemodel );\ngboolean imagemodel_state_paint( ImagemodelState state );\n\nGType imagemodel_get_type( void );\nImagemodel *imagemodel_new( iImage *iimage );\n\ngboolean imagemodel_set_state( Imagemodel *imagemodel, ImagemodelState state, \n\tGtkWidget *parent );\n\nvoid imagemodel_set_rulers( Imagemodel *imagemodel, gboolean show_rulers );\nvoid imagemodel_set_paintbox( Imagemodel *imagemodel, gboolean show_paintbox );\nvoid imagemodel_set_status( Imagemodel *imagemodel, gboolean show_status );\nvoid imagemodel_set_convert( Imagemodel *imagemodel, gboolean show_convert );\n\ngboolean imagemodel_refresh_text( Imagemodel *imagemodel );\ngboolean imagemodel_refresh_nib( Imagemodel *imagemodel );\n\nvoid imagemodel_paint_recalc( Imagemodel *imagemodel );\n"
  },
  {
    "path": "src/imagepresent.c",
    "content": "/* Imagepresent widget code.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/*\n#define DEBUG\n */\n\n/* Define to trace button press events.\n#define EVENT\n */\n\n/* Snap if closer than this.\n */\nconst int imagepresent_snap_threshold = 10;\n\n/* Cursor shape in id for each state.\n */\niWindowShape imagepresent_cursors[IMAGEMODEL_LAST] = {\n\tIWINDOW_SHAPE_EDIT,\t\t/* IMAGEMODEL_SELECT */\n\tIWINDOW_SHAPE_MOVE, \t\t/* IMAGEMODEL_PAN */\n\tIWINDOW_SHAPE_MAGIN,\t\t/* IMAGEMODEL_MAGIN */\n\tIWINDOW_SHAPE_MAGOUT,\t\t/* IMAGEMODEL_MAGOUT */\n\tIWINDOW_SHAPE_DROPPER,\t\t/* IMAGEMODEL_DROPPER */\n\tIWINDOW_SHAPE_PEN,\t\t/* IMAGEMODEL_PEN */\n\tIWINDOW_SHAPE_PEN,\t\t/* IMAGEMODEL_LINE */\n\tIWINDOW_SHAPE_RECT,\t\t/* IMAGEMODEL_RECT */\n\tIWINDOW_SHAPE_FLOOD,\t\t/* IMAGEMODEL_FLOOD */\n\tIWINDOW_SHAPE_FLOOD,\t\t/* IMAGEMODEL_BLOB */\n\tIWINDOW_SHAPE_TEXT,\t\t/* IMAGEMODEL_TEXT */\n\tIWINDOW_SHAPE_SMUDGE\t\t/* IMAGEMODEL_SMUDGE */\n};\n\n/* Gdk keysyms, and the zooms we set for each.\n */\ntypedef struct _ImagepresentKeymap { \n\tguint keyval;\n\tint zoom;\n} ImagepresentKeymap; \n\nstatic ImagepresentKeymap imagepresent_keymap[] = {\n\t{ GDK_1, 1 },\n\t{ GDK_2, 2 },\n\t{ GDK_3, 3 },\n\t{ GDK_4, 4 },\n\t{ GDK_5, 5 },\n\t{ GDK_6, 6 },\n\t{ GDK_7, 7 },\n\t{ GDK_8, 8 },\n\t{ GDK_9, 9 }\n};\n\n/* Parent class.\n */\nstatic GtkBinClass *parent_class = NULL;\n\nstatic void\nimagepresent_destroy( GtkObject *object )\n{\n\tImagepresent *ip = IMAGEPRESENT( object );\n\n#ifdef DEBUG\n\tprintf( \"imagepresent_destroy\\n\" );\n#endif /*DEBUG*/\n\n\tIM_FREEF( g_source_remove, ip->scroll_tid );\n\tIM_FREEF( iwindow_cursor_context_destroy, ip->cntxt );\n\tDESTROY_GTK( ip->ruler_menu );\n\n\tif( ip->imagemodel ) {\n\t\tiImage *iimage = ip->imagemodel->iimage;\n\n\t\tif( iimage ) \n\t\t\tiimage->views = g_slist_remove( iimage->views, ip );\n\t\tUNREF( ip->imagemodel );\n\t}\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n\n\t/* Child views should all have removed themselves.\n\t */\n\tg_assert( ip->regionviews == NULL );\n}\n\nstatic void\nimagepresent_size_request( GtkWidget *widget, GtkRequisition *requisition )\n{\n\tGtkBin *bin = GTK_BIN( widget );\n\tgint focus_width;\n\tgint focus_pad;\n\n\tgtk_widget_style_get( widget, \n\t\t\"focus-line-width\", &focus_width,\n\t\t\"focus-padding\", &focus_pad,\n\t\tNULL );\n\n\trequisition->width = 2 * (focus_width + focus_pad);\n\trequisition->height = 2 * (focus_width + focus_pad);\n\n\tif( bin->child && GTK_WIDGET_VISIBLE( bin->child ) ) {\n\t\tGtkRequisition child_requisition;\n\n\t\tgtk_widget_size_request( bin->child, &child_requisition );\n\n\t\trequisition->width += child_requisition.width;\n\t\trequisition->height += child_requisition.height;\n\t}\n}\n\nstatic void\nimagepresent_size_allocate( GtkWidget *widget, GtkAllocation *allocation )\n{\n\tGtkBin *bin = GTK_BIN( widget );\n\n\twidget->allocation = *allocation;\n\n\tif( bin->child && GTK_WIDGET_VISIBLE( bin->child ) ) {\n\t\tgint focus_width;\n\t\tgint focus_pad;\n\t\tGtkAllocation child_allocation;\n\n\t\tgtk_widget_style_get( widget, \n\t\t\t\"focus-line-width\", &focus_width,\n\t\t\t\"focus-padding\", &focus_pad,\n\t\t\tNULL );\n\n\t\tchild_allocation.x = allocation->x + focus_width + focus_pad;\n\t\tchild_allocation.y = allocation->y + focus_width + focus_pad;\n\t\tchild_allocation.width = IM_MAX( 1, \n\t\t\tallocation->width - 2 * (focus_width + focus_pad) );\n\t\tchild_allocation.height = IM_MAX( 1,\n\t\t\tallocation->height - 2 * (focus_width + focus_pad) );\n\n\t\tgtk_widget_size_allocate( bin->child, &child_allocation );\n\t}\n}\n\nstatic gboolean\nimagepresent_expose_event( GtkWidget *widget, GdkEventExpose *event )\n{\n\tif( GTK_WIDGET_DRAWABLE( widget ) ) {\n\t\tif( GTK_WIDGET_HAS_FOCUS( widget ) ) {\n\t\t\tgint focus_pad;\n\t\t\tint x, y, width, height;\n\n\t\t\tgtk_widget_style_get( widget, \n\t\t\t\t\"focus-padding\", &focus_pad,\n\t\t\t\tNULL );\n\n\t\t\tx = widget->allocation.x + focus_pad;\n\t\t\ty = widget->allocation.y + focus_pad;\n\t\t\twidth = widget->allocation.width - 2 * focus_pad;\n\t\t\theight = widget->allocation.height - 2 * focus_pad;\n\n\t\t\tgtk_paint_focus( widget->style, widget->window, \n\t\t\t\tGTK_WIDGET_STATE( widget ),\n\t\t\t\t&event->area, widget, \"imagepresent\",\n\t\t\t\tx, y, width, height );\n\t\t}\n\n\t\tGTK_WIDGET_CLASS( parent_class )->expose_event( widget, event );\n\t}\n\n\treturn( FALSE );\n}\n\n/* Connect to our enclosing iwnd on realize.\n */\nstatic void\nimagepresent_realize( GtkWidget *widget )\n{\n\tImagepresent *ip = IMAGEPRESENT( widget );\n\tiWindow *iwnd = IWINDOW( gtk_widget_get_toplevel( widget ) );\t\n\n\tif( !ip->cntxt ) \n\t\tip->cntxt = iwindow_cursor_context_new( iwnd, \n\t\t\t0, \"imagepresent\" );\n\n\t/* Set initial state. _realize() is too late ... the _refresh() has\n\t * already happened.\n\t */\n\tiwindow_cursor_context_set_cursor( ip->cntxt, \n\t\timagepresent_cursors[ip->imagemodel->state] );\n\n\tGTK_WIDGET_CLASS( parent_class )->realize( widget );\n}\n\nstatic void\nimagepresent_class_init( ImagepresentClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tGtkWidgetClass *widget_class = (GtkWidgetClass *) class;\n\n\t/* Init parent class.\n\t */\n\tparent_class = g_type_class_peek_parent( class );\n\n        object_class->destroy = imagepresent_destroy;\n\n        widget_class->size_request = imagepresent_size_request;\n        widget_class->size_allocate = imagepresent_size_allocate;\n        widget_class->expose_event = imagepresent_expose_event;\n        widget_class->realize = imagepresent_realize;\n\n\t/* Init default methods.\n\t */\n\n\t/* Static class init.\n\t */\n}\n\n/* Rethink rulers.\n */\nstatic void\nimagepresent_hruler_rethink( Imagepresent *ip )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tIMAGE *im = imageinfo_get( FALSE, conv->ii );\n\n\t/* Try to get the ruler width: same as the whole of the scrolled\n\t * window.\n\t */\n\tint ruler_width = GTK_WIDGET( ip->swin )->allocation.width;\n\n\tdouble from = imagemodel->visible.left;\n\tdouble to = from + ruler_width;\n\tdouble pos = ip->last_x;\n\n\tdouble scale;\n\n\tif( imagemodel->rulers_offset && im ) {\n\t\tfrom -= im->Xoffset;\n\t\tto -= im->Xoffset;\n\t\tpos -= im->Xoffset;\n\t}\n\n\tscale = conversion_dmag( conv->mag );\n\tif( imagemodel->rulers_mm && im ) \n\t\tscale *= im->Xres;\n\n\tfrom /= scale;\n\tto /= scale;\n\tpos /= scale;\n\n\tgtk_ruler_set_range( GTK_RULER( ip->hrule ), from, to, pos, to - from );\n}\n\nstatic void\nimagepresent_vruler_rethink( Imagepresent *ip )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tIMAGE *im = imageinfo_get( FALSE, conv->ii );\n\n\t/* Try to get the ruler height: same as the whole of the scrolled\n\t * window.\n\t */\n\tint ruler_height = GTK_WIDGET( ip->swin )->allocation.height;\n\n\tdouble from = imagemodel->visible.top;\n\tdouble to = from + ruler_height;\n\tdouble pos = ip->last_y;\n\n\tdouble scale;\n\n\tif( imagemodel->rulers_offset && im ) {\n\t\tfrom -= im->Yoffset;\n\t\tto -= im->Yoffset;\n\t\tpos -= im->Yoffset;\n\t}\n\n\tscale = conversion_dmag( conv->mag );\n\tif( imagemodel->rulers_mm && im ) \n\t\tscale *= im->Yres;\n\n\tfrom /= scale;\n\tto /= scale;\n\tpos /= scale;\n\n\tgtk_ruler_set_range( GTK_RULER( ip->vrule ), from, to, pos, to - from );\n}\n\n/* Zoom with the mouse clicked at position x, y in canvas coordinates.\n */\nstatic void\nimagepresent_zoom_in( Imagepresent *ip, int x, int y )\n{\n\tConversion *conv = ip->imagemodel->conv;\n\tint ix, iy;\n\n\tconversion_disp_to_im( conv, x, y, &ix, &iy );\n\timagepresent_set_mag_pos( ip, \n\t\tconversion_double( conv->mag ), ix, iy );\n}\n\nstatic void\nimagepresent_zoom_in_centre( Imagepresent *ip )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\n\timagepresent_zoom_in( ip,\n\t\tIM_RECT_HCENTRE( &imagemodel->visible ),\n\t\tIM_RECT_VCENTRE( &imagemodel->visible ) );\n}\n\nstatic void\nimagepresent_zoom_out( Imagepresent *ip )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tint ix, iy;\n\n\t/* Current centre of window, image cods.\n\t */\n\tconversion_disp_to_im( conv, \n\t\tIM_RECT_HCENTRE( &imagemodel->visible ),\n\t\tIM_RECT_VCENTRE( &imagemodel->visible ),\n\t\t&ix, &iy );\n\timagepresent_set_mag_pos( ip, conversion_halve( conv->mag ), ix, iy );\n}\n\n/* Scroll events ... handle mousewheel shortcuts here. \n */\nstatic gboolean\nimagepresent_scroll_event_cb( GtkWidget *widget, \n\tGdkEventScroll *ev, Imagepresent *ip )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tRect *visible = &imagemodel->visible;\n\tgboolean handled;\n\n\t/* Gimp uses page_incr / 4 I think, but then scroll speed varies with\n\t * window size, which is pretty odd. Just use a constant.\n\t */\n\tconst int incr = 50;\n\n\thandled = FALSE;\n\n\tif( ev->direction == GDK_SCROLL_UP || \n\t\tev->direction == GDK_SCROLL_DOWN ) {\n\t\tif( ev->state & GDK_CONTROL_MASK ) {\n\t\t\tif( ev->direction == GDK_SCROLL_UP )\n\t\t\t\timagepresent_zoom_in_centre( ip ); \n\t\t\telse\n\t\t\t\timagepresent_zoom_out( ip );\n\n\t\t\thandled = TRUE;\n\t\t}\n\t\telse if( ev->state & GDK_SHIFT_MASK ) {\n\t\t\tif( ev->direction == GDK_SCROLL_UP )\n\t\t\t\timagepresent_set_position( ip, \n\t\t\t\t\tvisible->left + incr, visible->top );\n\t\t\telse\n\t\t\t\timagepresent_set_position( ip, \n\t\t\t\t\tvisible->left - incr, visible->top );\n\n\t\t\thandled = TRUE;\n\t\t}\n\t\telse {\n\t\t\tif( ev->direction == GDK_SCROLL_UP )\n\t\t\t\timagepresent_set_position( ip, \n\t\t\t\t\tvisible->left, visible->top - incr );\n\t\t\telse\n\t\t\t\timagepresent_set_position( ip, \n\t\t\t\t\tvisible->left, visible->top + incr );\n\n\t\t\thandled = TRUE;\n\t\t}\n\t}\n\n\treturn( handled );\n}\n\n/* Our adjustments have changed (scroll or resize).\n */\nstatic void\nimagepresent_hadj_changed_cb( GtkAdjustment *adj, Imagepresent *ip )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\n\timagemodel->visible.left = adj->value;\n\timagemodel->visible.width = adj->page_size;\n\n\t/* Update the visible hint on the conversion.\n\t */\n\tconv->visible = imagemodel->visible;\n\n#ifdef DEBUG\n\tprintf( \"imagepresent_hadj_changed_cb: left = %d, width = %d\\n\",\n\t\timagemodel->visible.left, imagemodel->visible.width );\n#endif /*DEBUG*/\n\n\timagepresent_hruler_rethink( ip );\n}\n\nstatic void\nimagepresent_vadj_changed_cb( GtkAdjustment *adj, Imagepresent *ip )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\n\timagemodel->visible.top = adj->value;\n\timagemodel->visible.height = adj->page_size;\n\n\t/* Update the visible hint on the conversion.\n\t */\n\tconv->visible = imagemodel->visible;\n\n#ifdef DEBUG\n\tprintf( \"imagepresent_vadj_changed_cb: top = %d, height = %d\\n\",\n\t\timagemodel->visible.top, imagemodel->visible.height );\n#endif /*DEBUG*/\n\n\timagepresent_vruler_rethink( ip );\n}\n\nstatic void\nimagepresent_floating_new( Imagepresent *ip, \n\tint left, int top, int width, int height,\n\tgboolean frozen, RegionviewType type, RegionviewResize resize,\n\tint x, int y )\n{\n\tg_assert( !ip->regionview );\n\n\tip->floating.left = left;\n\tip->floating.top = top;\n\tip->floating.width = width;\n\tip->floating.height = height;\n\tip->regionview = regionview_new( NULL, &ip->floating, ip );\n\tip->regionview->frozen = frozen;\n\tip->regionview->type = type;\n\tip->regionview->resize = resize;\n\n\tregionview_attach( ip->regionview, x, y );\n}\n\n/* Need to fwd ref this.\n */\nstatic void imagepresent_left_release( Imagepresent *ip, GdkEvent *ev, \n\tint x, int y );\n\nstatic gint\nimagepresent_hruler_event( GtkWidget *widget, GdkEvent *ev, Imagepresent *ip )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tIMAGE *im = imageinfo_get( FALSE, conv->ii );\n\tgboolean handled = FALSE;\n\n\tswitch( ev->type ) {\n\tcase GDK_BUTTON_PRESS:\n\t\tswitch( ev->button.button ) {\n\t\tcase 1:\n\t\t\t(void) imagemodel_set_state( imagemodel, \n\t\t\t\tIMAGEMODEL_SELECT, NULL );\n\t\t\timagepresent_floating_new( ip,\n\t\t\t\t0, 0, im->Xsize, 0,\n\t\t\t\tTRUE, REGIONVIEW_HGUIDE,\n\t\t\t\tREGIONVIEW_RESIZE_BOTTOM,\n\t\t\t\tev->button.x, ev->button.y );\n\n\t\t\t/* The pointer will be grabbed for the drag on the\n\t\t\t * ruler window. We want to track in the main image\n\t\t\t * display window, so we have to explicitly ungrab.\n\t\t\t */\n\t\t\tgdk_pointer_ungrab( ev->button.time );\n\n\t\t\thandled = TRUE;\n\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tcase GDK_BUTTON_RELEASE:\n\t\tswitch( ev->button.button ) {\n\t\tcase 1:\n\t\t\timagepresent_left_release( ip, ev, \n\t\t\t\tev->button.x, ev->button.y );\n\t\t\thandled = TRUE;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn( handled );\n}\n\nstatic gint\nimagepresent_vruler_event( GtkWidget *widget, GdkEvent *ev, Imagepresent *ip )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tIMAGE *im = imageinfo_get( FALSE, conv->ii );\n\tgboolean handled = FALSE;\n\n\tswitch( ev->type ) {\n\tcase GDK_BUTTON_PRESS:\n\t\tswitch( ev->button.button ) {\n\t\tcase 1:\n\t\t\t(void) imagemodel_set_state( imagemodel, \n\t\t\t\tIMAGEMODEL_SELECT, NULL );\n\t\t\timagepresent_floating_new( ip,\n\t\t\t\t0, 0, 0, im->Ysize,\n\t\t\t\tTRUE, REGIONVIEW_VGUIDE,\n\t\t\t\tREGIONVIEW_RESIZE_RIGHT,\n\t\t\t\tev->button.x, ev->button.y );\n\t\t\tgdk_pointer_ungrab( ev->button.time );\n\t\t\thandled = TRUE;\n\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tcase GDK_BUTTON_RELEASE:\n\t\tswitch( ev->button.button ) {\n\t\tcase 1:\n\t\t\timagepresent_left_release( ip, ev, \n\t\t\t\tev->button.x, ev->button.y );\n\t\t\thandled = TRUE;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn( handled );\n}\n\n/* Track this during a snap.\n */\ntypedef struct {\n\tImagepresent *ip;\n\n\tint x;\t\t\t/* Start point */\n\tint y;\n\tint off_x;\t\t/* Current snap offset */\n\tint off_y;\n\tint best_x;\t\t/* 'Closeness' of best snap so far */\n\tint best_y;\n} ImagepresentSnap;\n\nstatic void *\nimagepresent_snap_sub( Regionview *regionview, \n\tImagepresentSnap *snap, gboolean *snapped )\n{\n\tImagemodel *imagemodel = snap->ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tRect area;\n\n\t/* Only static h/v guides.\n\t */\n\tif( regionview->type != REGIONVIEW_HGUIDE && \n\t\tregionview->type != REGIONVIEW_VGUIDE )\n\t\treturn( NULL );\n\tif( regionview->state != REGIONVIEW_WAIT )\n\t\treturn( NULL );\n\n\t/* Work in display cods.\n\t */\n\tconversion_im_to_disp_rect( conv, &regionview->area, &area );\n\n\tif( regionview->type == REGIONVIEW_HGUIDE ) {\n\t\tint score = abs( area.top - snap->y );\n\n\t\tif( score < snap->best_y ) {\n\t\t\tsnap->off_y = area.top - snap->y;\n\t\t\tsnap->best_y = score;\n\t\t\t*snapped = TRUE;\n\t\t}\n\t}\n\telse {\n\t\tint score = abs( area.left - snap->x );\n\n\t\tif( score < snap->best_x ) {\n\t\t\tsnap->off_x = area.left - snap->x;\n\t\t\tsnap->best_x = score;\n\t\t\t*snapped = TRUE;\n\t\t}\n\t}\n\n\treturn( NULL );\n}\n\nstatic gboolean\nimagepresent_snap( Imagepresent *ip, ImagepresentSnap *snap )\n{\n\tgboolean snapped;\n\n\tsnap->ip = ip;\n\tsnap->off_x = 0;\n\tsnap->off_y = 0;\n\tsnap->best_x = imagepresent_snap_threshold;\n\tsnap->best_y = imagepresent_snap_threshold;\n\n\tsnapped = FALSE;\n\tslist_map2( ip->regionviews,\n\t\t(SListMap2Fn) imagepresent_snap_sub, snap, &snapped );\n\n\treturn( snapped );\n}\n\ngboolean\nimagepresent_snap_point( Imagepresent *ip, int x, int y, int *sx, int *sy )\n{\n\tImagepresentSnap snap;\n\tgboolean snapped;\n\n\tsnap.x = x;\n\tsnap.y = y;\n\n\tsnapped = imagepresent_snap( ip, &snap );\n\n\t*sx = x + snap.off_x;\n\t*sy = y + snap.off_y;\n\n\treturn( snapped );\n}\n\ngboolean\nimagepresent_snap_rect( Imagepresent *ip, Rect *in, Rect *out )\n{\n\tImagepresentSnap snap[8];\n\tint i, best, best_score;\n\tgboolean snapped;\n\n\t/* Snap the corners plus the edge centres, take the best score.\n\t */\n\tsnap[0].x = in->left;\n\tsnap[0].y = in->top;\n\tsnap[1].x = in->left + in->width;\n\tsnap[1].y = in->top;\n\tsnap[2].x = in->left + in->width;\n\tsnap[2].y = in->top + in->height;\n\tsnap[3].x = in->left;\n\tsnap[3].y = in->top + in->height;\n\tsnap[4].x = in->left + in->width / 2;\n\tsnap[4].y = in->top;\n\tsnap[5].x = in->left + in->width;\n\tsnap[5].y = in->top + in->height / 2;\n\tsnap[6].x = in->left + in->width / 2;\n\tsnap[6].y = in->top + in->height;\n\tsnap[7].x = in->left;\n\tsnap[7].y = in->top + in->height / 2;\n\n\tfor( snapped = FALSE, i = 0; i < 8; i++ )\n\t\tsnapped |= imagepresent_snap( ip, &snap[i] );\n\n\tbest = 0;\n\tbest_score = snap[0].best_x;\n\tfor( i = 1; i < 7; i++ )\n\t\tif( snap[i].best_x < best_score ) {\n\t\t\tbest = i;\n\t\t\tbest_score = snap[i].best_x;\n\t\t}\n\tout->left = in->left + snap[best].off_x;\n\n\tbest = 0;\n\tbest_score = snap[0].best_y;\n\tfor( i = 1; i < 7; i++ )\n\t\tif( snap[i].best_y < best_score ) {\n\t\t\tbest = i;\n\t\t\tbest_score = snap[i].best_y;\n\t\t}\n\tout->top = in->top + snap[best].off_y;\n\n\tout->width = in->width;\n\tout->height = in->height;\n\n\treturn( snapped );\n}\n\n/* Set position x, y in canvas coordinates as the top left of the window.\n */\nvoid\nimagepresent_set_position( Imagepresent *ip, int x, int y )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tint maxx = conv->canvas.width - imagemodel->visible.width;\n\tint maxy = conv->canvas.height - imagemodel->visible.height;\n\n#ifdef DEBUG\n\tprintf( \"imagepresent_set_position: %d x %d\\n\", x, y );\n#endif /*DEBUG*/\n\n\tadjustments_set_value( ip->hadj, ip->vadj, \n\t\tIM_CLIP( 0, x, maxx ), IM_CLIP( 0, y, maxy ) );\n}\n\n/* Set a new magnification, and scroll for the passed x/y position in image\n * coordinates to be in the centre of the screen.\n */\nvoid\nimagepresent_set_mag_pos( Imagepresent *ip, int mag, int ix, int iy )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tint nx, ny;\n\tint last_x, last_y;\n\n#ifdef DEBUG\n\tprintf( \"imagepresent_set_mag_pos: %d, %d x %d\\n\", mag, ix, iy );\n#endif /*DEBUG*/\n\n\t/* Need to update last_x/y as well ... go to image cods around zoom\n\t * operation.\n\t */\n\tconversion_disp_to_im( conv, ip->last_x, ip->last_y, &last_x, &last_y );\n\n\t/* Take mouse pos to image cods around zoom operation.\n\t */\n\tconversion_set_mag( conv, mag );\n\tconversion_im_to_disp( conv, ix, iy, &nx, &ny );\n\n\t/* ... and try to get that point in the centre of the window. We need\n\t * to zap in the new adjustment upper value, since this won't\n\t * otherwise get set until we get back to idle.\n\t */\n\tip->hadj->upper = conv->canvas.width;\n\tip->vadj->upper = conv->canvas.height;\n\timagepresent_set_position( ip, \n\t\tnx - imagemodel->visible.width / 2, \n\t\tny - imagemodel->visible.height / 2 );\n\tconversion_im_to_disp( conv, \n\t\tlast_x, last_y, &ip->last_x, &ip->last_y );\n}\n\n/* Set a magnification, keeping the centre of the screen in the centre.\n */\nvoid\nimagepresent_zoom_to( Imagepresent *ip, int mag )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\n\t/* If window is larger than image.\n\t */\n\tint w = IM_MIN( imagemodel->visible.width, conv->canvas.width );\n\tint h = IM_MIN( imagemodel->visible.height, conv->canvas.height );\n\n\tint ix, iy;\n\n\tconversion_disp_to_im( conv, \n\t\timagemodel->visible.left + w / 2, \n\t\timagemodel->visible.top + h / 2, &ix, &iy );\n\timagepresent_set_mag_pos( ip, mag, ix, iy );\n}\n\n/* Left button press event.\n */\nstatic gboolean\nimagepresent_left_press( Imagepresent *ip, GdkEvent *ev, int x, int y )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tgboolean handled = FALSE;\n\tIMAGE *im2;\n\tint ix, iy;\n\n\t/* If there's a regionview grabbed already, block other actions. This\n\t * can happen with, for example, the win32 backend where we don't\n\t * always see a RELEASE for every PRESS.\n\t */\n\tif( ip->regionview )\n\t\treturn( FALSE );\n\n\tswitch( imagemodel->state ) {\n\tcase IMAGEMODEL_SELECT:\n\t\tif( ev->button.state & GDK_CONTROL_MASK ) {\n\t\t\timagepresent_snap_point( ip, x, y, &x, &y );\n\t\t\tconversion_disp_to_im( conv, x, y, &ix, &iy );\n\t\t\timagepresent_floating_new( ip,\n\t\t\t\tix, iy, 0, 0,\n\t\t\t\tFALSE, REGIONVIEW_MARK, \n\t\t\t\t\tREGIONVIEW_RESIZE_BOTTOMRIGHT,\n\t\t\t\tx, y );\n\n\t\t\thandled = TRUE;\n\t\t}\n\n\t\tbreak;\n\n\tcase IMAGEMODEL_PAN:\n\t\t/* Save how much we have to add to x_root to get x.  \n\t\t */\n\t\tip->dx = ev->button.x_root + imagemodel->visible.left;\n\t\tip->dy = ev->button.y_root + imagemodel->visible.top;\n\t\tbreak;\n\n\tcase IMAGEMODEL_MAGIN:\n\t\timagepresent_zoom_in( ip, x, y );\n\t\thandled = TRUE;\n\t\tbreak;\n\n\tcase IMAGEMODEL_MAGOUT:\n\t\timagepresent_zoom_out( ip );\n\t\thandled = TRUE;\n\t\tbreak;\n\n\tcase IMAGEMODEL_DROPPER:\n\tcase IMAGEMODEL_FLOOD:\n\tcase IMAGEMODEL_BLOB:\n\t\tbreak;\n\n\tcase IMAGEMODEL_PEN:\n\tcase IMAGEMODEL_SMUDGE:\n\t\timagepresent_snap_point( ip, x, y, &x, &y );\n\t\tconversion_disp_to_im( conv, x, y, &ix, &iy );\n\t\tip->paint_last_x = ix;\n\t\tip->paint_last_y = iy;\n\t\thandled = TRUE;\n\n\t\t/* This can take ages and, via progress, actually process a\n\t\t * few events. Do it at the end.\n\t\t */\n\t\timagemodel_refresh_nib( imagemodel );\n\n\t\tbreak;\n\n\tcase IMAGEMODEL_LINE:\n\t\timagepresent_snap_point( ip, x, y, &x, &y );\n\t\tconversion_disp_to_im( conv, x, y, &ix, &iy );\n\t\tip->paint_last_x = ix;\n\t\tip->paint_last_y = iy;\n\t\timagepresent_floating_new( ip,\n\t\t\tix, iy, 0, 0,\n\t\t\tTRUE, REGIONVIEW_LINE, REGIONVIEW_RESIZE_BOTTOMRIGHT,\n\t\t\tx, y );\n\t\thandled = TRUE;\n\n\t\t/* This can take ages and, via progress, actually process a\n\t\t * few events. Do it at the end.\n\t\t */\n\t\timagemodel_refresh_nib( imagemodel );\n\n\t\tbreak;\n\n\tcase IMAGEMODEL_RECT:\n\t\timagepresent_snap_point( ip, x, y, &x, &y );\n\t\tconversion_disp_to_im( conv, x, y, &ix, &iy );\n\t\timagepresent_floating_new( ip,\n\t\t\tix, iy, 0, 0,\n\t\t\tTRUE, REGIONVIEW_BOX, REGIONVIEW_RESIZE_BOTTOMRIGHT,\n\t\t\tx, y );\n\t\thandled = TRUE;\n\t\tbreak;\n\n\tcase IMAGEMODEL_TEXT:\n\t\timagepresent_snap_point( ip, x, y, &x, &y );\n\t\tconversion_disp_to_im( conv, x, y, &ix, &iy );\n\t\tip->paint_last_x = ix;\n\t\tip->paint_last_y = iy;\n\n\t\tif( !imagemodel_refresh_text( imagemodel ) ) {\n\t\t\tiwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR );\n\t\t\tbreak;\n\t\t}\n\n\t\tim2 = imageinfo_get( FALSE, imagemodel->text_mask );\n\t\timagepresent_floating_new( ip,\n\t\t\tix,\n\t\t\tiy + imagemodel->text_area.top,\n\t\t\tim2->Xsize, im2->Ysize,\n\t\t\tTRUE, REGIONVIEW_BOX, REGIONVIEW_RESIZE_EDIT,\n\t\t\tx, y );\n\n\t\thandled = TRUE;\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn( handled );\n}\n\nstatic void\nimagepresent_paint_stop( Imagepresent *ip, int x, int y )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tImageinfo *imageinfo = conv->ii;\n        Rect oper;\n        int ix, iy;\n\n        imagepresent_snap_point( ip, x, y, &x, &y );\n        conversion_disp_to_im( conv, x, y, &ix, &iy );\n\n\tswitch( imagemodel->state ) {\n\tcase IMAGEMODEL_DROPPER:\n\t\tif( im_rect_includespoint( &conv->underlay, ix, iy ) ) \n\t\t\tif( !imageinfo_paint_dropper( imageinfo, \n\t\t\t\timagemodel->ink, ix, iy ) )\n\t\t\t\tiwindow_alert( GTK_WIDGET( ip ), \n\t\t\t\t\tGTK_MESSAGE_ERROR );\n\n\t\tbreak;\n\n\tcase IMAGEMODEL_PEN:\n\t\tif( !imageinfo_paint_line( imageinfo, \n\t\t\timagemodel->ink, \n\t\t\timagemodel->nib, \n\t\t\tip->paint_last_x, ip->paint_last_y, ix, iy ) )\n\t\t\tiwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR );\n\n\t\tbreak;\n\n\tcase IMAGEMODEL_LINE:\n\t\tif( ip->regionview ) { \n\t\t\tDESTROY_GTK( ip->regionview );\n\n\t\t\tif( !imageinfo_paint_line( imageinfo, \n\t\t\t\timagemodel->ink, \n\t\t\t\timagemodel->nib, \n\t\t\t\tip->floating.left, ip->floating.top,\n\t\t\t\tIM_RECT_RIGHT( &ip->floating ),\n\t\t\t\tIM_RECT_BOTTOM( &ip->floating ) ) )\n\t\t\t\tiwindow_alert( GTK_WIDGET( ip ), \n\t\t\t\t\tGTK_MESSAGE_ERROR );\n\t\t}\n\n\t\tbreak;\n\n\tcase IMAGEMODEL_RECT:\n\t\tif( ip->regionview ) { \n\t\t\tDESTROY_GTK( ip->regionview );\n\n\t\t\tim_rect_normalise( &ip->floating );\n\n\t\t\tif( !imageinfo_paint_rect( imageinfo, \n\t\t\t\timagemodel->ink, &ip->floating ) )\n\t\t\t\tiwindow_alert( GTK_WIDGET( ip ), \n\t\t\t\t\tGTK_MESSAGE_ERROR );\n\t\t}\n\n\t\tbreak;\n\n\tcase IMAGEMODEL_FLOOD:\n\t\tif( !imageinfo_paint_flood( imageinfo, \n\t\t\timagemodel->ink, ix, iy, FALSE ) )\n\t\t\tiwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR );\n\n\t\tbreak;\n\n\tcase IMAGEMODEL_BLOB:\n\t\tif( !imageinfo_paint_flood( imageinfo, \n\t\t\timagemodel->ink, ix, iy, TRUE ) )\n\t\t\tiwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR );\n\n\t\tbreak;\n\n\tcase IMAGEMODEL_TEXT:\n\t\tif( ip->regionview ) { \n\t\t\tDESTROY_GTK( ip->regionview );\n\n\t\t\tif( !imageinfo_paint_mask( imageinfo, \n\t\t\t\timagemodel->ink, imagemodel->text_mask, \n\t\t\t\tip->floating.left, ip->floating.top ) )\n\t\t\t\tiwindow_alert( GTK_WIDGET( ip ), \n\t\t\t\t\tGTK_MESSAGE_ERROR );\n\t\t}\n\n\t\tbreak;\n\n\tcase IMAGEMODEL_SMUDGE:\n\t\t/* Area to smudge in display cods.\n\t\t */\n\t\toper.left = -10;\n\t\toper.top = -10;\n\t\toper.width = 20;\n\t\toper.height = 20;\n\n\t\t/* Translate to IMAGE cods.\n\t\t */\n\t\tconversion_disp_to_im_rect( conv, &oper, &oper );\n\n\t\tif( !imageinfo_paint_smudge( imageinfo,\n\t\t\t&oper, ip->paint_last_x, ip->paint_last_y, ix, iy ) )\n\t\t\tiwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR );\n\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\timagemodel_paint_recalc( imagemodel );\n\timageinfo_undo_mark( imageinfo );\n\n\t/* Ask everyone to drop cache, the image has changed.\n\t */\n\tim_invalidate( imageinfo_get( FALSE, imageinfo ) );\n}\n\n/* Left button release event.\n */\nstatic void\nimagepresent_left_release( Imagepresent *ip, GdkEvent *ev, int x, int y )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tRow *row = imagemodel->iimage ? \n\t\tHEAPMODEL( imagemodel->iimage )->row : NULL;\n\n\tswitch( imagemodel->state ) {\n\tcase IMAGEMODEL_SELECT:\n\t\tif( ip->regionview && row ) {\n\t\t\t/* Make a new region.\n\t\t\t */\n\t\t\tchar txt[MAX_STRSIZE];\n\t\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\t\t\tSymbol *sym;\n\n\t\t\tswitch( ip->regionview->type ) {\n\t\t\tcase REGIONVIEW_MARK:\n\t\t\t\tvips_buf_appendf( &buf, \"%s \", CLASS_MARK );\n\t\t\t\trow_qualified_name( row, &buf );\n\t\t\t\tvips_buf_appendd( &buf, ip->floating.left );\n\t\t\t\tvips_buf_appendd( &buf, ip->floating.top );\n\t\t\t\tbreak;\n\n\t\t\tcase REGIONVIEW_REGION:\n\t\t\t\tvips_buf_appendf( &buf, \"%s \", CLASS_REGION );\n\t\t\t\trow_qualified_name( row, &buf );\n\t\t\t\tvips_buf_appendd( &buf, ip->floating.left );\n\t\t\t\tvips_buf_appendd( &buf, ip->floating.top );\n\t\t\t\tvips_buf_appendd( &buf, ip->floating.width );\n\t\t\t\tvips_buf_appendd( &buf, ip->floating.height );\n\t\t\t\tbreak;\n\n\t\t\tcase REGIONVIEW_ARROW:\n\t\t\t\tvips_buf_appendf( &buf, \"%s \", CLASS_ARROW );\n\t\t\t\trow_qualified_name( row, &buf );\n\t\t\t\tvips_buf_appendd( &buf, ip->floating.left );\n\t\t\t\tvips_buf_appendd( &buf, ip->floating.top );\n\t\t\t\tvips_buf_appendd( &buf, ip->floating.width );\n\t\t\t\tvips_buf_appendd( &buf, ip->floating.height );\n\t\t\t\tbreak;\n\n\t\t\tcase REGIONVIEW_HGUIDE:\n\t\t\t\tvips_buf_appendf( &buf, \"%s \", CLASS_HGUIDE );\n\t\t\t\trow_qualified_name( row, &buf );\n\t\t\t\tvips_buf_appendd( &buf, ip->floating.top );\n\t\t\t\tbreak;\n\n\t\t\tcase REGIONVIEW_VGUIDE:\n\t\t\t\tvips_buf_appendf( &buf, \"%s \", CLASS_VGUIDE );\n\t\t\t\trow_qualified_name( row, &buf );\n\t\t\t\tvips_buf_appendd( &buf, ip->floating.left );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tg_assert( FALSE );\n\t\t\t}\n\n\t\t\tDESTROY_GTK( ip->regionview );\n\n\t\t\tif( !(sym = workspace_add_def_recalc( row->ws, \n\t\t\t\tvips_buf_all( &buf ) )) ) \n\t\t\t\tiwindow_alert( GTK_WIDGET( ip ), \n\t\t\t\t\tGTK_MESSAGE_ERROR );\n\n\t\t\tworkspace_deselect_all( row->ws );\n\t\t}\n\t\tbreak;\n\n\tcase IMAGEMODEL_DROPPER:\n\tcase IMAGEMODEL_PEN:\n\tcase IMAGEMODEL_LINE:\n\tcase IMAGEMODEL_RECT:\n\tcase IMAGEMODEL_FLOOD:\n\tcase IMAGEMODEL_BLOB:\n\tcase IMAGEMODEL_TEXT:\n\tcase IMAGEMODEL_SMUDGE:\n\t\timagepresent_paint_stop( ip, x, y );\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n/* Button motion event.\n */\nstatic void\nimagepresent_button_motion( Imagepresent *ip, GdkEvent *ev )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tImageinfo *imageinfo = conv->ii;\n\tRect oper;\n\tint x, y;\n\tint ix, iy;\n\n\timagepresent_snap_point( ip, ev->motion.x, ev->motion.y, &x, &y );\n\tconversion_disp_to_im( conv, x, y, &ix, &iy );\n\n\tswitch( imagemodel->state ) {\n\tcase IMAGEMODEL_SELECT:\n\t\tbreak;\n\n\tcase IMAGEMODEL_PAN:\n\t\timagepresent_set_position( ip, \n\t\t\t(int) ip->dx - ev->motion.x_root, \n\t\t\t(int) ip->dy - ev->motion.y_root );\n\t\tbreak;\n\n\tcase IMAGEMODEL_MAGIN:\n\t\tbreak;\n\n\tcase IMAGEMODEL_MAGOUT:\n\t\tbreak;\n\n\tcase IMAGEMODEL_DROPPER:\n\t\tif( im_rect_includespoint( &conv->underlay, ix, iy ) ) \n\t\t\tif( !imageinfo_paint_dropper( imageinfo, \n\t\t\t\timagemodel->ink, ix, iy ) )\n\t\t\t\tiwindow_alert( GTK_WIDGET( ip ), \n\t\t\t\t\tGTK_MESSAGE_ERROR );\n\t\tbreak;\n\n\tcase IMAGEMODEL_PEN:\n\t\tif( !imageinfo_paint_line( imageinfo, \n\t\t\timagemodel->ink, \n\t\t\timagemodel->nib, \n\t\t\tip->paint_last_x, ip->paint_last_y, ix, iy ) )\n\t\t\tiwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR );\n\t\tim_invalidate( imageinfo_get( FALSE, imageinfo ) );\n\n\t\tip->paint_last_x = ix;\n\t\tip->paint_last_y = iy;\n\t\tbreak;\n\n\tcase IMAGEMODEL_LINE:\n\t\t/* rubberband\n\t\t */\n\t\tbreak;\n\n\tcase IMAGEMODEL_SMUDGE:\n\t\t/* Area to smudge in display cods.\n\t\t */\n\t\toper.left = -10;\n\t\toper.top = -10;\n\t\toper.width = 20;\n\t\toper.height = 20;\n\n\t\t/* Translate to IMAGE cods.\n\t\t */\n\t\tconversion_disp_to_im_rect( conv, &oper, &oper );\n\n\t\tif( !imageinfo_paint_smudge( imageinfo, &oper, \n\t\t\tip->paint_last_x, ip->paint_last_y, \n\t\t\tix, iy ) )\n\t\t\tiwindow_alert( GTK_WIDGET( ip ), GTK_MESSAGE_ERROR );\n\t\tim_invalidate( imageinfo_get( FALSE, imageinfo ) );\n\n\t\tip->paint_last_x = ix;\n\t\tip->paint_last_y = iy;\n\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n}\n\n/* Main event loop.\n */\nstatic gboolean\nimagepresent_event_cb( GtkWidget *widget, GdkEvent *ev, Imagepresent *ip )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tgboolean handled;\n\n#ifdef EVENT\n\tprintf( \"imagepresent_event_cb %d\\n\", ev->type );\n#endif /*EVENT*/\n\n\thandled = FALSE;\n\n\tswitch( ev->type ) {\n\tcase GDK_BUTTON_PRESS:\n\t\tif( !GTK_WIDGET_HAS_FOCUS( GTK_WIDGET( ip ) ) )\n\t\t\tgtk_widget_grab_focus( GTK_WIDGET( ip ) );\n\n\t\tswitch( ev->button.button ) {\n\t\tcase 1:\n\t\t\thandled = imagepresent_left_press( ip, ev,  \n\t\t\t\tev->button.x, ev->button.y );\n\n\t\t\tbreak;\n\n\t\tcase 2:\n#ifdef EVENT\n\t\t\tprintf( \"button2 press: at %gx%g\\n\",\n\t\t\t\tev->button.x, ev->button.y );\n#endif /*EVENT*/\n\n\t\t\t/* Switch to pan, for this drag.\n\t\t\t */\n\t\t\timagemodel->save_state = imagemodel->state;\n\t\t\t(void) imagemodel_set_state( imagemodel, \n\t\t\t\tIMAGEMODEL_PAN, NULL );\n\t\t\thandled = imagepresent_left_press( ip, ev,  \n\t\t\t\tev->button.x, ev->button.y );\n\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t\tbreak;\n\n\tcase GDK_BUTTON_RELEASE:\n\t\tswitch( ev->button.button ) {\n\t\tcase 1:\n\t\t\timagepresent_left_release( ip, ev,\n\t\t\t\tev->button.x, ev->button.y );\n\n\t\t\tbreak;\n\n\t\tcase 2:\n#ifdef EVENT\n\t\t\tprintf( \"button2 release: at %gx%g\\n\",\n\t\t\t\tev->button.x, ev->button.y );\n#endif /*EVENT*/\n\n\t\t\t/* Should always succeed.\n\t\t\t */\n\t\t\t(void) imagemodel_set_state( imagemodel, \n\t\t\t\timagemodel->save_state, NULL );\n\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t\tbreak;\n\n\tcase GDK_MOTION_NOTIFY:\n\t\t/* We're using motion hints, so we need to read the pointer to\n\t\t * get the next one.\n\t\t */\n\t\twidget_update_pointer( GTK_WIDGET( ip ), ev );\n\n\t\tip->last_x = ev->motion.x;\n\t\tip->last_y = ev->motion.y;\n\n\t\tif( ev->motion.state & GDK_BUTTON1_MASK ||\n\t\t\tev->motion.state & GDK_BUTTON2_MASK ) \n\t\t\timagepresent_button_motion( ip, ev );\n\n\t\t/* Update tick marks on rulers, if they're being drawn.\n\t\t */\n\t\tif( GTK_WIDGET_VISIBLE( ip->hrule ) ) {\n\t\t\timagepresent_hruler_rethink( ip );\n\t\t\timagepresent_vruler_rethink( ip );\n\t\t}\n\n\t\tbreak;\n\n\tcase GDK_ENTER_NOTIFY:\n\t\tip->inside = TRUE;\n\n\t\tbreak;\n\n\tcase GDK_LEAVE_NOTIFY:\n\t\tip->inside = FALSE;\n\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn( handled );\n}\n\nstatic gboolean\nimagepresent_key_press_event_cb( GtkWidget *widget, GdkEventKey *event, \n\tImagepresent *ip )\n{\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tRect *visible = &imagemodel->visible;\n\tGtkAdjustment *hadj = ip->hadj;\n\tGtkAdjustment *vadj = ip->vadj;\n\tgboolean handled;\n\tint i;\n\n#ifdef DEBUG\n\tprintf( \"imagepresent_key_press_event_cb\\n\" );\n#endif /*DEBUG*/\n\n\thandled = FALSE;\n\n\tswitch( event->keyval ) {\n\tcase GDK_Left:\n\t\tif( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) )\n\t\t\timagepresent_set_position( ip, \n\t\t\t\tvisible->left - hadj->step_increment, \n\t\t\t\tvisible->top );\n\t\telse if( event->state & GDK_SHIFT_MASK )\n\t\t\timagepresent_set_position( ip, \n\t\t\t\tvisible->left - hadj->page_increment, \n\t\t\t\tvisible->top );\n\t\telse if( event->state & GDK_CONTROL_MASK )\n\t\t\timagepresent_set_position( ip, \n\t\t\t\t0, visible->top );\n\t\thandled = TRUE;\n\t\tbreak;\n\n\tcase GDK_Right:\n\t\tif( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) )\n\t\t\timagepresent_set_position( ip, \n\t\t\t\tvisible->left + hadj->step_increment, \n\t\t\t\tvisible->top );\n\t\telse if( event->state & GDK_SHIFT_MASK )\n\t\t\timagepresent_set_position( ip, \n\t\t\t\tvisible->left + hadj->page_increment, \n\t\t\t\tvisible->top );\n\t\telse if( event->state & GDK_CONTROL_MASK )\n\t\t\timagepresent_set_position( ip, \n\t\t\t\tconv->canvas.width, visible->top );\n\t\thandled = TRUE;\n\t\tbreak;\n\n\tcase GDK_Up:\n\t\tif( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) )\n\t\t\timagepresent_set_position( ip, \n\t\t\t\tvisible->left,\n\t\t\t\tvisible->top - vadj->step_increment );\n\t\telse if( event->state & GDK_SHIFT_MASK )\n\t\t\timagepresent_set_position( ip, \n\t\t\t\tvisible->left,\n\t\t\t\tvisible->top - vadj->page_increment );\n\t\telse if( event->state & GDK_CONTROL_MASK )\n\t\t\timagepresent_set_position( ip, \n\t\t\t\tvisible->left, 0 );\n\t\thandled = TRUE;\n\t\tbreak;\n\n\tcase GDK_Down:\n\t\tif( !(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) )\n\t\t\timagepresent_set_position( ip, \n\t\t\t\tvisible->left,\n\t\t\t\tvisible->top + vadj->step_increment );\n\t\telse if( event->state & GDK_SHIFT_MASK )\n\t\t\timagepresent_set_position( ip, \n\t\t\t\tvisible->left,\n\t\t\t\tvisible->top + vadj->page_increment );\n\t\telse if( event->state & GDK_CONTROL_MASK )\n\t\t\timagepresent_set_position( ip, \n\t\t\t\tvisible->left, conv->canvas.height );\n\t\thandled = TRUE;\n\t\tbreak;\n\n\t/* FIXME + and = are not always on the same key, of course :( \n\t */\n\tcase GDK_i:\n\tcase GDK_plus:\n\tcase GDK_equal:\n\t\tif( ip->inside ) \n\t\t\timagepresent_zoom_in( ip, ip->last_x, ip->last_y );\n\t\telse \n\t\t\timagepresent_zoom_in_centre( ip ); \n\t\thandled = TRUE;\n\t\tbreak;\n\n\tcase GDK_o: \n\tcase GDK_minus:\n\t\timagepresent_zoom_out( ip );\n\t\thandled = TRUE;\n\t\tbreak;\n\n\tcase GDK_0:\n\t\tconversion_set_mag( conv, 0 );\n\t\thandled = TRUE;\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\t/* Check the number zoom keys too.\n\t */\n\tif( !handled ) \n\t\tfor( i = 0; i < IM_NUMBER( imagepresent_keymap ); i++ )\n\t\t\tif( event->keyval == imagepresent_keymap[i].keyval ) {\n\t\t\t\tint mask = event->state & GDK_CONTROL_MASK;\n\t\t\t\tint zoom = imagepresent_keymap[i].zoom;\n\n\t\t\t\timagepresent_zoom_to( ip, mask ? -zoom : zoom );\n\t\t\t\thandled = TRUE;\n\t\t\t\tbreak;\n\t\t\t}\n\n\treturn( handled );\n}\n\n/* ... and set the work window once that's there.\n */\nstatic void\nimagepresent_realize_id_cb( Imagedisplay *id )\n{\n\tiWindow *iwnd = IWINDOW( gtk_widget_get_toplevel( GTK_WIDGET( id ) ) );\t\n\n\tiwindow_set_work_window( iwnd, GTK_WIDGET( id )->window );\n}\n\nstatic void\nimagepresent_rulers_mm_cb( GtkWidget *wid, GtkWidget *host, \n\tImagepresent *ip )\n{\n\tip->imagemodel->rulers_mm = gtk_check_menu_item_get_active( \n\t\tGTK_CHECK_MENU_ITEM( wid ) );\n\tiobject_changed( IOBJECT( ip->imagemodel ) );\n}\n\nstatic void\nimagepresent_rulers_offset_cb( GtkWidget *wid, GtkWidget *host, \n\tImagepresent *ip )\n{\n\tip->imagemodel->rulers_offset = gtk_check_menu_item_get_active( \n\t\tGTK_CHECK_MENU_ITEM( wid ) );\n\tiobject_changed( IOBJECT( ip->imagemodel ) );\n}\n\nstatic void\nimagepresent_ruler_hide_cb( GtkWidget *wid, GtkWidget *host, Imagepresent *ip )\n{\n\timagemodel_set_rulers( ip->imagemodel, FALSE );\n}\n\nstatic void\nimagepresent_init( Imagepresent *ip )\n{\n\tGtkWidget *bar;\n\tGtkWidget *table;\n\n\t/* Basic init.\n\t */\n\tip->imagemodel = NULL;\n\n\tip->dx = 0;\n\tip->dy = 0;\n\tip->last_x = 0;\n\tip->last_y = 0;\n\tip->inside = FALSE;\n\tip->scroll_tid = 0;\n\tip->u = 0;\n\tip->v = 0;\n\tip->regionview = NULL;\n\tip->paint_last_x = 0;\n\tip->paint_last_y = 0;\n\tip->regionviews = NULL;\n\tip->grabbed = NULL;\n\n\t/* Make main imagedisplay table.\n\t */\n\ttable = GTK_WIDGET( gtk_table_new( 2, 2, FALSE ) );\n        gtk_container_add( GTK_CONTAINER( ip ), table );\n\tgtk_widget_show( table );\n\n\t/* Make canvas.\n\t */\n\tip->id = imagedisplay_new( NULL );\n\tGTK_WIDGET_SET_FLAGS( ip, GTK_CAN_FOCUS );\n\tgtk_signal_connect( GTK_OBJECT( ip->id ), \"realize\",\n\t\tGTK_SIGNAL_FUNC( imagepresent_realize_id_cb ), NULL );\n\n\t/* Press/release/motion-notify stuff.\n\t */\n\tgtk_widget_add_events( GTK_WIDGET( ip->id ), \n\t\tGDK_KEY_PRESS_MASK | \n\t\tGDK_POINTER_MOTION_MASK | \n\t\tGDK_POINTER_MOTION_HINT_MASK |\n\t\tGDK_ENTER_NOTIFY_MASK | \n\t\tGDK_LEAVE_NOTIFY_MASK |\n\t\tGDK_BUTTON_PRESS_MASK | \n\t\tGDK_BUTTON_RELEASE_MASK ); \n\tgtk_signal_connect_after( GTK_OBJECT( ip->id ), \"event\",\n\t\tGTK_SIGNAL_FUNC( imagepresent_event_cb ), ip );\n\tgtk_signal_connect( GTK_OBJECT( ip ), \"key_press_event\",\n\t\tGTK_SIGNAL_FUNC( imagepresent_key_press_event_cb ), ip );\n\n\tip->swin = GTK_SCROLLED_WINDOW( gtk_scrolled_window_new( NULL, NULL ) );\n\tgtk_scrolled_window_add_with_viewport( ip->swin, GTK_WIDGET( ip->id ) );\n        gtk_scrolled_window_set_policy( ip->swin,\n\t\tGTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );\n\tip->hadj = gtk_scrolled_window_get_hadjustment( ip->swin );\n\tip->vadj = gtk_scrolled_window_get_vadjustment( ip->swin );\n\tgtk_signal_connect( GTK_OBJECT( ip->swin ), \"scroll_event\",\n\t\tGTK_SIGNAL_FUNC( imagepresent_scroll_event_cb ), ip );\n\n\tgtk_signal_connect( GTK_OBJECT( ip->hadj ), \"changed\",\n\t\tGTK_SIGNAL_FUNC( imagepresent_hadj_changed_cb ), ip );\n\tgtk_signal_connect( GTK_OBJECT( ip->hadj ), \"value_changed\",\n\t\tGTK_SIGNAL_FUNC( imagepresent_hadj_changed_cb ), ip );\n\tgtk_signal_connect( GTK_OBJECT( ip->vadj ), \"changed\",\n\t\tGTK_SIGNAL_FUNC( imagepresent_vadj_changed_cb ), ip );\n\tgtk_signal_connect( GTK_OBJECT( ip->vadj ), \"value_changed\",\n\t\tGTK_SIGNAL_FUNC( imagepresent_vadj_changed_cb ), ip );\n\n\tbar = ip->swin->hscrollbar;\n\tg_assert( GTK_IS_SCROLLBAR( bar ) );\n\tGTK_WIDGET_UNSET_FLAGS( bar, GTK_CAN_FOCUS );\n\tbar = ip->swin->vscrollbar;\n\tg_assert( GTK_IS_SCROLLBAR( bar ) );\n\tGTK_WIDGET_UNSET_FLAGS( bar, GTK_CAN_FOCUS );\n\n\t/* Need one menu per image window (could have a single menu for all\n\t * windows, but then we'd have to set the state of the toggle buttons\n\t * before mapping)\n\t */\n\tip->ruler_menu = popup_build( _( \"Ruler menu\" ) );\n\tpopup_add_tog( ip->ruler_menu, _( \"Rulers In _mm\" ), \n\t\tPOPUP_FUNC( imagepresent_rulers_mm_cb ) );\n\tpopup_add_tog( ip->ruler_menu, _( \"Show _Offset\" ), \n\t\tPOPUP_FUNC( imagepresent_rulers_offset_cb ) );\n\tmenu_add_sep( ip->ruler_menu );\n\tpopup_add_but( ip->ruler_menu, GTK_STOCK_CLOSE,\n\t\tPOPUP_FUNC( imagepresent_ruler_hide_cb ) );\n\n\t/* Make rulers.\n\t */\n\tip->hrule = GTK_HRULER( gtk_hruler_new() );\n\tgtk_ruler_set_metric( GTK_RULER( ip->hrule ), GTK_PIXELS );\n\tGTK_WIDGET_UNSET_FLAGS( GTK_WIDGET( ip->hrule ), GTK_CAN_FOCUS );\n\tgtk_widget_show( GTK_WIDGET( ip->hrule ) );\n\n\tip->vrule = GTK_VRULER( gtk_vruler_new() );\n\tgtk_ruler_set_metric( GTK_RULER( ip->vrule ), GTK_PIXELS );\n\tGTK_WIDGET_UNSET_FLAGS( GTK_WIDGET( ip->vrule ), GTK_CAN_FOCUS );\n\tgtk_widget_show( GTK_WIDGET( ip->vrule ) );\n\n\tip->heb = GTK_EVENT_BOX( gtk_event_box_new() );\n        gtk_container_add( GTK_CONTAINER( ip->heb ), GTK_WIDGET( ip->hrule ) );\n        gtk_signal_connect( GTK_OBJECT( ip->heb ), \"event\",\n\t\tGTK_SIGNAL_FUNC( imagepresent_hruler_event ), ip );\n        popup_attach( GTK_WIDGET( ip->heb ), ip->ruler_menu, ip );\n\n\tip->veb = GTK_EVENT_BOX( gtk_event_box_new() );\n        gtk_container_add( GTK_CONTAINER( ip->veb ), GTK_WIDGET( ip->vrule ) );\n        gtk_signal_connect( GTK_OBJECT( ip->veb ), \"event\",\n\t\tGTK_SIGNAL_FUNC( imagepresent_vruler_event ), ip );\n        popup_attach( GTK_WIDGET( ip->veb ), ip->ruler_menu, ip );\n\n\t/* Attach all widgets to table.\n\t */\n\tgtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( ip->heb ), \n\t\t1, 2, 0, 1,\n\t\tGTK_EXPAND | GTK_SHRINK | GTK_FILL,\n\t\tGTK_FILL, \n\t\t2, 2 );\n\tgtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( ip->veb ), \n\t\t0, 1, 1, 2,\n\t\tGTK_FILL, \n\t\tGTK_EXPAND | GTK_SHRINK | GTK_FILL,\n\t\t2, 2 );\n\tgtk_table_attach( GTK_TABLE( table ), GTK_WIDGET( ip->swin ), \n\t\t1, 2, 1, 2,\n\t\tGTK_FILL | GTK_EXPAND | GTK_SHRINK, \n\t\tGTK_FILL | GTK_EXPAND | GTK_SHRINK,\n\t\t2, 2 );\n\tgtk_widget_show( GTK_WIDGET( ip->id ) );\n\tgtk_widget_show( GTK_WIDGET( ip->swin ) );\n\n\t/* Set initial ruler visibility on first refresh from imagemodel.\n\t */\n}\n\nGType\nimagepresent_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ImagepresentClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) imagepresent_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Imagepresent ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) imagepresent_init,\n\t\t};\n\n\t\ttype = g_type_register_static( GTK_TYPE_BIN, \n\t\t\t\"Imagepresent\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\n/* The model has changed ... update!\n */\nstatic void\nimagepresent_imagemodel_changed_cb( Imagemodel *imagemodel, Imagepresent *ip )\n{\n\tif( ip->cntxt )\n\t\tiwindow_cursor_context_set_cursor( ip->cntxt, \n\t\t\timagepresent_cursors[imagemodel->state] );\n\n\twidget_visible( GTK_WIDGET( ip->heb ), imagemodel->show_rulers );\n\twidget_visible( GTK_WIDGET( ip->veb ), imagemodel->show_rulers );\n\timagepresent_hruler_rethink( ip );\n\timagepresent_vruler_rethink( ip );\n}\n\n/* The model has a new imageinfo.\n */\nstatic void\nimagepresent_imagemodel_imageinfo_changed_cb( Imagemodel *imagemodel, \n\tImagepresent *ip )\n{\n\t/* Reset our mode. We don't want to stay painting.\n\t */\n\tif( imagemodel_state_paint( imagemodel->state ) ) \n\t\timagemodel_set_state( imagemodel, IMAGEMODEL_SELECT, NULL );\n}\n\nstatic void\nimagepresent_link( Imagepresent *ip, Imagemodel *imagemodel )\n{\n\tip->imagemodel = imagemodel;\n\tg_object_ref( G_OBJECT( ip->imagemodel ) );\n\tiobject_sink( IOBJECT( ip->imagemodel ) );\n\n\tg_signal_connect( G_OBJECT( imagemodel ), \"changed\", \n\t\tG_CALLBACK( imagepresent_imagemodel_changed_cb ), ip );\n\tg_signal_connect( G_OBJECT( imagemodel ), \"imageinfo_changed\", \n\t\tG_CALLBACK( imagepresent_imagemodel_imageinfo_changed_cb ), \n\t\tip );\n\timagedisplay_set_conversion( ip->id, imagemodel->conv );\n\n\tif( imagemodel->iimage )\n\t\timagemodel->iimage->views = \n\t\t\tg_slist_prepend( imagemodel->iimage->views, ip );\n}\n\n/* Make a new Imagepresent. \n */\nImagepresent *\nimagepresent_new( Imagemodel *imagemodel )\n{\n\tImagepresent *ip = g_object_new( TYPE_IMAGEPRESENT, NULL );\n\n\timagepresent_link( ip, imagemodel );\n\n\treturn( ip );\n}\n\n/* Background scroller.\n */\nstatic gboolean\nimagepresent_scroll_cb( Imagepresent *ip )\n{\n\timagepresent_set_position( ip, \n\t\tip->imagemodel->visible.left + ip->u, \n\t\tip->imagemodel->visible.top + ip->v );\n\n\treturn( TRUE );\n}\n\nvoid\nimagepresent_scroll_start( Imagepresent *ip, int u, int v )\n{\n\tif( !ip->scroll_tid )\n\t\tip->scroll_tid = g_timeout_add( 100, \n\t\t\t(GSourceFunc) imagepresent_scroll_cb, ip );\n\n\tip->u = u;\n\tip->v = v;\n}\n\nvoid\nimagepresent_scroll_stop( Imagepresent *ip )\n{\n\tIM_FREEF( g_source_remove, ip->scroll_tid );\n\tip->u = 0;\n\tip->v = 0;\n}\n"
  },
  {
    "path": "src/imagepresent.h",
    "content": "/* Imagepresent widget stuff.\n */\n\n/*\n\n    Copyright (C) 1991-2001 The Natoinal Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_IMAGEPRESENT (imagepresent_get_type())\n#define IMAGEPRESENT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IMAGEPRESENT, Imagepresent ))\n#define IMAGEPRESENT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_IMAGEPRESENT, ImagepresentClass))\n#define IS_IMAGEPRESENT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IMAGEPRESENT ))\n#define IS_IMAGEPRESENT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEPRESENT ))\n#define IMAGEPRESENT_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), \\\n\t\tTYPE_IMAGEPRESENT, ImagepresentClass ))\n\n/* Track an image view canvas in one of these.\n */\nstruct _Imagepresent {\n\tGtkBin parent_object;\n\n\t/* Context.\n\t */\n\tImagemodel *imagemodel;\t\t/* Keep model parts of widgets here */\n\n\t/* Sub-widgets.\n\t */\n\tImagedisplay *id;\t\t/* Image we display */\n\tGtkScrolledWindow *swin;\n\tGtkAdjustment *hadj;\n\tGtkAdjustment *vadj;\n\tGtkHRuler *hrule;\t\t/* Rulers */\n\tGtkVRuler *vrule;\n\tGtkEventBox *heb;\t\t/* EventBoxes holding rulers */\n\tGtkEventBox *veb;\n\tiWindowCursorContext *cntxt;\n\tGtkWidget *ruler_menu;\n\n\t/* Panning stuff.\n\t */\n\tguint dx, dy;\t\t/* Drag start position */\n\n\t/* Last known mouse position, mouse in window.\n\t */\n\tint last_x, last_y;\n\tgboolean inside;\n\n\t/* Background scroll stuff.\n\t */\n\tguint scroll_tid;\n\tint u, v;\n\n\t/* Rubberbanding.\n\t */\n\tRegionview *regionview;\t/* region rubberband display */\n\tRect floating;\t\t/* rubberband area */\n\n\t/* Painting stuff.\n\t */\n\tint paint_last_x;\n\tint paint_last_y;\n\n\t/* Regionviews drawing on us. Used for snap-to-guide stuff.\n\t */\n\tGSList *regionviews;\n\n\t/* The regionview that's currently grabbed ... maintained for us by\n\t * regionview.c ... see regionview_attach()/_detach()\n\t */\n\tRegionview *grabbed;\n};\n\n/* Class structure.\n */\ntypedef struct _ImagepresentClass {\n\t/* Our parent.\n\t */\n\tGtkBinClass parent_class;\n} ImagepresentClass;\n\ngboolean imagepresent_snap_point( Imagepresent *ip, \n\tint x, int y, int *sx, int *sy );\ngboolean imagepresent_snap_rect( Imagepresent *ip, Rect *in, Rect *out );\n\nvoid imagepresent_paint_recalc( Imagepresent *ip );\n\nGType imagepresent_get_type( void );\nImagepresent *imagepresent_new( Imagemodel *imagemodel );\n\nvoid imagepresent_set_position( Imagepresent *ip, int x, int w );\nvoid imagepresent_set_mag_pos( Imagepresent *ip, int mag, int ix, int iy );\nvoid imagepresent_zoom_to( Imagepresent *ip, int mag );\n\nvoid imagepresent_scroll_start( Imagepresent *ip, int u, int v );\nvoid imagepresent_scroll_stop( Imagepresent *ip );\n"
  },
  {
    "path": "src/imageview.c",
    "content": "/* display an image in a window ... watching an iImage model.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n/* Define to trace button press events.\n#define EVENT\n */\n\n#include \"ip.h\"\n\nstatic FloatwindowClass *parent_class = NULL;\n\n/* All the magnification menus we have.\n */\ntypedef struct _ImageviewMagmenu {\n\tconst char *name;\n\tint mag;\n} ImageviewMagmenu;\n\nstatic const ImageviewMagmenu imageview_mags[] = {\n\t{ \"Zoom6Mode\", -16 },\n\t{ \"Zoom12Mode\", -8 },\n\t{ \"Zoom25Mode\", -4 },\n\t{ \"Zoom50Mode\", -2 },\n\t{ \"Zoom100Mode\", 1 },\n\t{ \"Zoom200Mode\", 2 },\n\t{ \"Zoom400Mode\", 4 },\n\t{ \"Zoom800Mode\", 8 },\n\t{ \"Zoom1600Mode\", 16 }\n};\n\nstatic void\nimageview_destroy( GtkObject *object )\n{\n\tImageview *iv;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_IMAGEVIEW( object ) );\n\n\tiv = IMAGEVIEW( object );\n\n#ifdef DEBUG\n\tprintf( \"imageview_destroy\\n\" );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\tUNREF( iv->imagemodel );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\nimageview_class_init( ImageviewClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = imageview_destroy;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n}\n\nstatic void\nimageview_init( Imageview *iv )\n{\n\tiv->imagemodel = NULL;\n}\n\nGtkType\nimageview_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Imageview\",\n\t\t\tsizeof( Imageview ),\n\t\t\tsizeof( ImageviewClass ),\n\t\t\t(GtkClassInitFunc) imageview_class_init,\n\t\t\t(GtkObjectInitFunc) imageview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_FLOATWINDOW, &info );\n\t}\n\n\treturn( type );\n}\n\nstatic void\nimageview_refresh_title( Imageview *iv )\n{\n\tImagemodel *imagemodel = iv->imagemodel;\n\tiImage *iimage = imagemodel->iimage;\n\tRow *row = HEAPMODEL( iimage )->row;\n\tWorkspace *ws = row_get_workspace( row );\n\n\t/* Can come here during ws destroy.\n\t */\n\tif( ws ) {\n\t\tConversion *conv = imagemodel->conv;\n\t\tImageinfo *ii = iimage->value.ii;\n\n\t\tchar txt[512];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\trow_qualified_name_relative( ws->sym, row, &buf );\n\n\t\tif( ii && imageinfo_is_from_file( ii ) )\n\t\t\tvips_buf_appendf( &buf, \" - %s\", IOBJECT( ii )->name );\n\n\t\tvips_buf_appendf( &buf, \" - %.0f%%\", \n\t\t\t100.0 * conversion_dmag( conv->mag ) );\n\n\t\tiwindow_set_title( IWINDOW( iv ), \"%s\", vips_buf_all( &buf ) );\n\t}\n}\n\n/* The model has changed ... update our menus and titlebar.\n */\nstatic void\nimageview_imagemodel_changed_cb( Imagemodel *imagemodel, Imageview *iv )\n{\n\tiWindow *iwnd = IWINDOW( iv );\n\tConversion *conv = imagemodel->conv;\n\n\tGtkAction *action;\n\tint i;\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\"Status\" );\n\tgtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),\n\t\timagemodel->show_status );\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\"Control\" );\n\tgtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),\n\t\timagemodel->show_convert );\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\"Paint\" );\n\tgtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),\n\t\timagemodel->show_paintbox );\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\"Rulers\" );\n\tgtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),\n\t\timagemodel->show_rulers );\n\n\tfor( i = 0; i < IM_NUMBER( imageview_mags ); i++ )\n\t\tif( conv->mag == imageview_mags[i].mag ) {\n\t\t\taction = gtk_action_group_get_action( \n\t\t\t\tiwnd->action_group,\n\t\t\t\timageview_mags[i].name );\n\t\t\tgtk_toggle_action_set_active( \n\t\t\t\tGTK_TOGGLE_ACTION( action ),\n\t\t\t\tTRUE );\n\t\t\tbreak;\n\t\t}\n\n\timageview_refresh_title( iv );\n}\n\n/* Region class names indexed by iRegionType.\n */\nstatic const char *imageview_region_name[] = {\n\tCLASS_MARK,\n\tCLASS_HGUIDE,\n\tCLASS_VGUIDE,\n\tCLASS_ARROW,\n\tCLASS_REGION,\n\tCLASS_AREA\n};\n\n/* Look up a iRegionType from an action name.\n */\nstatic iRegionType\nimageview_get_region_type( GtkAction *action )\n{\n\t/* Action names indexed by iRegionType.\n\t */\n\tstatic const char *action_names[] = {\n\t\t\"NewMark\",\n\t\t\"NewHGuide\",\n\t\t\"NewVGuide\",\n\t\t\"NewArrow\",\n\t\t\"NewRegion\"\n\t};\n\n\tconst char *name = gtk_action_get_name( action );\n\n\tint i;\n\n\tfor( i = 0; i < IM_NUMBER( action_names ); i++ )\n\t\tif( strcmp( name, action_names[i] ) == 0 )\n\t\t\treturn( (iRegionType) i );\n\n\tg_assert( FALSE );\n\t\n\t/* Keep gcc happy.\n\t */\n\treturn( FALSE );\n}\n\nstatic void\nimageview_new_arrow2_action_cb( GtkAction *action, Imageview *iv )\n{\n\tiRegionType rt = imageview_get_region_type( action );\n\tImagemodel *imagemodel = iv->imagemodel;\n\tiImage *iimage = imagemodel->iimage;\n\tRow *row = HEAPMODEL( iimage )->row;\n\tWorkspace *ws = row_get_workspace( row );\n\tConversion *conv = imagemodel->conv;\n\tint dx = imagemodel->visible.left + imagemodel->visible.width / 2;\n\tint dy = imagemodel->visible.top + imagemodel->visible.height / 2;\n\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tSymbol *sym;\n\tint ix, iy;\n\n\tconversion_disp_to_im( conv, dx, dy, &ix, &iy );\n\n\tvips_buf_appendf( &buf, \"%s \", imageview_region_name[rt] );\n\trow_qualified_name_relative( ws->sym, row, &buf );\n\tswitch( rt ) {\n\tcase IREGION_MARK:\n\t\tvips_buf_appendf( &buf, \" (%d) (%d)\", ix, iy );\n\t\tbreak;\n\n\tcase IREGION_HGUIDE:\n\t\tvips_buf_appendf( &buf, \" (%d)\", iy );\n\t\tbreak;\n\n\tcase IREGION_VGUIDE:\n\t\tvips_buf_appendf( &buf, \" (%d)\", ix );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\tif( !(sym = workspace_add_def_recalc( ws, vips_buf_all( &buf ) )) ) {\n\t\tiwindow_alert( GTK_WIDGET( iv ), GTK_MESSAGE_ERROR );\n\t\treturn;\n\t}\n\n\tworkspace_deselect_all( ws );\n}\n\nstatic void\nimageview_new_arrow4_action_cb( GtkAction *action, Imageview *iv )\n{\n\tiRegionType rt = imageview_get_region_type( action );\n\tImagemodel *imagemodel = iv->imagemodel;\n\tiImage *iimage = imagemodel->iimage;\n\tRow *row = HEAPMODEL( iimage )->row;\n\tWorkspace *ws = row_get_workspace( row );\n\tConversion *conv = imagemodel->conv;\n\n\tRect dr, ir;\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tSymbol *sym;\n\tColumn *col;\n\n\tdr.left = imagemodel->visible.left + imagemodel->visible.width / 4;\n\tdr.top = imagemodel->visible.top + imagemodel->visible.height / 4;\n\tdr.width = imagemodel->visible.width / 2;\n\tdr.height = imagemodel->visible.height / 2;\n\tconversion_disp_to_im_rect( conv, &dr, &ir );\n\n\tvips_buf_appendf( &buf, \"%s \", imageview_region_name[rt] );\n\trow_qualified_name_relative( ws->sym, row, &buf );\n\tvips_buf_appendf( &buf, \" (%d) (%d) %d %d\", \n\t\tir.left, ir.top, ir.width, ir.height );\n\n\tif( !(sym = workspace_add_def_recalc( ws, vips_buf_all( &buf ) )) ) {\n\t\tiwindow_alert( GTK_WIDGET( iv ), GTK_MESSAGE_ERROR );\n\t\treturn;\n\t}\n\n\tcol = sym->expr->row->top_col;\n\tcolumn_scrollto( col, MODEL_SCROLL_BOTTOM );\n}\n\nstatic void\nimageview_replace_action_cb( GtkAction *action, Imageview *iv )\n{\n\tImagemodel *imagemodel = iv->imagemodel;\n\tiImage *iimage = imagemodel->iimage;\n\n\tclassmodel_graphic_replace( CLASSMODEL( iimage ), GTK_WIDGET( iv ) );\n}\n\nstatic void\nimageview_save_action_cb( GtkAction *action, Imageview *iv )\n{\n\tImagemodel *imagemodel = iv->imagemodel;\n\tiImage *iimage = imagemodel->iimage;\n\n\tclassmodel_graphic_save( CLASSMODEL( iimage ), GTK_WIDGET( iv ) );\n}\n\nstatic void\nimageview_recalc_action_cb( GtkAction *action, Imageview *iv )\n{\n\tImagemodel *imagemodel = iv->imagemodel;\n\tiImage *iimage = imagemodel->iimage;\n\tRow *row = HEAPMODEL( iimage )->row;\n\n        workspace_deselect_all( row->ws );\n        row_select( row );\n        if( !workspace_selected_recalc( row->ws ) )\n\t\tiwindow_alert( GTK_WIDGET( iv ), GTK_MESSAGE_ERROR );\n        workspace_deselect_all( row->ws );\n}\n\nstatic void\nimageview_header_action_cb( GtkAction *action, Imageview *iv )\n{\n\tImagemodel *imagemodel = iv->imagemodel;\n\tiImage *iimage = imagemodel->iimage;\n\n\tiimage_header( GTK_WIDGET( iv ), MODEL( iimage ) );\n}\n\nstatic void\nimageview_zoom_in_action_cb( GtkAction *action, Imageview *iv )\n{\n\tImagemodel *imagemodel = iv->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\n\tconversion_set_mag( conv, conversion_double( conv->mag ) ); \n}\n\nstatic void\nimageview_zoom_out_action_cb( GtkAction *action, Imageview *iv )\n{\n\tImagemodel *imagemodel = iv->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\n\tconversion_set_mag( conv, conversion_halve( conv->mag ) ); \n}\n\nstatic void\nimageview_zoom_100_action_cb( GtkAction *action, Imageview *iv )\n{\n\tif( iv->ip )\n\t\timagepresent_zoom_to( iv->ip, 1 );\n}\n\nstatic void\nimageview_zoom_fit_action_cb( GtkAction *action, Imageview *iv )\n{\n\timagepresent_zoom_to( iv->ip, 0 );\n}\n\nstatic void\nimageview_show_status_action_cb( GtkToggleAction *action, Imageview *iv )\n{\n\timagemodel_set_status( iv->imagemodel, \n\t\tgtk_toggle_action_get_active( action ) );\n}\n\nstatic void\nimageview_show_convert_action_cb( GtkToggleAction *action, Imageview *iv )\n{\n\timagemodel_set_convert( iv->imagemodel, \n\t\tgtk_toggle_action_get_active( action ) );\n}\n\nstatic void\nimageview_show_paintbox_action_cb( GtkToggleAction *action, Imageview *iv )\n{\n\timagemodel_set_paintbox( iv->imagemodel, \n\t\tgtk_toggle_action_get_active( action ) );\n}\n\nstatic void\nimageview_show_rulers_action_cb( GtkToggleAction *action, Imageview *iv )\n{\n\timagemodel_set_rulers( iv->imagemodel, \n\t\tgtk_toggle_action_get_active( action ) );\n}\n\nstatic void\nimageview_mode_action_cb( GtkRadioAction *action, GtkRadioAction *current,\n\tImageview *iv )\n{\n\tImagemodelState state = (ImagemodelState) \n\t\tgtk_radio_action_get_current_value( action );\n\n\timagemodel_set_state( iv->imagemodel, state, GTK_WIDGET( iv ) );\n}\n\nstatic void\nimageview_mag_action_cb( GtkRadioAction *action, GtkRadioAction *current, \n\tImageview *iv )\n{\n\tif( iv->ip ) \n\t\timagepresent_zoom_to( iv->ip, \n\t\t\tgtk_radio_action_get_current_value( action ) );\n}\n\n/* Our actions.\n */\nstatic GtkActionEntry imageview_actions[] = {\n\t/* Menu items.\n\t */\n\t{ \"ViewToolbarMenu\", NULL, \"_Toolbar\" },\n\t{ \"ViewModeMenu\", NULL, \"M_ode\" },\n\t{ \"ViewZoomMenu\", NULL, \"_Zoom\" },\n\n\t/* Actions.\n\t */\n\t{ \"NewMark\", \n\t\tNULL, N_( \"_Mark\" ), NULL, \n\t\tN_( \"Create a new mark\" ), \n\t\tG_CALLBACK( imageview_new_arrow2_action_cb ) },\n\n\t{ \"NewHGuide\", \n\t\tNULL, N_( \"_Horizontal Guide\" ), NULL, \n\t\tN_( \"Create a new horizontal guide\" ), \n\t\tG_CALLBACK( imageview_new_arrow2_action_cb ) },\n\n\t{ \"NewVGuide\", \n\t\tNULL, N_( \"_Vertical Guide\" ), NULL, \n\t\tN_( \"Create a new vertical guide\" ), \n\t\tG_CALLBACK( imageview_new_arrow2_action_cb ) },\n\n\t{ \"NewArrow\", \n\t\tNULL, N_( \"_Arrow\" ), NULL, \n\t\tN_( \"Create a new arrow\" ), \n\t\tG_CALLBACK( imageview_new_arrow4_action_cb ) },\n\n\t{ \"NewRegion\", \n\t\tNULL, N_( \"_Region\" ), NULL, \n\t\tN_( \"Create a new region\" ), \n\t\tG_CALLBACK( imageview_new_arrow4_action_cb ) },\n\n\t{ \"Replace\", \n\t\tNULL, N_( \"Replace Image\" ), NULL, \n\t\tN_( \"Replace image from file\" ), \n\t\tG_CALLBACK( imageview_replace_action_cb ) },\n\n\t{ \"SaveAs\", \n\t\tGTK_STOCK_SAVE_AS, N_( \"Save Image As\" ), NULL,\n\t\tN_( \"Save image to file\" ), \n\t\tG_CALLBACK( imageview_save_action_cb ) },\n\n\t{ \"Recalculate\", \n\t\tNULL, N_( \"Recalculate\" ), \"<control>C\",\n\t\tN_( \"Recalculate image\" ), \n\t\tG_CALLBACK( imageview_recalc_action_cb ) },\n\n\t{ \"Header\", \n\t\tNULL, N_( \"_Header\" ), NULL,\n\t\tN_( \"View image header\" ), \n\t\tG_CALLBACK( imageview_header_action_cb ) },\n\n\t{ \"ZoomIn\",\n\t\tGTK_STOCK_ZOOM_IN, N_( \"Zoom _In\" ), \"<control>plus\",\n\t\tN_( \"Zoom in on mouse cursor\" ),\n\t\tG_CALLBACK( imageview_zoom_in_action_cb ) },\n\n\t{ \"ZoomOut\",\n\t\tGTK_STOCK_ZOOM_OUT, N_( \"Zoom _Out\" ), \"<control>minus\",\n\t\tN_( \"Zoom out\" ),\n\t\tG_CALLBACK( imageview_zoom_out_action_cb ) },\n\n\t{ \"Zoom100\",\n\t\tGTK_STOCK_ZOOM_100, N_( \"Zoom _100%\" ), \"<control>equal\",\n\t\tN_( \"Zoom to 100%\" ),\n\t\tG_CALLBACK( imageview_zoom_100_action_cb ) },\n\n\t{ \"ZoomFit\",\n\t\tGTK_STOCK_ZOOM_FIT, N_( \"Zoom to _Fit\" ), NULL,\n\t\tN_( \"Zoom to fit image to window\" ),\n\t\tG_CALLBACK( imageview_zoom_fit_action_cb ) }\n};\n\nstatic GtkToggleActionEntry imageview_toggle_actions[] = {\n\t{ \"Status\",\n\t\tNULL, N_( \"_Status\" ), NULL,\n\t\tN_( \"Show status bar\" ),\n\t\tG_CALLBACK( imageview_show_status_action_cb ), TRUE },\n\n\t{ \"Control\",\n\t\tNULL, N_( \"_Display Control\" ), NULL,\n\t\tN_( \"Show display control bar\" ),\n\t\tG_CALLBACK( imageview_show_convert_action_cb ), TRUE },\n\n\t{ \"Paint\",\n\t\tNULL, N_( \"_Paint\" ), NULL,\n\t\tN_( \"Show paint bar\" ),\n\t\tG_CALLBACK( imageview_show_paintbox_action_cb ), FALSE },\n\n\t{ \"Rulers\",\n\t\tNULL, N_( \"_Rulers\" ), NULL,\n\t\tN_( \"Show rulers\" ),\n\t\tG_CALLBACK( imageview_show_rulers_action_cb ), FALSE }\n};\n\nstatic GtkRadioActionEntry imageview_mode_radio_actions[] = {\n\t{ \"SelectMode\",\n\t\tNULL, N_( \"_Select\" ), NULL,\n\t\tN_( \"Select and modify selections\" ),\n\t\tIMAGEMODEL_SELECT },\n\n\t{ \"PanMode\",\n\t\tNULL, N_( \"_Pan\" ), NULL,\n\t\tN_( \"Pan image\" ),\n\t\tIMAGEMODEL_PAN },\n\n\t{ \"ZoomInMode\",\n\t\tNULL, N_( \"Zoom _In\" ), NULL,\n\t\tN_( \"Zoom in on mouse cursor\" ),\n\t\tIMAGEMODEL_MAGIN },\n\n\t{ \"ZoomOutMode\",\n\t\tNULL, N_( \"Zoom _Out\" ), NULL,\n\t\tN_( \"Zoom out\" ),\n\t\tIMAGEMODEL_MAGOUT }\n};\n\nstatic GtkRadioActionEntry imageview_zoom_radio_actions[] = {\n\t{ \"Zoom6Mode\",\n\t\tNULL, N_( \"6%\" ), NULL, N_( \"Zoom to 6%\" ), -16 },\n\t{ \"Zoom12Mode\",\n\t\tNULL, N_( \"12%\" ), NULL, N_( \"Zoom to 12%\" ), -8 },\n\t{ \"Zoom25Mode\",\n\t\tNULL, N_( \"25%\" ), NULL, N_( \"Zoom to 25%\" ), -4 },\n\t{ \"Zoom50Mode\",\n\t\tNULL, N_( \"50%\" ), NULL, N_( \"Zoom to 50%\" ), -2 },\n\t{ \"Zoom100Mode\",\n\t\tNULL, N_( \"100%\" ), NULL, N_( \"Zoom to 100%\" ), 1 },\n\t{ \"Zoom200Mode\",\n\t\tNULL, N_( \"200%\" ), NULL, N_( \"Zoom to 200%\" ), 2 },\n\t{ \"Zoom400Mode\",\n\t\tNULL, N_( \"400%\" ), NULL, N_( \"Zoom to 400%\" ), 4 },\n\t{ \"Zoom800Mode\",\n\t\tNULL, N_( \"800%\" ), NULL, N_( \"Zoom to 800%\" ), 8 },\n\t{ \"Zoom1600Mode\",\n\t\tNULL, N_( \"1600%\" ), NULL, N_( \"Zoom to 1600%\" ), 16 }\n};\n\nstatic const char *imageview_menubar_ui_description =\n\"<ui>\"\n\n\"  <menubar name='ImageviewMenubar'>\"\n\"    <menu action='FileMenu'>\"\n\"      <menu action='NewMenu'>\"\n\"        <menuitem action='NewMark'/>\"\n\"        <menuitem action='NewHGuide'/>\"\n\"        <menuitem action='NewVGuide'/>\"\n\"        <menuitem action='NewArrow'/>\"\n\"        <menuitem action='NewRegion'/>\"\n\"      </menu>\"\n\"      <separator/>\"\n\"      <menuitem action='Replace'/>\"\n\"      <menuitem action='SaveAs'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Recalculate'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Close'/>\"\n\"      <menuitem action='Quit'/>\"\n\"    </menu>\"\n\"    <menu action='ViewMenu'>\"\n\"      <menu action='ViewToolbarMenu'>\"\n\"        <menuitem action='Status'/>\"\n\"        <menuitem action='Control'/>\"\n\"        <menuitem action='Paint'/>\"\n\"        <menuitem action='Rulers'/>\"\n\"      </menu>\"\n\"      <menu action='ViewModeMenu'>\"\n\"        <menuitem action='SelectMode'/>\"\n\"        <menuitem action='PanMode'/>\"\n\"        <menuitem action='ZoomInMode'/>\"\n\"        <menuitem action='ZoomOutMode'/>\"\n\"      </menu>\"\n\"      <menuitem action='Header'/>\"\n\"      <separator/>\"\n\"      <menuitem action='ZoomIn'/>\"\n\"      <menuitem action='ZoomOut'/>\"\n\"      <menuitem action='Zoom100'/>\"\n\"      <menuitem action='ZoomFit'/>\"\n\"      <menu action='ViewZoomMenu'>\"\n\"        <menuitem action='Zoom6Mode'/>\"\n\"        <menuitem action='Zoom12Mode'/>\"\n\"        <menuitem action='Zoom25Mode'/>\"\n\"        <menuitem action='Zoom50Mode'/>\"\n\"        <menuitem action='Zoom100Mode'/>\"\n\"        <menuitem action='Zoom200Mode'/>\"\n\"        <menuitem action='Zoom400Mode'/>\"\n\"        <menuitem action='Zoom800Mode'/>\"\n\"        <menuitem action='Zoom1600Mode'/>\"\n\"      </menu>\"\n\"    </menu>\"\n\"    <menu action='HelpMenu'>\"\n\"      <menuitem action='Guide'/>\"\n\"      <menuitem action='About'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Homepage'/>\"\n\"    </menu>\"\n\"  </menubar>\"\n\n\"  <popup name='ImageviewPopup'>\"\n\"    <menu action='ViewToolbarMenu'>\"\n\"      <menuitem action='Status'/>\"\n\"      <menuitem action='Control'/>\"\n\"      <menuitem action='Paint'/>\"\n\"      <menuitem action='Rulers'/>\"\n\"    </menu>\"\n\"    <menuitem action='Zoom100'/>\"\n\"    <menuitem action='ZoomFit'/>\"\n\"    <menuitem action='Header'/>\"\n\"    <separator/>\"\n\"    <menuitem action='Replace'/>\"\n\"    <menuitem action='SaveAs'/>\"\n\"    <menuitem action='Recalculate'/>\"\n\"    <separator/>\"\n\"    <menuitem action='Close'/>\"\n\"  </popup>\"\n\n\"</ui>\";\n\nstatic gint\nimageview_event( GtkWidget *widget, GdkEvent *event, Imageview *iv )\n{\n\tgboolean handled = FALSE;\n\n#ifdef EVENT\n\tif( event->type == GDK_BUTTON_PRESS )\n\t\tprintf( \"imageview_event: GDK_BUTTON_PRESS\\n\" );\n#endif /*EVENT*/\n\n\tswitch( event->type ) { \n\tcase GDK_MOTION_NOTIFY: \n{\n\t\tImagemodel *imagemodel = iv->imagemodel;\n\t\tConversion *conv = imagemodel->conv;\n\t\tint ix, iy;\n\n\t\tconversion_disp_to_im( conv, \n\t\t\tevent->button.x, event->button.y, &ix, &iy );\n\n\t\tstatusview_mouse( iv->sv, ix, iy );\n}\n\n\t\tbreak;\n\n\tcase GDK_BUTTON_PRESS:\n\t\tswitch( event->button.button ) {\n\t\tcase 3:\n{\n\t\t\tiWindow *iwnd = IWINDOW( iv );\n\t\t\tGtkWidget *popup;\n\n\t\t\tpopup = gtk_ui_manager_get_widget( iwnd->ui_manager, \n\t\t\t\t\"/ImageviewPopup\" );\n\t\t\tgtk_menu_popup( GTK_MENU( popup ), NULL, NULL,\n\t\t\t\t(GtkMenuPositionFunc) NULL, NULL, 3, \n\t\t\t\tevent->button.time );\n\t\t\thandled = TRUE;\n}\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn( handled );\n}\n\nstatic gboolean\nimageview_filedrop( Imageview *iv, const char *file )\n{\n\tgboolean result;\n\n\tif( (result = iimage_replace( iv->imagemodel->iimage, file )) )\n\t\tsymbol_recalculate_all();\n\n\treturn( result );\n}\n\nstatic void\nimageview_build( Imageview *iv, GtkWidget *vbox, iImage *iimage )\n{\n\tiWindow *iwnd = IWINDOW( iv );\n\n\tGError *error;\n\tGtkWidget *mbar;\n\tGtkWidget *frame;\n\tGList *focus_chain;\n\n\t/* All the model parts for our set of views.\n\t */\n\tiv->imagemodel = imagemodel_new( iimage );\n\tg_object_ref( G_OBJECT( iv->imagemodel ) );\n\tiobject_sink( IOBJECT( iv->imagemodel ) );\n\tiv->imagemodel_changed_sid = g_signal_connect( \n\t\tG_OBJECT( iv->imagemodel ), \"changed\", \n\t\tG_CALLBACK( imageview_imagemodel_changed_cb ), iv );\n\n        /* Make main menu bar\n         */\n\tgtk_action_group_add_actions( iwnd->action_group, \n\t\timageview_actions, G_N_ELEMENTS( imageview_actions ), \n\t\tGTK_WINDOW( iv ) );\n\tgtk_action_group_add_toggle_actions( iwnd->action_group, \n\t\timageview_toggle_actions, \n\t\t\tG_N_ELEMENTS( imageview_toggle_actions ), \n\t\tGTK_WINDOW( iv ) );\n\tgtk_action_group_add_radio_actions( iwnd->action_group,\n\t\timageview_mode_radio_actions, \n\t\t\tG_N_ELEMENTS( imageview_mode_radio_actions ), \n\t\tIMAGEMODEL_SELECT,\n\t\tG_CALLBACK( imageview_mode_action_cb ),\n\t\tGTK_WINDOW( iv ) );\n\tgtk_action_group_add_radio_actions( iwnd->action_group,\n\t\timageview_zoom_radio_actions, \n\t\t\tG_N_ELEMENTS( imageview_zoom_radio_actions ), \n\t\t1,\n\t\tG_CALLBACK( imageview_mag_action_cb ),\n\t\tGTK_WINDOW( iv ) );\n\n\terror = NULL;\n\tif( !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager,\n\t\timageview_menubar_ui_description, -1, &error ) ) {\n\t\tg_message( \"building menus failed: %s\", error->message );\n\t\tg_error_free( error );\n\t\texit( EXIT_FAILURE );\n\t}\n\n\tmbar = gtk_ui_manager_get_widget( iwnd->ui_manager, \n\t\t\"/ImageviewMenubar\" );\n\tgtk_box_pack_start( GTK_BOX( vbox ), mbar, FALSE, FALSE, 0 );\n        gtk_widget_show( mbar );\n\n\t/* This will set to NULL if we don't have infobar support.\n\t */\n\tif( (IWINDOW( iv )->infobar = infobar_new()) ) \n\t\tgtk_box_pack_start( GTK_BOX( vbox ), \n\t\t\tGTK_WIDGET( IWINDOW( iv )->infobar ), FALSE, FALSE, 0 );\n\n\t/* Status bar.\n\t */\n\tiv->sv = statusview_new( iv->imagemodel );\n\tgtk_box_pack_start( GTK_BOX( vbox ), \n\t\tGTK_WIDGET( iv->sv ), FALSE, FALSE, 0 );\n\n\t/* Conversion bar.\n\t */\n\tiv->cv = conversionview_new( iv->imagemodel );\n\tgtk_box_pack_start( GTK_BOX( vbox ), \n\t\tGTK_WIDGET( iv->cv ), FALSE, FALSE, 0 );\n\n\t/* Paintbox bar.\n\t */\n\tiv->pbv = paintboxview_new( iv->imagemodel );\n\tgtk_box_pack_start( GTK_BOX( vbox ), \n\t\tGTK_WIDGET( iv->pbv ), FALSE, FALSE, 0 );\n\n\t/* Image area. \n\t */\n\tframe = gtk_frame_new( NULL );\n\tgtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_OUT );\n\tgtk_widget_show( frame );\n\tgtk_box_pack_start( GTK_BOX( vbox ), \n\t\tGTK_WIDGET( frame ), TRUE, TRUE, 0 );\n\tiv->ip = imagepresent_new( iv->imagemodel );\n\tgtk_container_add( GTK_CONTAINER( frame ), GTK_WIDGET( iv->ip ) );\n\tgtk_widget_show( GTK_WIDGET( iv->ip ) );\n\tgtk_signal_connect_after( GTK_OBJECT( iv->ip->id ), \"event\",\n\t\tGTK_SIGNAL_FUNC( imageview_event ), iv );\n\n\t/* Position and size to restore?\n\t */\n\tif( MODEL( iimage )->window_width != -1 ) {\n\t\t/* Floatwindow will set pos/size.\n\t\t */\n\t\tiv->imagemodel->show_status = iimage->show_status;\n\t\tiv->imagemodel->show_paintbox = iimage->show_paintbox;\n\t\tiv->imagemodel->show_convert = iimage->show_convert;\n\t\tiv->imagemodel->show_rulers = iimage->show_rulers;\n\t\tiv->imagemodel->scale = iimage->scale;\n\t\tiv->imagemodel->offset = iimage->offset;\n\t\tiv->imagemodel->falsecolour = iimage->falsecolour;\n\t\tiv->imagemodel->type = iimage->type;\n\n\t\t/* Our caller must call imagepresent_set_mag_pos() after\n\t\t * _show(). Not accurate if we set it here.\n\t\t */\n\t}\n\telse {\n\t\tint w, h; \n\n\t\t/* Set initial size. This is really hard to do right :-( These\n\t\t * magic numbers will break with different themes.\n\n\t\t \tFIXME ... maybe realize the window but don't map it,\n\t\t\tcalculate border size, then set default size and map?\n\t\t\tyuk!\n\n\t\t\tthe magic numbers here are hard to derive, there are \n\t\t\tmany, many widgets piled up together to make this \n\t\t\twindow\n\n\t\t\tlast set correctly for clearlooks\n\n\t\t */\n\t\tw = IM_MIN( IMAGE_WINDOW_WIDTH, \n\t\t\tiv->imagemodel->conv->image.width + 14 );\n\t\th = IM_MIN( IMAGE_WINDOW_HEIGHT, \n\t\t\tiv->imagemodel->conv->image.height + 39 );\n\t\tgtk_window_set_default_size( GTK_WINDOW( iv ), w, h );\n\t\tconversion_set_mag( iv->imagemodel->conv, 1 );\n\t}\n\n\t/* Set as file drop destination \n\t */\n\tfiledrop_register( GTK_WIDGET( iv ), \n\t\t(FiledropFunc) imageview_filedrop, iv );\n\n\t/* Override the focus_chain ... we want the imagedisplay first.\n\t */\n\tfocus_chain = NULL;\n\tfocus_chain = g_list_append( focus_chain, iv->ip );\n\tfocus_chain = g_list_append( focus_chain, iv->cv );\n\tfocus_chain = g_list_append( focus_chain, iv->pbv );\n\tgtk_container_set_focus_chain( GTK_CONTAINER( vbox ), focus_chain );\n\tg_list_free( focus_chain );\n\n\tgtk_widget_grab_focus( GTK_WIDGET( iv->ip->id ) );\n}\n\nstatic void *\nimageview_add_region( Classmodel *classmodel, Imageview *iv )\n{\n\tiRegionInstance *instance;\n\n\tif( MODEL( classmodel )->display &&\n\t\t(instance = classmodel_get_instance( classmodel )) ) {\n\t\tRegionview *regionview = regionview_new( classmodel, \n\t\t\t&instance->area, iv->ip );\n\t\tPElement *root = &HEAPMODEL( classmodel )->row->expr->root;\n\n\t\t/* Look at the class we are drawing, set the display type.\n\t\t */\n\t\tregionview_set_type( regionview, root );\n\t}\n\n\treturn( NULL );\n}\n\nstatic void\nimageview_popdown( iWindow *iwnd, void *client,\n\tiWindowNotifyFn nfn, void *sys )\n{\n\tImageview *iv = IMAGEVIEW( iwnd );\n\tImagemodel *imagemodel = iv->imagemodel;\n\tiImage *iimage = imagemodel->iimage;\n\tConversion *conv = imagemodel->conv;\n\n\t/* We have to note position/size in popdown rather than destroy, since\n\t * the widgets have to all still be extant.\n\t */\n\n\t/* Save the centre of the window in image cods.\n\t */\n\tconversion_disp_to_im( conv, \n\t\timagemodel->visible.left + imagemodel->visible.width / 2, \n\t\timagemodel->visible.top + imagemodel->visible.height / 2,\n\t\t&iimage->image_left, &iimage->image_top );\n\tiimage->image_mag = conv->mag;\n\n\tiimage->show_status = imagemodel->show_status;\n\tiimage->show_paintbox = imagemodel->show_paintbox;\n\tiimage->show_rulers = imagemodel->show_rulers;\n\n\t/* Signal changed on iimage if we save the convert settings. This will\n\t * make the thumbnail update.\n\t */\n\tif( iimage->show_convert != imagemodel->show_convert ||\n\t\tiimage->scale != imagemodel->scale ||\n\t\tiimage->offset != imagemodel->offset ||\n\t\tiimage->falsecolour != imagemodel->falsecolour ||\n\t\tiimage->type != imagemodel->type ) {\n\t\tiimage->show_convert = imagemodel->show_convert;\n\t\tiimage->scale = imagemodel->scale;\n\t\tiimage->offset = imagemodel->offset;\n\t\tiimage->falsecolour = imagemodel->falsecolour;\n\t\tiimage->type = imagemodel->type;\n\t\tiobject_changed( IOBJECT( iimage ) );\n\t}\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nimageview_link( Imageview *iv, iImage *iimage, GtkWidget *parent )\n{\n\tiwindow_set_build( IWINDOW( iv ), \n\t\t(iWindowBuildFn) imageview_build, iimage, NULL, NULL );\n\tiwindow_set_popdown( IWINDOW( iv ), imageview_popdown, NULL );\n\tiwindow_set_parent( IWINDOW( iv ), parent );\n\tfloatwindow_link( FLOATWINDOW( iv ), MODEL( iimage ) );\n\tiwindow_build( IWINDOW( iv ) );\n\tslist_map( iimage->classmodels,\n\t\t(SListMapFn) imageview_add_region, iv );\n\n\t/* Initial \"changed\" on the model to get all views to init.\n\t */\n\tiobject_changed( IOBJECT( iv->imagemodel ) );\n}\n\nImageview *\nimageview_new( iImage *iimage, GtkWidget *parent )\n{\n\tImageview *iv = gtk_type_new( TYPE_IMAGEVIEW );\n\n\timageview_link( iv, iimage, parent );\n\n\t/* This is odd ... we wouldn't normally _show() the widget in _new(),\n\t * but restoring the scroll position doesn't work unless the window is\n\t * visible. We have to show here.\n\t */\n\tgtk_widget_show( GTK_WIDGET( iv ) );\n\n\tif( MODEL( iimage )->window_width != -1 ) \n\t\timagepresent_set_mag_pos( iv->ip, \n\t\t\tiimage->image_mag,\n\t\t\tiimage->image_left, iimage->image_top );\n\n\treturn( iv );\n}\n\n/* Make an imageview, and try to make area (image cods) visible. width/height\n * can be -ve\n */\nImageview *\nimageview_new_area( iImage *iimage, Rect *area, GtkWidget *parent )\n{\n\tImageview *iv = imageview_new( iimage, parent );\n\tImagemodel *imagemodel = iv->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tint shrink_x, shrink_y, shrink;\n\n\t/* Calculate a shrink factor which should make all the region \n\t * visible ... don't zoom.\n\t */\n\tshrink_x = (abs( area->width ) + conv->canvas.width) / \n\t\tconv->canvas.width;\n\tshrink_y = (abs( area->height ) + conv->canvas.height) / \n\t\tconv->canvas.height;\n\tshrink = -IM_MAX( 1, IM_MAX( shrink_x, shrink_y ) );\n\tif( shrink == -1 )\n\t\tshrink = 1;\n\n\timagepresent_set_mag_pos( iv->ip, shrink, \n\t\tarea->left + area->width / 2, \n\t\tarea->top + area->height / 2 );\n\n\treturn( iv );\n}\n"
  },
  {
    "path": "src/imageview.h",
    "content": "/* Decls for imageview.c ... display an image in a window.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_IMAGEVIEW (imageview_get_type())\n#define IMAGEVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_IMAGEVIEW, Imageview ))\n#define IMAGEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_IMAGEVIEW, ImageviewClass ))\n#define IS_IMAGEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IMAGEVIEW ))\n#define IS_IMAGEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_IMAGEVIEW ))\n\ntypedef struct _Imageview {\n\tFloatwindow parent_class;\n\n\t/* Model stuff here.\n\t */\n\tImagemodel *imagemodel;\n\tguint imagemodel_changed_sid;\n\n\tImagepresent *ip;\n\tConversionview *cv;\n\tStatusview *sv;\n\tPaintboxview *pbv;\n} Imageview;\n\ntypedef struct _ImageviewClass {\n\tFloatwindowClass parent_class;\n\n\t/* My methods.\n\t */\n} ImageviewClass;\n\nGtkType imageview_get_type( void );\nvoid imageview_set_paint( Imageview *iv, gboolean paint );\nImageview *imageview_new( iImage *iimage, GtkWidget *parent );\nImageview *imageview_new_area( iImage *iimage, Rect *area, GtkWidget *parent );\n"
  },
  {
    "path": "src/iobject.c",
    "content": "/* abstract base class for all nip objects\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* Our signals. \n */\nenum {\n\tSIG_DESTROY,\t/* End lifetime */\n\tSIG_CHANGED,\t/* iObject has changed somehow */\n\tSIG_LAST\n};\n\nstatic GObjectClass *parent_class = NULL;\n\nstatic guint iobject_signals[SIG_LAST] = { 0 };\n\n/* Don't emit \"destroy\" immediately, do it from the _dispose handler.\n */\nvoid *\niobject_destroy( iObject *iobject )\n{\n#ifdef DEBUG\n\tprintf( \"iobject_destroy: \" );\n\tiobject_print( iobject );\n#endif /*DEBUG*/\n\n\tif( !iobject->in_destruction )\n\t\tg_object_run_dispose( G_OBJECT( iobject ) );\n\n\treturn( NULL );\n}\n\nvoid *\niobject_changed( iObject *iobject )\n{\n\tg_return_val_if_fail( iobject != NULL, NULL );\n\tg_return_val_if_fail( IS_IOBJECT( iobject ), NULL );\n\n#ifdef DEBUG\n\tprintf( \"iobject_changed: \" );\n\tiobject_print( iobject );\n#endif /*DEBUG*/\n\n\tg_signal_emit( G_OBJECT( iobject ), iobject_signals[SIG_CHANGED], 0 );\n\n\treturn( NULL );\n}\n\nvoid *\niobject_info( iObject *iobject, VipsBuf *buf )\n{\n\tiObjectClass *iobject_class = IOBJECT_GET_CLASS( iobject );\n\n\tg_return_val_if_fail( iobject != NULL, NULL );\n\tg_return_val_if_fail( IS_IOBJECT( iobject ), NULL );\n\n\tif( iobject_class->info )\n\t\tiobject_class->info( iobject, buf );\n\n\treturn( NULL );\n}\n\nstatic void\niobject_dispose( GObject *gobject )\n{\n\tiObject *iobject = IOBJECT( gobject );\n\n#ifdef DEBUG\n\tprintf( \"iobject_dispose: \" );\n\tiobject_print( iobject );\n#endif /*DEBUG*/\n\n\tif( !iobject->in_destruction ) {\n\t\tiobject->in_destruction = TRUE;\n\t\tg_signal_emit( G_OBJECT( iobject ), \n\t\t\tiobject_signals[SIG_DESTROY], 0 );\n\t\tiobject->in_destruction = FALSE;\n\t}\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\niobject_finalize( GObject *gobject )\n{\n\tiObject *iobject = IOBJECT( gobject );\n\n#ifdef DEBUG\n\tprintf( \"iobject_finalize: \" );\n\tiobject_print( iobject );\n#endif /*DEBUG*/\n\n\t/* Unlike GTK, we allow floating objects to be finalized. Handy if a\n\t * _new() fails. So don't assert( !iobject->floating );\n\t */\n\n\tIM_FREE( iobject->name );\n\tIM_FREE( iobject->caption );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\niobject_real_destroy( iObject *iobject )\n{\n}\n\nstatic void\niobject_real_changed( iObject *iobject )\n{\n\tiObjectClass *iobject_class = IOBJECT_GET_CLASS( iobject );\n\n\tif( iobject_class->generate_caption )\n\t\tIM_SETSTR( iobject->caption, \n\t\t\tiobject_class->generate_caption( iobject ) );\n}\n\nstatic void\niobject_real_info( iObject *iobject, VipsBuf *buf )\n{\n\tif( iobject->name )\n\t\tvips_buf_appendf( buf, \"name = \\\"%s\\\"\\n\", iobject->name );\n\tif( iobject->caption )\n\t\tvips_buf_appendf( buf, \"caption = \\\"%s\\\"\\n\", iobject->caption );\n\tvips_buf_appendf( buf, \"iObject :: \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( iobject ) );\n}\n\nstatic void\niobject_class_init( iObjectClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = iobject_dispose;\n\tgobject_class->finalize = iobject_finalize;\n\n\tclass->destroy = iobject_real_destroy;\n\tclass->changed = iobject_real_changed;\n\tclass->info = iobject_real_info;\n\tclass->generate_caption = NULL;\n\n\tclass->user_name = _( \"Object\" );\n\n\t/* Create signals.\n\t */\n\tiobject_signals[SIG_DESTROY] = g_signal_new( \"destroy\",\n\t\tG_TYPE_FROM_CLASS( gobject_class ),\n\t\tG_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,\n\t\tG_STRUCT_OFFSET( iObjectClass, destroy ), \n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\tiobject_signals[SIG_CHANGED] = g_signal_new( \"changed\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( iObjectClass, changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n}\n\nstatic void\niobject_init( iObject *iobject )\n{\n#ifdef DEBUG\n\tprintf( \"iobject_init: \" );\n\tiobject_print( iobject );\n#endif /*DEBUG*/\n\n\t/* Init our instance fields.\n\t */\n\tiobject->name = NULL;\n\tiobject->caption = NULL;\n\tiobject->floating = TRUE;\n\tiobject->in_destruction = FALSE;\n}\n\nGType\niobject_get_type( void )\n{\n\tstatic GType iobject_type = 0;\n\n\tif( !iobject_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( iObjectClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) iobject_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( iObject ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) iobject_init,\n\t\t};\n\n\t\tiobject_type = g_type_register_static( G_TYPE_OBJECT, \n\t\t\t\"iObject\", &info, 0 );\n\t}\n\n\treturn( iobject_type );\n}\n\n/* Test the name field ... handy with map.\n */\nvoid *\niobject_test_name( iObject *iobject, const char *name )\n{\n\tg_return_val_if_fail( iobject != NULL, NULL );\n\tg_return_val_if_fail( IS_IOBJECT( iobject ), NULL );\n\n\tif( iobject->name && strcmp( iobject->name, name ) == 0 )\n\t\treturn( iobject );\n\n\treturn( NULL );\n}\n\nvoid *\niobject_print( iObject *iobject )\n{\n\tg_print( \"%s \\\"%s\\\" (%p)\\n\", \n\t\tG_OBJECT_TYPE_NAME( iobject ),\n\t\tNN( iobject->name ), \n\t\tiobject ); \n\n\treturn( NULL );\n}\n\nvoid\niobject_set( iObject *iobject, const char *name, const char *caption )\n{\n\tgboolean changed = FALSE;\n\n\tg_return_if_fail( iobject != NULL );\n\tg_return_if_fail( IS_IOBJECT( iobject ) );\n\n\tif( name && name != iobject->name ) {\n\t\tIM_SETSTR( iobject->name, name );\n\t\tchanged = TRUE;\n\t}\n\tif( caption && caption != iobject->caption ) {\n\t\tIM_SETSTR( iobject->caption, caption );\n\t\tchanged = TRUE;\n\t}\n\n\tif( changed )\n\t\tiobject_changed( iobject );\n\n#ifdef DEBUG\n\tprintf( \"iobject_set: \" );\n\tiobject_print( iobject );\n#endif /*DEBUG*/\n}\n\nvoid\niobject_sink( iObject *iobject )\n{\n\tg_assert( IS_IOBJECT( iobject ) ); \n\n\tif( iobject->floating ) {\n\t\tiobject->floating = FALSE;\n\t\tg_object_unref( G_OBJECT( iobject ) );\n\t}\n}\n\nvoid\niobject_dump( iObject *iobject )\n{\n\tchar txt[1000];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tiobject_info( iobject, &buf );\n\tprintf( \"%s\", vips_buf_all( &buf ) );\n}\n"
  },
  {
    "path": "src/iobject.h",
    "content": "/* abstract base class for all nip objects\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_IOBJECT (iobject_get_type())\n#define IOBJECT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IOBJECT, iObject ))\n#define IOBJECT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_IOBJECT, iObjectClass))\n#define IS_IOBJECT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IOBJECT ))\n#define IS_IOBJECT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IOBJECT ))\n#define IOBJECT_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_IOBJECT, iObjectClass ))\n\n/* Handy iobject_destroy() shortcut.\n */\n#define IDESTROY( O ) { \\\n\tif( O ) { \\\n\t\t(void) iobject_destroy( IOBJECT( O ) ); \\\n\t\t( O ) = NULL; \\\n\t} \\\n}\n\nstruct _iObject {\n\tGObject parent_object;\n\n\t/* My instance vars.\n\t */\n        char *name;             /* iObject name */\n        char *caption;          /* Comment of some sort */\n\n\t/* True when created ... the 1 reference that gobject makes is\n\t * 'floating' and not owned by anyone. Do _sink() after every _ref()\n\t * to transfer ownership to the parent container. Upshot: no need to\n\t * _unref() after _add() in _new().\n\t */\n\tgboolean floating;\n\n\t/* Stop destroy loops with this.\n\t */\n\tgboolean in_destruction;\n};\n\ntypedef struct _iObjectClass {\n\tGObjectClass parent_class;\n\n\t/* End object's lifetime, just like gtk_object_destroy.\n\t */\n\tvoid (*destroy)( iObject * );\n\n\t/* Something about the object has changed. Should use glib's properties\n\t * but fix this later.\n\t */\n\tvoid (*changed)( iObject * );\n\n\t/* Try and say something useful about us.\n\t */\n\tvoid (*info)( iObject *, VipsBuf * );\n\n\t/* Called on _changed() to update the caption. Define this if you want\n\t * the caption to be an explanatory note about the object. \n\t */\n\tconst char *(*generate_caption)( iObject * );\n\n\t/* The i18n name for this class we show the user. FOr example,\n\t * Workspace is referred to as \"tab\" by the user.\n\t */\n\tconst char *user_name;\n} iObjectClass;\n\n#define IOBJECT_GET_CLASS_NAME( obj ) \\\n\t((G_TYPE_INSTANCE_GET_CLASS( (obj), \\\n\t\tTYPE_IOBJECT, iObjectClass ))->user_name)\n\nvoid *iobject_destroy( iObject *iobject );\nvoid *iobject_changed( iObject *iobject );\nvoid *iobject_info( iObject *iobject, VipsBuf * );\n\nGType iobject_get_type( void );\n\nvoid *iobject_test_name( iObject *iobject, const char *name );\nvoid *iobject_print( iObject *iobject );\nvoid iobject_set( iObject *iobject, const char *name, const char *caption );\nvoid iobject_sink( iObject *iobject );\nvoid iobject_dump( iObject *iobject );\n"
  },
  {
    "path": "src/ip.h",
    "content": "/* All ip headers.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* We can get multiple includes sometimes, gah, thank you bison.\n */\n#ifndef IP_H\n#define IP_H\n\n/* DEBUG everywhere.\n#define DEBUG\n */\n\n/* Turn off VIPS's old and broken defines, we don't need them.\n */\n#define IM_NO_VIPS7_COMPAT\n\n/* Enable heap sanity checks on every alloc ... very slow ... also see heap.c\n#define DEBUG_HEAP\n */\n\n#ifdef HAVE_CONFIG_H\n#include <config.h>\n#endif /*HAVE_CONFIG_H*/\n\n#ifdef ENABLE_NLS\n#include <libintl.h>\n#define _(String) gettext(String)\n#ifdef gettext_noop\n#define N_(String) gettext_noop(String)\n#else\n#define N_(String) (String)\n#endif\n#else /* NLS is disabled */\n#define _(String) (String)\n#define N_(String) (String)\n#define textdomain(String) (String)\n#define gettext(String) (String)\n#define dgettext(Domain,String) (String)\n#define dcgettext(Domain,String,Type) (String)\n#define bindtextdomain(Domain,Directory) (Domain) \n#define bind_textdomain_codeset(Domain,Codeset) (Codeset) \n#define ngettext(S, P, N) ((N) == 1 ? (S) : (P))\n#endif /* ENABLE_NLS */\n\n#include <time.h>\n#include <ctype.h>\n#include <errno.h>\n#include <limits.h>\n#include <math.h>\n#include <memory.h>\n#include <locale.h>\n#include <setjmp.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#ifdef HAVE_PWD_H\n#include <pwd.h>\n#endif /*HAVE_PWD_H*/\n#ifdef HAVE_FNMATCH_H\n#include <fnmatch.h>\n#endif /*HAVE_FNMATCH_H*/\n#ifdef HAVE_SYS_PARAM_H\n#include <sys/param.h>\n#endif /*HAVE_SYS_PARAM_H*/\n#include <sys/stat.h>\n#ifdef HAVE_SYS_TIME_H\n#include <sys/time.h>\n#endif /*HAVE_SYS_TIME_H*/\n#include <sys/types.h>\n#ifdef HAVE_SYS_RESOURCE_H\n#include <sys/resource.h>\n#endif /*HAVE_SYS_RESOURCE_H*/\n#ifdef HAVE_SYS_WAIT_H\n#include <sys/wait.h>\n#endif /*HAVE_SYS_WAIT_H*/\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif /*HAVE_UNISTD_H*/\n#ifdef HAVE_SYS_STATVFS_H\n#include <sys/statvfs.h>\n#endif /*HAVE_SYS_STATVFS_H*/\n#ifdef HAVE_SYS_VFS_H\n#include <sys/vfs.h>\n#endif /*HAVE_SYS_VFS_H*/\n#ifdef HAVE_SYS_MOUNT_H\n#include <sys/mount.h>\n#endif /*HAVE_SYS_MOUNT_H*/\n#ifdef OS_WIN32\n#include <windows.h>\n#endif /*OS_WIN32*/\n#ifdef HAVE_FFTW\n#include <fftw.h>\n#endif /*HAVE_FFTW*/\n#ifdef HAVE_FFTW3\n#include <fftw3.h>\n#endif /*HAVE_FFTW3*/\n#include <fcntl.h>\n\n/* Have to include glib before dmalloc ... dmalloc may be included by vips.h\n */\n#include <gtk/gtk.h>\n#include <gdk/gdkkeysyms.h>\n\n#ifdef HAVE_LIBGOFFICE\n#include <goffice/goffice.h>\n\n#include <goffice/app/go-plugin.h>\n#include <goffice/app/go-plugin-loader-module.h>\n\n#include <goffice/data/go-data-simple.h>\n\n#include <goffice/graph/gog-data-set.h>\n#include <goffice/graph/gog-label.h>\n#include <goffice/graph/gog-object.h>\n#include <goffice/graph/gog-plot.h>\n#include <goffice/graph/gog-series.h>\n#include <goffice/graph/gog-grid.h>\n#include <goffice/graph/gog-grid-line.h>\n#include <goffice/graph/gog-legend.h>\n#include <goffice/graph/gog-chart-map.h>\n\n\n#include <goffice/utils/go-color.h>\n#include <goffice/utils/go-marker.h>\n#endif /*HAVE_LIBGOFFICE*/\n\n#ifdef HAVE_LIBGVC\n#include <gvc.h>\n#endif /*HAVE_LIBGVC*/\n\n#include <vips/vips.h>\n#include <vips/vips7compat.h>\n#include <vips/debug.h>\n\n#include <libxml/tree.h>\n#include <libxml/parser.h>\n\n/* If we're not using GNU C, elide __attribute__ \n */\n#ifndef __GNUC__\n#  ifndef __attribute__\n#    define  __attribute__(x)  /*NOTHING*/\n#  endif\n#endif\n\n/* Our general widgets.\n */\n#include \"formula.h\"\n#include \"doubleclick.h\"\n\n/* Generated marshallers.\n */\n#include \"nipmarshal.h\"\n\n/* XML namespace ... note, not nip2! We can't change this.\n */\n#define NAMESPACE \"http://www.vips.ecs.soton.ac.uk/nip\" \n\n#define MAXFILES (4000)\t\t/* Max. no of files in path */\n#define STACK_SIZE (1000)\t/* Depth of eval stack */\n#define LEN_LABEL (512)\t\t/* Label on windows */\n#define MAX_SYSTEM (50)\t\t/* Max number of args we allow */\n#define MAX_BANDS (64)\t\t/* Max number of bands in image */\n#define MAX_CSTACK (10)\t\t/* Max number of cursors we stack */\n#define MAX_STRSIZE (100000)\t/* Size of text for user defs */\n#define MAX_TRACE (1024)\t/* Biggest thing we print in trace */\n#define MAX_SSTACK (40)\t\t/* Scope stack for parser */\n#define VIPS_HOMEPAGE \"https://github.com/jcupitt/nip2\"\n#define IP_NAME PACKAGE \"-\" VERSION\n#define NIP_DOCPATH \"$VIPSHOME\" G_DIR_SEPARATOR_S \"share\" G_DIR_SEPARATOR_S \\\n        \"doc\" G_DIR_SEPARATOR_S PACKAGE G_DIR_SEPARATOR_S \"html\"\n#define VIPS_DOCPATH \"$VIPSHOME\" G_DIR_SEPARATOR_S \"share\" G_DIR_SEPARATOR_S \\\n\t\"doc\" G_DIR_SEPARATOR_S \"vips\" G_DIR_SEPARATOR_S \"html\"\n#define IP_NAME PACKAGE \"-\" VERSION\n#define MAX_LINELENGTH (120)\t/* Max chars we display of value */\n#define MAX_RECENT (10)\t\t/* Number of recent items in file menu */\n#define NIP_COPYRIGHT \"%s: &#0169;2023 libvips.org\"\n\n/* Our stock_ids.\n */\n#define STOCK_NEXT_ERROR \"nip-next-error\"\n#define STOCK_DROPPER \"nip-dropper\"\n#define STOCK_DUPLICATE \"nip-duplicate\"\n#define STOCK_PAINTBRUSH \"nip-paintbrush\"\n#define STOCK_LINE \"nip-linedraw\"\n#define STOCK_TEXT \"nip-text\"\n#define STOCK_SMUDGE \"nip-smudge\"\n#define STOCK_FLOOD \"nip-flood\"\n#define STOCK_FLOOD_BLOB \"nip-floodblob\"\n#define STOCK_RECT \"nip-rect\"\n#define STOCK_MOVE \"nip-move\"\n#define STOCK_LOCK \"nip-lock\"\n#define STOCK_ALERT \"nip-alert\"\n#define STOCK_SELECT \"nip-select\"\n#define STOCK_LED_RED \"nip-led-red\"\n#define STOCK_LED_GREEN \"nip-led-green\"\n#define STOCK_LED_BLUE \"nip-led-blue\"\n#define STOCK_LED_YELLOW \"nip-led-yellow\"\n#define STOCK_LED_CYAN \"nip-led-cyan\"\n#define STOCK_LED_OFF \"nip-led-off\"\n\n/* How much we decompile for error messages.\n */\n#define MAX_ERROR_FRAG (100)\n\n/* win32 adds '_', sometimes. \n */\n#ifdef OS_WIN32\n#ifndef popen\n#define popen(b,m) _popen(b,m)\n#endif /*popen*/\n#ifndef pclose\n#define pclose(f) _pclose(f)\n#endif /*pclose*/\n#define mktemp(f) _mktemp(f)\n#endif /*OS_WIN32*/\n\n/* Fwd ref these.\n */\ntypedef struct _Watch Watch;\ntypedef struct _Toolitem Toolitem;\ntypedef struct _BuiltinInfo BuiltinInfo;\ntypedef struct _Classmodel Classmodel;\ntypedef struct _Colour Colour;\ntypedef struct _Column Column;\ntypedef struct _Columnview Columnview;\ntypedef struct _Compile Compile;\ntypedef struct _Conversion Conversion;\ntypedef struct _Conversionview Conversionview;\ntypedef struct _Expr Expr;\ntypedef struct _Filemodel Filemodel;\ntypedef struct _Heap Heap;\ntypedef struct _HeapBlock HeapBlock;\ntypedef struct _Heapmodel Heapmodel;\ntypedef struct _iArrow iArrow;\ntypedef struct _iImage iImage;\ntypedef struct _Imagedisplay Imagedisplay;\ntypedef struct _Managed Managed;\ntypedef struct _Managedfile Managedfile;\ntypedef struct _Managedgvalue Managedgvalue;\ntypedef struct _Managedgobject Managedgobject;\ntypedef struct _Managedstring Managedstring;\ntypedef struct _Imageinfo Imageinfo;\ntypedef struct _Imagepresent Imagepresent;\ntypedef struct _Imagemodel Imagemodel;\ntypedef struct _iRegion iRegion;\ntypedef struct _iRegiongroup iRegiongroup;\ntypedef struct _Link Link;\ntypedef struct _LinkExpr LinkExpr;\ntypedef struct _Model Model;\ntypedef struct _iObject iObject;\ntypedef struct _iContainer iContainer;\ntypedef struct _Paintboxview Paintboxview;\ntypedef struct _ParseConst ParseConst;\ntypedef struct _ParseNode ParseNode;\ntypedef struct _Program Program;\ntypedef struct _String String;\ntypedef struct _Number Number;\ntypedef struct _Reduce Reduce;\ntypedef struct _Regionview Regionview;\ntypedef struct _Rhs Rhs;\ntypedef struct _Rhsview Rhsview;\ntypedef struct _Row Row;\ntypedef struct _Rowview Rowview;\ntypedef struct _Statusview Statusview;\ntypedef struct _Plotstatus Plotstatus;\ntypedef struct _Plot Plot;\ntypedef struct _Plotwindow Plotwindow;\ntypedef struct _Plotpresent Plotpresent;\ntypedef struct _Plotmodel Plotmodel;\ntypedef struct _Graphwindow Graphwindow;\ntypedef struct _Subcolumn Subcolumn;\ntypedef struct _Subcolumnview Subcolumnview;\ntypedef struct _Symbol Symbol;\ntypedef struct _Tool Tool;\ntypedef struct _Toolkit Toolkit;\ntypedef struct _Toolkitgroup Toolkitgroup;\ntypedef struct _Toolkitgroupview Toolkitgroupview;\ntypedef struct _Toolkitview Toolkitview;\ntypedef struct _Toolview Toolview;\ntypedef struct _Trace Trace;\ntypedef struct _Preview Preview;\ntypedef struct _Infobar Infobar;\ntypedef struct _iError iError;\ntypedef struct _Log Log;\ntypedef struct _vObject vObject;\ntypedef struct _View View;\ntypedef struct _Workspace Workspace;\ntypedef struct _Workspaceview Workspaceview;\ntypedef struct _Workspaceroot Workspaceroot;\ntypedef struct _Workspacegroup Workspacegroup;\ntypedef struct _Workspacegroupview Workspacegroupview;\ntypedef struct _Prefworkspaceview Prefworkspaceview;\ntypedef struct _Prefcolumnview Prefcolumnview;\ntypedef struct _iText iText;\ntypedef struct _Expression Expression;\ntypedef struct _Mainw Mainw;\ntypedef struct _Toolviewitemgroup Toolviewitemgroup;\ntypedef struct _Panechild Panechild;\ntypedef struct _Toolkitbrowser Toolkitbrowser;\ntypedef struct _Workspacedefs Workspacedefs;\n\n/* container map function typedefs.\n */\ntypedef void *(*row_map_fn)( Row *, void *, void *, void * );\ntypedef void *(*symbol_map_fn)( Symbol *, void *, void *, void * );\ntypedef void *(*column_map_fn)( Column *, void * );\ntypedef void *(*view_map_fn)( View *, void *, void * );\ntypedef void *(*rowview_map_fn)( Rowview *, void * );\ntypedef void *(*workspace_map_fn)( Workspace *, void * );\ntypedef void *(*toolkit_map_fn)( Toolkit *, void *, void * );\ntypedef void *(*tool_map_fn)( Tool *, void *, void * );\n\n/* Util stuff.\n */\n#include \"util.h\"\n#include \"gtkutil.h\"\n#include \"path.h\"\n#include \"iobject.h\"\n#include \"icontainer.h\"\n#include \"iwindow.h\"\n#include \"idialog.h\"\n#include \"boxes.h\"\n#include \"popupbutton.h\"\n#include \"imageheader.h\"\n#include \"filesel.h\"\n#include \"managed.h\"\n#include \"managedfile.h\"\n#include \"managedgvalue.h\"\n#include \"managedgobject.h\"\n#include \"imageinfo.h\"\n#include \"imagedisplay.h\"\n#include \"colourdisplay.h\"\n#include \"imagemodel.h\"\n#include \"imagepresent.h\"\n#include \"floatwindow.h\"\n#include \"imageview.h\"\n#include \"tslider.h\"\n#include \"pane.h\"\n#include \"progress.h\"\n\n/* Basic ip includes (order important).\n */\n#include \"tree.h\"\n#include \"heap.h\"\n#include \"managedstring.h\"\n#include \"class.h\"\n#include \"link.h\"\n#include \"expr.h\"\n#include \"model.h\"\n#include \"paintboxview.h\"\n#include \"conversion.h\"\n#include \"heapmodel.h\"\n#include \"classmodel.h\"\n#include \"filemodel.h\"\n#include \"symbol.h\"\n#include \"workspace.h\"\n#include \"workspaceroot.h\"\n#include \"workspacegroup.h\"\n#include \"toolkitgroup.h\"\n#include \"secret.h\"\n#include \"action.h\"\n#include \"reduce.h\"\n#include \"vobject.h\"\n#include \"vipsobject.h\"\n#include \"view.h\"\n#include \"graphicview.h\"\n#include \"spin.h\"\n#include \"row.h\"\n#include \"rowview.h\"\n#include \"subcolumn.h\"\n#include \"subcolumnview.h\"\n#include \"rhs.h\"\n#include \"rhsview.h\"\n#include \"workspaceview.h\"\n#include \"workspacegroupview.h\"\n#include \"toolkitgroupview.h\"\n#include \"column.h\"\n#include \"columnview.h\"\n#include \"toolkit.h\"\n#include \"tool.h\"\n#include \"toolkitview.h\"\n#include \"toolview.h\"\n#include \"watch.h\"\n#include \"value.h\"\n#include \"panechild.h\"\n\n/* Per module includes, any order\n */\n#include \"workspacedefs.h\"\n#include \"toolkitbrowser.h\"\n#include \"defbrowser.h\"\n#include \"log.h\"\n#include \"error.h\"\n#include \"trace.h\"\n#include \"program.h\"\n#include \"conversionview.h\"\n#include \"statusview.h\"\n#include \"plotstatus.h\"\n#include \"mainw.h\"\n#include \"preview.h\"\n#include \"builtin.h\"\n#include \"compile.h\"\n#include \"dump.h\"\n#include \"main.h\"\n#include \"predicate.h\"\n#include \"slider.h\"\n#include \"clock.h\"\n#include \"pathname.h\"\n#include \"fontname.h\"\n#include \"group.h\"\n#include \"real.h\"\n#include \"vector.h\"\n#include \"colour.h\"\n#include \"number.h\"\n#include \"istring.h\"\n#include \"editview.h\"\n#include \"expression.h\"\n#include \"expressionview.h\"\n#include \"stringview.h\"\n#include \"numberview.h\"\n#include \"matrix.h\"\n#include \"matrixview.h\"\n#include \"plot.h\"\n#ifdef HAVE_LIBGOFFICE\n#include \"plotview.h\"\n#endif /*HAVE_LIBGOFFICE*/\n#include \"plotmodel.h\"\n#include \"plotpresent.h\"\n#include \"plotwindow.h\"\n#include \"graphwindow.h\"\n#include \"option.h\"\n#include \"optionview.h\"\n#include \"iimage.h\"\n#include \"iregion.h\"\n#include \"iregiongroup.h\"\n#include \"iarrow.h\"\n#include \"valueview.h\"\n#include \"sliderview.h\"\n#include \"pathnameview.h\"\n#include \"fontnameview.h\"\n#include \"colourview.h\"\n#include \"iimageview.h\"\n#include \"iregionview.h\"\n#include \"iregiongroupview.h\"\n#include \"prefs.h\"\n#include \"prefworkspaceview.h\"\n#include \"prefcolumnview.h\"\n#include \"regionview.h\"\n#include \"itext.h\"\n#include \"itextview.h\"\n#include \"toggle.h\"\n#include \"toggleview.h\"\n#include \"call.h\"\n#include \"cache.h\"\n#include \"parser.h\"\n\n#ifdef WITH_DMALLOC\n#include <dmalloc.h>\n#endif /*WITH_DMALLOC*/\n\n#endif /*IP_H*/\n"
  },
  {
    "path": "src/iregion.c",
    "content": "/* an ip region class object in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic iImageClass *parent_class = NULL;\n\nvoid\niregion_instance_destroy( iRegionInstance *instance )\n{\n\tinstance->image_class.type = ELEMENT_NOVAL;\n\tinstance->image_class.ele = (void *) 8;\n\tMANAGED_UNREF( instance->ii );\n\tinstance->classmodel = NULL;\n\tinstance->iregiongroup = NULL;\n\theap_unregister_element( reduce_context->heap, &instance->image_class );\n}\n\nvoid\niregion_instance_init( iRegionInstance *instance, Classmodel *classmodel )\n{\n\tinstance->image_class.type = ELEMENT_NOVAL;\n\tinstance->image_class.ele = (void *) 9;\n\tinstance->ii = NULL;\n\tinstance->area.left = 0;\n\tinstance->area.top = 0;\n\tinstance->area.width = 0;\n\tinstance->area.height = 0;\n\tinstance->classmodel = classmodel;\n\tinstance->iregiongroup = NULL;\n\n\theap_register_element( reduce_context->heap, &instance->image_class );\n}\n\ngboolean\niregion_instance_update( iRegionInstance *instance, PElement *root )\n{\n\tPElement image;\n\tPElement image_class;\n\tImageinfo *value;\n\tint left, top, width, height;\n\n\tif( !class_get_member_class( root, MEMBER_IMAGE, \"Image\", &image ) ||\n\t\t!class_get_member_image( &image, MEMBER_VALUE, &value ) ||\n\t\t!class_get_member_int( root, MEMBER_LEFT, &left ) ||\n\t\t!class_get_member_int( root, MEMBER_TOP, &top ) ||\n\t\t!class_get_member_int( root, MEMBER_WIDTH, &width ) ||\n\t\t!class_get_member_int( root, MEMBER_HEIGHT, &height ) )\n\t\treturn( FALSE );\n\n\tinstance->area.left = left;\n\tinstance->area.top = top;\n\tinstance->area.width = width;\n\tinstance->area.height = height;\n\n\tMANAGED_UNREF( instance->ii );\n\tinstance->ii = value;\n\tMANAGED_REF( value );\n\n\tPEPOINTE( &image_class, &instance->image_class );\n\tPEPUTPE( &image_class, &image );\n\n\treturn( TRUE );\n}\n\nstatic void\niregion_finalize( GObject *gobject )\n{\n\tiRegion *iregion;\n\n#ifdef DEBUG\n\tprintf( \"iregion_finalize\\n\" );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_IREGION( gobject ) );\n\n\tiregion = IREGION( gobject );\n\n\t/* My instance finalize stuff.\n\t */\n\tiregion_instance_destroy( &iregion->instance );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void *\niregion_generate_caption_sub( iImage *iimage, \n\tiRegion *iregion, gboolean *first )\n{\n\tiImage *our_iimage = IIMAGE( iregion );\n\tWorkspace *ws = HEAPMODEL( iregion )->row->ws;\n\tRow *row = HEAPMODEL( iimage )->row;\n\n\t/* Supress this name in the caption if it's a superclass. If this\n\t * thing is on a super, it's on the subclass too ... not helpful to\n\t * have it twice.\n\t */\n\tif( row->sym &&\n\t\t!is_super( row->sym ) ) {\n\t\tif( *first )\n\t\t\t*first = FALSE;\n\t\telse \n\t\t\tvips_buf_appends( &our_iimage->caption_buffer, \", \" );\n\n\t\trow_qualified_name_relative( ws->sym, \n\t\t\trow, &our_iimage->caption_buffer );\n\t}\n\n\treturn( NULL );\n}\n\nstatic const char *\niregion_generate_caption( iObject *iobject ) \n{\n\tiRegion *iregion = IREGION( iobject );\n\tiImage *iimage = IIMAGE( iregion );\n\tconst int nimages = g_slist_length( CLASSMODEL( iregion )->iimages );\n\tVipsBuf *buf = &iimage->caption_buffer;\n\tgboolean first;\n\n\tvips_buf_rewind( buf );\n\theapmodel_name( HEAPMODEL( iregion ), buf );\n\tvips_buf_appendf( buf, \" \" );\n\t/* Expands to (eg.) \"Region on A1 at (10, 10), size (50, 50)\"\n\t */\n\tvips_buf_appendf( buf, _( \"on\" ) );\n\tvips_buf_appendf( buf, \" \" );\n\tif( nimages > 1 )\n\t\tvips_buf_appendf( buf, \"[\" );\n\tfirst = TRUE;\n\tslist_map2( CLASSMODEL( iregion )->iimages,\n\t\t(SListMap2Fn) iregion_generate_caption_sub, iregion, &first );\n\tif( nimages > 1 )\n\t\tvips_buf_appendf( buf, \"]\" );\n\tvips_buf_appendf( buf, \" \" );\n\tvips_buf_appendf( buf, _( \"at (%d, %d), size (%d, %d)\" ),\n\t\tiregion->instance.area.left, iregion->instance.area.top,\n\t\tiregion->instance.area.width, iregion->instance.area.height );\n\n\treturn( vips_buf_all( buf ) );\n}\n\nstatic void\niregion_done_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys )\n{\n\tClassmodel *classmodel = CLASSMODEL( client );\n\tiRegionInstance *instance = classmodel_get_instance( classmodel );\n\tStringset *ss = STRINGSET( iwnd );\n\tRect area;\n\n\tStringsetChild *left = stringset_child_get( ss, _( \"Left\" ) );\n\tStringsetChild *top = stringset_child_get( ss, _( \"Top\" ) );\n\tStringsetChild *width = stringset_child_get( ss, _( \"Width\" ) );\n\tStringsetChild *height = stringset_child_get( ss, _( \"Height\" ) );\n\n\tif( !get_geditable_int( left->entry, &area.left ) ||\n\t\t!get_geditable_int( top->entry, &area.top ) ||\n\t\t!get_geditable_int( width->entry, &area.width ) ||\n\t\t!get_geditable_int( height->entry, &area.height ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tif( instance ) {\n\t\tinstance->area = area;\n\t\tclassmodel_update( classmodel );\n\t\tsymbol_recalculate_all();\n\t}\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic View *\niregion_view_new( Model *model, View *parent )\n{\n\treturn( iregionview_new() );\n}\n\n/* Pop up a iregion edit box. Shared with iarrow.c.\n */\nvoid \niregion_edit( GtkWidget *parent, Model *model )\n{\n\tClassmodel *classmodel = CLASSMODEL( model );\n\tiRegionInstance *instance = classmodel_get_instance( classmodel );\n\tGtkWidget *ss = stringset_new();\n\n\tif( instance ) {\n\t\tchar txt[256];\n\n\t\tim_snprintf( txt, 256, \"%d\", instance->area.left );\n\t\tstringset_child_new( STRINGSET( ss ), \n\t\t\t_( \"Left\" ), txt, _( \"Left edge of region\" ) );\n\t\tim_snprintf( txt, 256, \"%d\", instance->area.top );\n\t\tstringset_child_new( STRINGSET( ss ), \n\t\t\t_( \"Top\" ), txt, _( \"Top edge of region\" ) );\n\t\tim_snprintf( txt, 256, \"%d\", instance->area.width );\n\t\tstringset_child_new( STRINGSET( ss ), \n\t\t\t_( \"Width\" ), txt, _( \"Width of region\" ) );\n\t\tim_snprintf( txt, 256, \"%d\", instance->area.height );\n\t\tstringset_child_new( STRINGSET( ss ), \n\t\t\t_( \"Height\" ), txt, _( \"Height of region\" ) );\n\t}\n\n\tiwindow_set_title( IWINDOW( ss ), _( \"Edit %s %s\" ),\n\t\tIOBJECT_GET_CLASS_NAME( model ),\n\t\tIOBJECT( HEAPMODEL( model )->row )->name );\n\tidialog_set_callbacks( IDIALOG( ss ), \n\t\tiwindow_true_cb, NULL, NULL, classmodel );\n\tidialog_add_ok( IDIALOG( ss ), \n\t\tiregion_done_cb, _( \"Set %s\" ), \n\t\tIOBJECT_GET_CLASS_NAME( model ) );\n\tiwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( parent ) );\n\tidialog_set_iobject( IDIALOG( ss ), IOBJECT( model ) );\n\tidialog_set_pinup( IDIALOG( ss ), TRUE );\n\tiwindow_build( IWINDOW( ss ) );\n\n\tgtk_widget_show( ss );\n}\n\n/* Shared with iarrow.c.\n */\nvoid\niregion_parent_add( iContainer *child )\n{\n\tICONTAINER_CLASS( parent_class )->parent_add( child );\n\n\t/* Now we're all linked up, make a child model to handle client \n\t * displays on imageviews.\n\t */\n\t(void) iregiongroup_new( CLASSMODEL( child ) );\n}\n\n/* Shared with iarrow.c.\n */\nxmlNode *\niregion_save( Model *model, xmlNode *xnode )\n{\n\t/* Get our parent class. We can't just use the global parent_class, \n\t * since due to our lame MI scheme, this method may be called for \n\t * iarrow/ipoint etc. as well as iregion ... look up dynamically.\n\t */\n\tgpointer parent_class = PARENT_CLASS_DYNAMIC( model );\n\n\tiRegionInstance *instance = \n\t\tclassmodel_get_instance( CLASSMODEL( model ) );\n\n\txmlNode *xthis;\n\n\tif( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )\n\t\treturn( NULL );\n\n\tif( instance && CLASSMODEL( model )->edited ) {\n\t\tRect *area = &instance->area;\n\n\t\tif( !set_iprop( xthis, \"left\", area->left ) ||\n\t\t\t!set_iprop( xthis, \"top\", area->top ) ||\n\t\t\t!set_iprop( xthis, \"width\", area->width ) ||\n\t\t\t!set_iprop( xthis, \"height\", area->height ) )\n\t\t\treturn( NULL );\n\t}\n\n\treturn( xthis );\n}\n\n/* Shared with iarrow.c.\n */\ngboolean\niregion_load( Model *model, \n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\tgpointer parent_class = PARENT_CLASS_DYNAMIC( model );\n\tiRegionInstance *instance = \n\t\tclassmodel_get_instance( CLASSMODEL( model ) );\n\n\tg_assert( IS_RHS( parent ) );\n\n\tif( instance ) {\n\t\tRect *area = &instance->area;\n\n\t\tif( get_iprop( xnode, \"left\", &area->left ) &&\n\t\t\tget_iprop( xnode, \"top\", &area->top ) &&\n\t\t\tget_iprop( xnode, \"width\", &area->width ) &&\n\t\t\tget_iprop( xnode, \"height\", &area->height ) )\n\t\t\tclassmodel_set_edited( CLASSMODEL( model ), TRUE );\n\t}\n\n\treturn( MODEL_CLASS( parent_class )->load( model, \n\t\tstate, parent, xnode ) );\n}\n\n/* Need to implement _update_heap(), as not all model fields are directly\n * editable ... some are set only from expr. See also iimage.c. Shared with\n * iarrow.c.\n */\nvoid *\niregion_update_heap( Heapmodel *heapmodel )\n{\n\tgpointer parent_class = PARENT_CLASS_DYNAMIC( heapmodel );\n\tiRegionInstance *instance = \n\t\tclassmodel_get_instance( CLASSMODEL( heapmodel ) );\n\tExpr *expr = heapmodel->row->expr;\n\n\tRect area;\n\tPElement pe;\n\n\tif( instance ) {\n\t\t/* Save any model fields that may have been set by _load() and \n\t\t * which might be zapped by _get_instance().\n\t\t */\n\t\tarea = instance->area;\n\n\t\t/* Look for the base instance and update from that.\n\t\t */\n\t\tif( !class_get_exact( &expr->root, \n\t\t\tIOBJECT( heapmodel )->name, &pe ) )\n\t\t\treturn( FALSE );\n\t\tif( !iregion_instance_update( instance, &pe ) )\n\t\t\treturn( heapmodel );\n\n\t\t/* Restore model fields from _load().\n\t\t */\n\t\tinstance->area = area;\n\t}\n\n\t/* Classmodel _update_heap() will do _instance_new() from the fixed up\n\t * model.\n\t */\n\treturn( HEAPMODEL_CLASS( parent_class )->update_heap( heapmodel ) );\n}\n\nstatic void *\niregion_update_model( Heapmodel *heapmodel )\n{\n\tiRegion *iregion = IREGION( heapmodel );\n\n\tif( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) )\n\t\treturn( heapmodel );\n\n\t/* Update who-has-displays-on-what stuff.\n\t */\n\tclassmodel_iimage_update( CLASSMODEL( iregion ), iregion->instance.ii );\n\n\t/* Make sure the caption is regenerated.\n\t */\n\tiobject_changed( IOBJECT( heapmodel ) );\n\n\treturn( NULL );\n}\n\n/* Update iRegion from heap. Shared with iarrow.c.\n */\ngboolean\niregion_class_get( Classmodel *classmodel, PElement *root )\n{\n\tgpointer parent_class = PARENT_CLASS_DYNAMIC( classmodel );\n\tiRegionInstance *instance = classmodel_get_instance( classmodel );\n\n#ifdef DEBUG\n\tprintf( \"iregion_class_get: \" );\n\trow_name_print( HEAPMODEL( classmodel )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( instance && !iregion_instance_update( instance, root ) )\n\t\treturn( FALSE );\n\n\treturn( CLASSMODEL_CLASS( parent_class )->class_get( \n\t\tclassmodel, root ) );\n}\n\n/* Make a new \"fn value\" application. Shared with iarrow.c.\n */\ngboolean\niregion_class_new( Classmodel *classmodel, PElement *fn, PElement *out )\n{\n\tHeap *heap = reduce_context->heap;\n\tiRegionInstance *instance = classmodel_get_instance( classmodel );\n\n\tPElement rhs;\n\n#ifdef DEBUG\n\tprintf( \"iregion_class_new\\n\" );\n#endif /*DEBUG*/\n\n\t/* Make application nodes.\n\t */\n\tif( instance ) {\n\t\theap_appl_init( out, fn );\n\t\tif( !heap_appl_add( heap, out, &rhs ) ||\n\t\t\t!heap_element_new( heap, \n\t\t\t\t&instance->image_class, &rhs ) ||\n\t\t\t!heap_appl_add( heap, out, &rhs ) ||\n\t\t\t!heap_real_new( heap, instance->area.left, &rhs ) ||\n\t\t\t!heap_appl_add( heap, out, &rhs ) ||\n\t\t\t!heap_real_new( heap, instance->area.top, &rhs ) ||\n\t\t\t!heap_appl_add( heap, out, &rhs ) ||\n\t\t\t!heap_real_new( heap, instance->area.width, &rhs ) ||\n\t\t\t!heap_appl_add( heap, out, &rhs ) ||\n\t\t\t!heap_real_new( heap, instance->area.height, &rhs ) )\n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic void *\niregion_get_instance( Classmodel *classmodel )\n{\n\tiRegion *iregion = IREGION( classmodel );\n\n\treturn( &iregion->instance );\n}\n\nstatic void\niregion_class_init( iRegionClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tiContainerClass *icontainer_class = (iContainerClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tHeapmodelClass *heapmodel_class = (HeapmodelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->finalize = iregion_finalize;\n\n\tiobject_class->user_name = _( \"Region\" );\n\tiobject_class->generate_caption = iregion_generate_caption;\n\n\ticontainer_class->parent_add = iregion_parent_add;\n\n\tmodel_class->view_new = iregion_view_new;\n\tmodel_class->edit = iregion_edit;\n\tmodel_class->save = iregion_save;\n\tmodel_class->load = iregion_load;\n\n\theapmodel_class->update_heap = iregion_update_heap;\n\theapmodel_class->update_model = iregion_update_model;\n\n\tclassmodel_class->class_get = iregion_class_get;\n\tclassmodel_class->class_new = iregion_class_new;\n\tclassmodel_class->get_instance = iregion_get_instance;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\niregion_init( iRegion *iregion )\n{\n\tiregion_instance_init( &iregion->instance, CLASSMODEL( iregion ) );\n\n\tiobject_set( IOBJECT( iregion ), CLASS_REGION, NULL );\n}\n\nGType\niregion_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( iRegionClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) iregion_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( iRegion ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) iregion_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_IIMAGE, \n\t\t\t\"iRegion\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/iregion.h",
    "content": "/* a ip region class in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_IREGION (iregion_get_type())\n#define IREGION( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IREGION, iRegion ))\n#define IREGION_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_IREGION, iRegionClass))\n#define IS_IREGION( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IREGION ))\n#define IS_IREGION_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IREGION ))\n#define IREGION_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_IREGION, iRegionClass ))\n\n/* Handy for indexing arrays.\n */\ntypedef enum iRegionType {\n\tIREGION_MARK = 0,\n\tIREGION_HGUIDE,\n\tIREGION_VGUIDE,\n\tIREGION_ARROW,\n\tIREGION_REGION,\n\tIREGION_AREA\n} iRegionType;\n\n/* Our instance vars ... packaged up for code sharing.\n */\ntypedef struct {\n\t/* Stuff from the heap.\n\t */\n\tElement image_class;\t\t/* Child image class */\n\tImageinfo *ii;\n\tRect area;\n\n\t/* Client display stuff.\n\t */\n\tClassmodel *classmodel;\n\tiRegiongroup *iregiongroup;\n} iRegionInstance;\n\nstruct _iRegion {\n\tiImage parent_class;\n\n\t/* Class fields shared with iarrow.c.\n\t */\n\tiRegionInstance instance;\n};\n\ntypedef struct _iRegionClass {\n\tiImageClass parent_class;\n\n\t/* My methods.\n\t */\n} iRegionClass;\n\nvoid iregion_instance_destroy( iRegionInstance *instance );\nvoid iregion_instance_init( iRegionInstance *instance, Classmodel *classmodel );\ngboolean iregion_instance_update( iRegionInstance *instance, PElement *root );\n\nvoid iregion_edit( GtkWidget *parent, Model *model );\nvoid iregion_parent_add( iContainer *child );\nxmlNode *iregion_save( Model *model, xmlNode *xnode );\ngboolean iregion_load( Model *model, \n\tModelLoadState *state, Model *parent, xmlNode *xnode );\n\nvoid *iregion_update_heap( Heapmodel *heapmodel );\n\ngboolean iregion_class_get( Classmodel *classmodel, PElement *root );\ngboolean iregion_class_new( Classmodel *classmodel, \n\tPElement *fn, PElement *out );\n\nGType iregion_get_type( void );\n"
  },
  {
    "path": "src/iregiongroup.c",
    "content": "/* base model for a client regions on an imageview\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic void *\niregiongroup_update_model( Heapmodel *heapmodel )\n{\n#ifdef DEBUG\n\tprintf( \"iregiongroup_update_model: \" );\n\trow_name_print( heapmodel->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) )\n\t\treturn( heapmodel );\n\n\t/* Only display most-derived classes. Don't display \"this\".\n\t */\n\tif( heapmodel->row->sym )\n\t\tmodel_display( MODEL( heapmodel ),\n\t\t\t!is_super( heapmodel->row->sym ) &&\n\t\t\t!is_this( heapmodel->row->sym ) );\n\n\treturn( NULL );\n}\n\nstatic View *\niregiongroup_view_new( Model *model, View *parent )\n{\n\treturn( iregiongroupview_new() );\n}\n\nstatic void\niregiongroup_class_init( iRegiongroupClass *class )\n{\n\tModelClass *model_class = (ModelClass *) class;\n\tHeapmodelClass *heapmodel_class = (HeapmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\theapmodel_class->update_model = iregiongroup_update_model;\n\n\tmodel_class->view_new = iregiongroup_view_new;\n}\n\nstatic void\niregiongroup_init( iRegiongroup *iregiongroup )\n{\n\t/* Display turned on in _update_model() above.\n\t */\n\tMODEL( iregiongroup )->display = FALSE;\n}\n\nGType\niregiongroup_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( iRegiongroupClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) iregiongroup_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( iRegiongroup ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) iregiongroup_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"iRegiongroup\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\niRegiongroup *\niregiongroup_new( Classmodel *classmodel )\n{\n\tiRegiongroup *iregiongroup;\n\n\tiregiongroup = IREGIONGROUP( g_object_new( TYPE_IREGIONGROUP, NULL ) );\n\n\ticontainer_child_add( ICONTAINER( classmodel ), \n\t\tICONTAINER( iregiongroup ), -1 );\n\n#ifdef DEBUG\n\tprintf( \"iregiongroup_new: \" );\n\trow_name_print( HEAPMODEL( classmodel )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\treturn( iregiongroup );\n}\n"
  },
  {
    "path": "src/iregiongroup.h",
    "content": "/* base model for a client regions on an imageview\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_IREGIONGROUP (iregiongroup_get_type())\n#define IREGIONGROUP( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_IREGIONGROUP, iRegiongroup ))\n#define IREGIONGROUP_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_IREGIONGROUP, iRegiongroupClass))\n#define IS_IREGIONGROUP( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_IREGIONGROUP ))\n#define IS_IREGIONGROUP_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_IREGIONGROUP ))\n#define IREGIONGROUP_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), \\\n\t\tTYPE_IREGIONGROUP, iRegiongroupClass ))\n\nstruct _iRegiongroup {\n\tClassmodel parent_class;\n\n};\n\ntypedef struct _iRegiongroupClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} iRegiongroupClass;\n\nGType iregiongroup_get_type( void );\niRegiongroup *iregiongroup_new( Classmodel *classmodel );\n"
  },
  {
    "path": "src/iregiongroupview.c",
    "content": "/* coordinate the display of regionviews on imageviews\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\nstatic iRegiongroup *\niregiongroupview_get_iregiongroup( iRegiongroupview *iregiongroupview )\n{\n\treturn( IREGIONGROUP( VOBJECT( iregiongroupview )->iobject ) ); \n}\n\nstatic Classmodel *\niregiongroupview_get_classmodel( iRegiongroupview *iregiongroupview )\n{\n\tiRegiongroup *iregiongroup;\n\n\tif( (iregiongroup = \n\t\tiregiongroupview_get_iregiongroup( iregiongroupview )) )\n\t\treturn( CLASSMODEL( ICONTAINER( iregiongroup )->parent ) );\n\n\treturn( NULL );\n}\n\nstatic void\niregiongroupview_destroy( GtkObject *object )\n{\n\tiRegiongroupview *iregiongroupview;\n\n#ifdef DEBUG\n\tprintf( \"iregiongroupview_destroy: %p\\n\", object );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_IREGIONGROUPVIEW( object ) );\n\n\tiregiongroupview = IREGIONGROUPVIEW( object );\n\n\t/* Destroy all regionviews we manage.\n\t */\n\tslist_map( iregiongroupview->classmodel->views, \n\t\t(SListMapFn) object_destroy, NULL );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\n/* What we track during a refresh.\n */\ntypedef struct {\n\tGSList *notused;\n\tiRegiongroupview *iregiongroupview;\n\tClassmodel *classmodel;\n\tiImage *iimage;\n\tImagepresent *ip;\n} iRegiongroupviewRefreshState;\n\nstatic Regionview *\niregiongroupview_refresh_imageview_test( Regionview *regionview,\n\tiRegiongroupviewRefreshState *irs )\n{\n\tif( regionview->classmodel == irs->classmodel && \n\t\tregionview->ip == irs->ip )\n\t\treturn( regionview );\n\n\treturn( NULL );\n}\n\nstatic void *\niregiongroupview_refresh_imageview( Imagepresent *ip, \n\tiRegiongroupviewRefreshState *irs )\n{\n\tRegionview *regionview;\n\n\tirs->ip = ip;\n\n\t/* Do we have a Regionview for this iv already?\n\t */\n\tif( (regionview = slist_map( irs->notused,\n\t\t(SListMapFn) iregiongroupview_refresh_imageview_test, irs )) ) {\n\t\t/* Yes ... reuse.\n\t\t */\n\t\tirs->notused = g_slist_remove( irs->notused, regionview );\n\t}\n\telse {\n\t\t/* Nope ... make a new one.\n\t\t */\n\t\tiRegionInstance *instance = \n\t\t\tclassmodel_get_instance( irs->classmodel );\n\t\tPElement *root = &HEAPMODEL( irs->classmodel )->row->expr->root;\n\n\t\tif( instance ) {\n\t\t\tRegionview *regionview = regionview_new( \n\t\t\t\tirs->classmodel, &instance->area, ip );\n\n#ifdef DEBUG\n\t\t\tprintf( \"iregiongroupview_refresh_imageview: \"\n\t\t\t\t\"creating new regionview\\n\" );\n#endif /*DEBUG*/\n\n\t\t\t/* Set the display type from the heap class name.\n\t\t\t */\n\t\t\tregionview_set_type( regionview, root );\n\t\t}\n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\niregiongroupview_refresh_iimage( iImage *iimage, \n\tiRegiongroupviewRefreshState *irs )\n{\n\tirs->iimage = iimage;\n\tslist_map( iimage->views,\n\t\t(SListMapFn) iregiongroupview_refresh_imageview, irs );\n\n\treturn( NULL );\n}\n\nstatic void \niregiongroupview_refresh( vObject *vobject )\n{\n\tiRegiongroupview *iregiongroupview = IREGIONGROUPVIEW( vobject );\n\n\tiRegiongroupviewRefreshState irs;\n\n#ifdef DEBUG\n\tprintf( \"iregiongroupview_refresh\\n\" );\n\tprintf( \"watching model %s %s\\n\", \n\t\tG_OBJECT_TYPE_NAME( vobject->iobject ), \n\t\tNN( IOBJECT( vobject->iobject )->name ) );\n#endif /*DEBUG*/\n\n\tiregiongroupview->classmodel = \n\t\tiregiongroupview_get_classmodel( iregiongroupview );\n\n\tif( iregiongroupview->classmodel ) { \n\t\t/* Make a note of all the displays we have now, loop over the \n\t\t * displays we should have, reusing when possible ... remove \n\t\t * any unused displays at the end.\n\t\t */\n\t\tirs.classmodel = iregiongroupview->classmodel;\n\t\tirs.notused = g_slist_copy( irs.classmodel->views );\n\t\tirs.iregiongroupview = iregiongroupview;\n\n\t\tslist_map( irs.classmodel->iimages,\n\t\t\t(SListMapFn) iregiongroupview_refresh_iimage, &irs );\n\n\t\t/* Remove all the regionviews we've not used. \n\t\t */\n\t\tslist_map( irs.notused, (SListMapFn) object_destroy, NULL );\n\t\tIM_FREEF( g_slist_free, irs.notused );\n\t}\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\niregiongroupview_class_init( iRegiongroupviewClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = iregiongroupview_destroy;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = iregiongroupview_refresh;\n}\n\nstatic void\niregiongroupview_init( iRegiongroupview *iregiongroupview )\n{\n#ifdef DEBUG\n\tprintf( \"iregiongroupview_init\\n\" );\n#endif /*DEBUG*/\n}\n\nGtkType\niregiongroupview_get_type( void )\n{\n\tstatic GtkType iregiongroupview_type = 0;\n\n\tif( !iregiongroupview_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"iRegiongroupview\",\n\t\t\tsizeof( iRegiongroupview ),\n\t\t\tsizeof( iRegiongroupviewClass ),\n\t\t\t(GtkClassInitFunc) iregiongroupview_class_init,\n\t\t\t(GtkObjectInitFunc) iregiongroupview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tiregiongroupview_type = gtk_type_unique( TYPE_VIEW, &info );\n\t}\n\n\treturn( iregiongroupview_type );\n}\n\nView *\niregiongroupview_new( void )\n{\n\tiRegiongroupview *iregiongroupview = \n\t\tgtk_type_new( TYPE_IREGIONGROUPVIEW );\n\n#ifdef DEBUG\n\tprintf( \"iregiongroupview_new\\n\" );\n#endif /*DEBUG*/\n\n\treturn( VIEW( iregiongroupview ) );\n}\n"
  },
  {
    "path": "src/iregiongroupview.h",
    "content": "/* coordinate the display of regionviews on imageviews\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_IREGIONGROUPVIEW (iregiongroupview_get_type())\n#define IREGIONGROUPVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_IREGIONGROUPVIEW, iRegiongroupview ))\n#define IREGIONGROUPVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_IREGIONGROUPVIEW, \\\n\t\tiRegiongroupviewClass ))\n#define IS_IREGIONGROUPVIEW( obj ) \\\n\t(GTK_CHECK_TYPE( (obj), TYPE_IREGIONGROUPVIEW ))\n#define IS_IREGIONGROUPVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_IREGIONGROUPVIEW ))\n\ntypedef struct _iRegiongroupview {\n\tView parent_class;\n\n\t/* Keep our classmodel here, we need it during destroy.\n\t */\n\tClassmodel *classmodel;\n\n} iRegiongroupview;\n\ntypedef struct _iRegiongroupviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} iRegiongroupviewClass;\n\nGtkType iregiongroupview_get_type( void );\nView *iregiongroupview_new( void );\n"
  },
  {
    "path": "src/iregionview.c",
    "content": "/* display a region in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic iImageviewClass *parent_class = NULL;\n\nstatic void\niregionview_class_init( iRegionviewClass *class )\n{\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n}\n\nstatic void\niregionview_init( iRegionview *iregionview )\n{\n#ifdef DEBUG\n\tprintf( \"iregionview_init\\n\" );\n#endif /*DEBUG*/\n}\n\nGtkType\niregionview_get_type( void )\n{\n\tstatic GtkType iregionview_type = 0;\n\n\tif( !iregionview_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"iRegionview\",\n\t\t\tsizeof( iRegionview ),\n\t\t\tsizeof( iRegionviewClass ),\n\t\t\t(GtkClassInitFunc) iregionview_class_init,\n\t\t\t(GtkObjectInitFunc) iregionview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tiregionview_type = gtk_type_unique( TYPE_IIMAGEVIEW, &info );\n\t}\n\n\treturn( iregionview_type );\n}\n\nView *\niregionview_new( void )\n{\n\tiRegionview *iregionview = gtk_type_new( TYPE_IREGIONVIEW );\n\n#ifdef DEBUG\n\tprintf( \"iregionview_new\\n\" );\n#endif /*DEBUG*/\n\n\treturn( VIEW( iregionview ) );\n}\n"
  },
  {
    "path": "src/iregionview.h",
    "content": "/* display a region in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_IREGIONVIEW (iregionview_get_type())\n#define IREGIONVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_IREGIONVIEW, iRegionview ))\n#define IREGIONVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_IREGIONVIEW, iRegionviewClass ))\n#define IS_IREGIONVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IREGIONVIEW ))\n#define IS_IREGIONVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_IREGIONVIEW ))\n\ntypedef struct _iRegionview {\n\tiImageview parent_class;\n\n} iRegionview;\n\ntypedef struct _iRegionviewClass {\n\tiImageviewClass parent_class;\n\n\t/* My methods.\n\t */\n} iRegionviewClass;\n\nGtkType iregionview_get_type( void );\nView *iregionview_new( void );\n"
  },
  {
    "path": "src/istring.h",
    "content": "/* an editable string in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_STRING (string_get_type())\n#define STRING( obj ) (GTK_CHECK_CAST( (obj), TYPE_STRING, String ))\n#define STRING_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_STRING, StringClass ))\n#define IS_STRING( obj ) (GTK_CHECK_TYPE( (obj), TYPE_STRING ))\n#define IS_STRING_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_STRING ))\n\nstruct _String {\n\tClassmodel parent_class;\n\n\t/* Class fields.\n\t */\n\tchar *value;\n};\n\ntypedef struct _StringClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} StringClass;\n\nGType string_get_type( void );\n"
  },
  {
    "path": "src/itext.c",
    "content": "/* a text item in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic HeapmodelClass *parent_class = NULL;\n\nstatic void\nitext_finalize( GObject *gobject )\n{\n\tiText *itext;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_ITEXT( gobject ) );\n\n\titext = ITEXT( gobject );\n\n#ifdef DEBUG\n\tprintf( \"itext_destroy\\n\" );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\tIM_FREE( itext->formula );\n\tIM_FREE( itext->formula_default );\n\tvips_buf_destroy( &itext->value );\n\tvips_buf_destroy( &itext->decompile );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\nitext_info( iObject *iobject, VipsBuf *buf )\n{\n\tiText *itext = ITEXT( iobject );\n\n\tvips_buf_appends( buf, _( \"Formula\" ) );\n\tvips_buf_appendf( buf, \": %s\\n\", NN( itext->formula ) );\n}\n\n/* Fwd ref this.\n */\nstatic gboolean itext_add_element( VipsBuf *buf, \n\tPElement *base, gboolean top, gboolean bracket );\n\n/* Sub-fn of below, callback for list print. Eval and print the item into \n * the buffer, separating with commas as required. \n */\nstatic void *\nitext_add_list( PElement *base, VipsBuf *buf, gboolean *first )\n{\n\tReduce *rc = reduce_context;\n\n\tif( *first )\n\t\t*first = FALSE;\n\telse \n\t\tvips_buf_appends( buf, \", \" );\n\n\t/* Reduce the head, and print.\n\t */\n\tif( !reduce_pelement( rc, reduce_spine, base ) ) \n\t\treturn( base );\n\tif( !itext_add_element( buf, base, FALSE, FALSE ) )\n\t\treturn( base );\n\n\t/* Buffer full? Abort list print.\n\t */\n\tif( buf->full )\n\t\treturn( base );\n\n\treturn( NULL );\n}\n\n/* Sub-fn of below, callback for string print. Print the chars into the \n * buffer.\n */\nstatic void *\nitext_add_string( PElement *base, VipsBuf *buf )\n{\n\tReduce *rc = reduce_context;\n\n\t/* Reduce the head, and add the char.\n\t */\n\tif( !reduce_pelement( rc, reduce_spine, base ) ) \n\t\treturn( base );\n\tif( PEISCHAR( base ) )\n\t\t/* Don't escape chars in string mode.\n\t\t */\n\t\tvips_buf_appendf( buf, \"%c\", PEGETCHAR( base ) );\n\telse {\n\t\t/* Help! Fall back to ordinary item print.\n\t\t */\n\t\tvips_buf_appends( buf, \", \" );\n\t\tif( !itext_add_element( buf, base, FALSE, FALSE ) )\n\t\t\treturn( base );\n\t}\n\n\t/* Buffer full? Abort string print.\n\t */\n\tif( buf->full )\n\t\treturn( base );\n\n\treturn( NULL );\n}\n\n/* Print a char ... we need to escape \\n etc.\n */\nstatic void\nitext_add_char( int ch, VipsBuf *buf )\n{\n\tchar in[2];\n\tchar out[3];\n\n\tin[0] = ch;\n\tin[1] = '\\0';\n\tmy_strecpy( out, in, FALSE );\n\n\tvips_buf_appends( buf, out );\n}\n\n/* Print a complex. \n */\nstatic void\nitext_add_complex( double rp, double ip, VipsBuf *buf )\n{\n\tif( PRINT_CARTESIAN ) \n\t\tvips_buf_appendf( buf, \"(%.12g, %.12g)\", rp, ip );\n\telse {\n\t\tif( rp == 0 ) {\n\t\t\tif( ip == 0 ) \n\t\t\t\tvips_buf_appendf( buf, \"0\" );\n\t\t\telse \n\t\t\t\tvips_buf_appendf( buf, \"%.12gj\", ip );\n\t\t}\n\t\telse if( ip == 0 ) \n\t\t\tvips_buf_appendf( buf, \"%.12g\", rp );\n\t\telse\n\t\t\tvips_buf_appendf( buf, \"%.12g + %.12gj\", rp, ip );\n\n\t}\n}\n\n/* Try to decompile.\n */\nstatic gboolean\nitext_decompile_element( VipsBuf *buf, PElement *base, gboolean top )\n{\n\tReduce *rc = reduce_context;\n\tgboolean result;\n\n\t/* Set the value label for a tally entry.\n\t */\n\tif( PEISNOVAL( base ) ) \n\t\tvips_buf_appends( buf, _( \"no value\" ) );\n\telse if( PEISREAL( base ) ) \n\t\tvips_buf_appendf( buf, \"%g\", PEGETREAL( base ) );\n\telse if( PEISBOOL( base ) ) \n\t\tvips_buf_appends( buf, bool_to_char( PEGETBOOL( base ) ) );\n\telse if( PEISCHAR( base ) ) {\n\t\tvips_buf_appends( buf, \"'\" );\n\t\titext_add_char( (int) PEGETCHAR( base ), buf );\n\t\tvips_buf_appends( buf, \"'\" );\n\t}\n\telse if( PEISCOMPLEX( base ) ) \n\t\titext_add_complex( PEGETREALPART( base ), PEGETIMAGPART( base ),\n\t\t\tbuf );\n\telse if( PEISMANAGEDSTRING( base ) ) {\n\t\tManagedstring *managedstring = PEGETMANAGEDSTRING( base );\n\n\t\tvips_buf_appendf( buf, \"\\\"%s\\\"\", managedstring->string );\n\t}\n\telse if( PEISELIST( base ) ) {\n\t\tvips_buf_appends( buf, \"[ ]\" );\n\t}\n\telse if( !heap_is_string( base, &result ) ) \n\t\t/* Eval error.\n\t\t */\n\t\treturn( FALSE );\n\telse if( result ) {\n\t\tvips_buf_appends( buf, \"\\\"\" );\n\t\tif( heap_map_list( base,\n\t\t\t(heap_map_list_fn) itext_add_string, buf, NULL ) )\n\t\t\treturn( FALSE );\n\t\tvips_buf_appends( buf, \"\\\"\" );\n\t}\n\telse if( PEISLIST( base ) ) {\n\t\tgboolean first = TRUE;\n\n\t\tvips_buf_appends( buf, \"[\" );\n\t\tif( heap_map_list( base,\n\t\t\t(heap_map_list_fn) itext_add_list, buf, &first ) )\n\t\t\treturn( FALSE );\n\t\tvips_buf_appends( buf, \"]\" );\n\t}\n\telse if( PEISIMAGE( base ) ) {\n\t\tImageinfo *ii = PEGETII( base );\n\n\t\tif( !top )\n\t\t\tvips_buf_appends( buf, \"(\" );\n\n\t\tif( ii && IOBJECT( ii )->name ) \n\t\t\tvips_buf_appendf( buf, \"vips_image \\\"%s\\\"\", \n\t\t\t\tIOBJECT( ii )->name );\n\t\telse \n\t\t\tvips_buf_appendf( buf, \"vips_image <unknown>\" );\n\n\t\tif( !top )\n\t\t\tvips_buf_appends( buf, \")\" );\n\t}\n\telse if( PEISMANAGED( base ) ) {\n\t\tManaged *managed;\n\n\t\tif( !(managed = PEGETMANAGED( base )) ) \n\t\t\tvips_buf_appendf( buf, \"<NULL managed>\" );  \n\t\telse { \n\t\t\tvips_buf_appendf( buf, \"<%s \", \n\t\t\t\tG_OBJECT_TYPE_NAME( managed ) );\n\t\t\tiobject_info( IOBJECT( managed ), buf );\n\t\t\tvips_buf_appends( buf, \">\" );\n\t\t}\n\t}\n\telse if( PEISCLASS( base ) ) {\n\t\tCompile *compile = PEGETCLASSCOMPILE( base );\n\t\tPElement params;\n\t\tint i;\n\n\t\tif( !top )\n\t\t\tvips_buf_appends( buf, \"(\" );\n\n\t\tsymbol_qualified_name( compile->sym, buf );\n\n\t\t/* Skip over the secrets, then decompile all the args.\n\t\t */\n\t\tPEGETCLASSSECRET( &params, base );\n\t\tfor( i = 0; i < compile->nsecret; i++ ) {\n\t\t\tHeapNode *hn = PEGETVAL( &params );\n\n\t\t\tPEPOINTRIGHT( hn, &params );\n\t\t}\n\n\t\tfor( i = 0; i < compile->nparam; i++ ) {\n\t\t\tHeapNode *hn = PEGETVAL( &params );\n\t\t\tHeapNode *sv = GETLEFT( hn );\n\t\t\tPElement value;\n\n\t\t\tPEPOINTRIGHT( sv, &value );\n\t\t\tvips_buf_appends( buf, \" \" );\n\t\t\tif( !itext_decompile_element( buf, &value, FALSE ) )\n\t\t\t\treturn( FALSE );\n\n\t\t\tPEPOINTRIGHT( hn, &params );\n\t\t}\n\n\t\tif( !top )\n\t\t\tvips_buf_appends( buf, \")\" );\n\n\t}\n\telse if( PEISSYMREF( base ) ) \n\t\tvips_buf_appends( buf, IOBJECT( PEGETSYMREF( base ) )->name );\n\telse if( PEISTAG( base ) ) \n\t\tvips_buf_appends( buf, PEGETTAG( base ) );\n\telse \n\t\tgraph_pelement( rc->heap, buf, base, TRACE_FUNCTIONS );\n\n\treturn( TRUE );\n}\n\n/* Little wrapper ... used for formatting error messages, etc. FALSE for eval\n * error.\n */\nstatic gboolean \nitext_decompile( Reduce *rc, VipsBuf *buf, PElement *root )\n{\n\t/* Evaluate and print off values.\n\t */\n\tif( !reduce_pelement( rc, reduce_spine, root ) ) \n\t\treturn( FALSE );\n\n\tif( !itext_decompile_element( buf, root, TRUE ) && !buf->full ) \n\t\t/* Tally eval failed, and buffer is not full ... must\n\t\t * have been an eval error.\n\t\t */\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Print function for computed values. top is TRUE only for the very top level\n * output. bracket means we should bracket compound expressions.\n */\nstatic gboolean\nitext_add_element( VipsBuf *buf, PElement *base, \n\tgboolean top, gboolean bracket )\n{\n\tgboolean result;\n\n\t/* Set the value label for a tally entry.\n\t */\n\tif( PEISNOVAL( base ) ) \n\t\tvips_buf_appends( buf, _( \"no value\" ) );\n\telse if( PEISREAL( base ) ) \n\t\tvips_buf_appendf( buf, \"%.7g\", PEGETREAL( base ) );\n\telse if( PEISBOOL( base ) ) \n\t\tvips_buf_appends( buf, bool_to_char( PEGETBOOL( base ) ) );\n\telse if( PEISCHAR( base ) ) {\n\t\tvips_buf_appends( buf, \"'\" );\n\t\titext_add_char( (int) PEGETCHAR( base ), buf );\n\t\tvips_buf_appends( buf, \"'\" );\n\t}\n\telse if( PEISCOMPLEX( base ) ) {\n\t\titext_add_complex( PEGETREALPART( base ), PEGETIMAGPART( base ),\n\t\t\tbuf );\n\t}\n\telse if( PEISMANAGEDSTRING( base ) ) {\n\t\tManagedstring *managedstring = PEGETMANAGEDSTRING( base );\n\n\t\tif( !top ) \n\t\t\tvips_buf_appends( buf, \"\\\"\" );\n\t\tvips_buf_appends( buf, managedstring->string );\n\t\tif( !top ) \n\t\t\tvips_buf_appends( buf, \"\\\"\" );\n\t}\n\telse if( PEISELIST( base ) ) {\n\t\tvips_buf_appends( buf, \"[ ]\" );\n\t}\n\telse if( !heap_is_string( base, &result ) ) \n\t\t/* Eval error.\n\t\t */\n\t\treturn( FALSE );\n\telse if( result ) {\n\t\t/* Only generate quotes for non-top-level string objects.\n\t\t */\n\t\tif( !top ) \n\t\t\tvips_buf_appends( buf, \"\\\"\" );\n\n\t\t/* Print string contents.\n\t\t */\n\t\tif( heap_map_list( base,\n\t\t\t(heap_map_list_fn) itext_add_string, buf, NULL ) )\n\t\t\treturn( FALSE );\n\n\t\tif( !top ) \n\t\t\tvips_buf_appends( buf, \"\\\"\" );\n\t}\n\telse if( PEISLIST( base ) ) {\n\t\tgboolean first = TRUE;\n\n\t\tvips_buf_appends( buf, \"[\" );\n\t\tif( heap_map_list( base,\n\t\t\t(heap_map_list_fn) itext_add_list, buf, &first ) )\n\t\t\treturn( FALSE );\n\t\tvips_buf_appends( buf, \"]\" );\n\t}\n\telse if( PEISIMAGE( base ) ) {\n\t\tvips_buf_appendf( buf, \"<\" );\n\t\tvips_buf_appendi( buf, imageinfo_get( FALSE, PEGETII( base ) ) );\n\t\tvips_buf_appendf( buf, \">\" );\n\t}\n\telse if( PEISMANAGED( base ) ) {\n\t\tManaged *managed = PEGETMANAGED( base );\n\n\t\tvips_buf_appends( buf, \"<\" );\n\t\tiobject_info( IOBJECT( managed ), buf );\n\t\tvips_buf_appends( buf, \">\" );\n\t}\n\telse if( PEISCLASS( base ) ) {\n\t\tCompile *compile = PEGETCLASSCOMPILE( base );\n\t\tPElement params;\n\t\tint i;\n\n\t\tif( bracket && compile->nparam )\n\t\t\tvips_buf_appends( buf, \"(\" );\n\n\t\t/* Name.\n\t\t */\n\t\tsymbol_qualified_name( compile->sym, buf );\n\n\t\t/* Skip over the secrets, then value-ize all the args.\n\t\t */\n\t\tPEGETCLASSSECRET( &params, base );\n\t\tfor( i = 0; i < compile->nsecret; i++ ) {\n\t\t\tHeapNode *hn = PEGETVAL( &params );\n\n\t\t\tPEPOINTRIGHT( hn, &params );\n\t\t}\n\n\t\tfor( i = 0; i < compile->nparam; i++ ) {\n\t\t\tHeapNode *hn = PEGETVAL( &params );\n\t\t\tHeapNode *sv = GETLEFT( hn );\n\t\t\tPElement value;\n\n\t\t\tPEPOINTRIGHT( sv, &value );\n\t\t\tvips_buf_appends( buf, \" \" );\n\t\t\tif( !itext_add_element( buf, &value, FALSE, TRUE ) )\n\t\t\t\treturn( FALSE );\n\n\t\t\tPEPOINTRIGHT( hn, &params );\n\t\t}\n\n\t\tif( bracket && compile->nparam )\n\t\t\tvips_buf_appends( buf, \")\" );\n\t}\n\telse if( PEISSYMREF( base ) ) {\n\t\tSymbol *sym = PEGETSYMREF( base );\n\n\t\tif( is_scope( sym ) ) {\n\t\t\tvips_buf_appendf( buf, \"<scope '\" );\n\t\t\tsymbol_qualified_name( sym, buf );\n\t\t\tvips_buf_appendf( buf, \"'>\" ); \n\t\t}\n\t\telse {\n\t\t\tvips_buf_appendf( buf, \"<reference to symbol '\" ), \n\t\t\tsymbol_qualified_name( sym, buf );\n\t\t\tvips_buf_appendf( buf, \"'>\" ); \n\t\t}\n\t}\n\telse if( PEISTAG( base ) ) \n\t\tvips_buf_appendf( buf, \".%s\", PEGETTAG( base ) );\n\telse {\n\t\tvips_buf_appendf( buf, \"<\" ); \n\t\tvips_buf_appends( buf, _( \"function\" ) );\n\t\tvips_buf_appendf( buf, \">\" ); \n\t}\n\n\treturn( TRUE );\n}\n\n/* Little wrapper ... used for formatting error messages, etc. FALSE for eval\n * error.\n */\ngboolean \nitext_value( Reduce *rc, VipsBuf *buf, PElement *root )\n{\n\t/* Evaluate and print off values.\n\t */\n\tif( !reduce_pelement( rc, reduce_spine, root ) ) \n\t\treturn( FALSE );\n\n\tif( !itext_add_element( buf, root, TRUE, FALSE ) && !buf->full ) \n\t\t/* Tally eval failed, and buffer is not full ... must\n\t\t * have been an eval error.\n\t\t */\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Same, but everror on eval fail.\n */\nvoid\nitext_value_ev( Reduce *rc, VipsBuf *buf, PElement *root )\n{\n\tif( !itext_value( rc, buf, root ) )\n\t\treduce_throw( rc );\n}\n\n/* Decompile an Expr.\n */\nstatic gboolean\nitext_make_decompiled_string( Expr *expr, VipsBuf *buf )\n{\n\t/* Old error on this expression?\n\t */\n\tif( expr->err ) {\n\t\texpr_error_get( expr );\n\t\treturn( FALSE );\n\t}\n\n\t/* Dirty? We can't print dirty values, since we might have pointers \n\t * to deleted symbols in the heap (if we are dirty because one of our \n\t * parents has been deleted).\n\n\t \tFIXME ... this seem a bit restrictive :-( ... could just\n\t\tblock reads of symbol pointers instead?\n\n\t */\n\tif( expr->sym->dirty ) {\n\t\tvips_buf_appendf( buf, _( \"Dirty value\" ) );\n\t\treturn( TRUE );\n\t}\n\n\t/* Evaluate and print off values.\n\t */\n\tif( !itext_decompile( reduce_context, buf, &expr->root ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Make a value string from an Expr.\n */\ngboolean\nitext_make_value_string( Expr *expr, VipsBuf *buf )\n{\n\t/* Old error on this expression?\n\t */\n\tif( expr->err ) {\n\t\texpr_error_get( expr );\n\t\treturn( FALSE );\n\t}\n\n\t/* Dirty? We can't print dirty values, since we might have pointers \n\t * to deleted symbols in the heap (if we are dirty because one of our \n\t * parents has been deleted).\n\n\t \tFIXME ... this seem a bit restrictive :-( ... could just\n\t\tblock reads of symbol pointers instead?\n\n\t */\n\tif( expr->sym->dirty ) {\n\t\tvips_buf_appendf( buf, _( \"Dirty value\" ) );\n\t\treturn( TRUE );\n\t}\n\n\t/* Evaluate and print off values.\n\t */\n\tif( !itext_value( reduce_context, buf, &expr->root ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic void *\nitext_update_model( Heapmodel *heapmodel )\n{\n\tiText *itext = ITEXT( heapmodel );\n        Row *row = HEAPMODEL( itext )->row;\n\tExpr *expr = row->expr;\n\n#ifdef DEBUG\n\tprintf( \"itext_update_model: \" );\n\trow_name_print( row );\n\tif( row->sym && \n\t\trow->sym->dirty )\n\t\tprintf( \" (dirty)\" );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tvips_buf_set_dynamic( &itext->value, LINELENGTH );\n\tvips_buf_set_dynamic( &itext->decompile, LINELENGTH );\n\tif( expr ) {\n\t\tif( !itext_make_value_string( expr, &itext->value ) ||\n\t\t\t!itext_make_decompiled_string( expr, \n\t\t\t\t&itext->decompile ) ) \n\t\t\texpr_error_set( expr );\n\t}\n\n#ifdef DEBUG\n\tprintf( \"itext_update_model: \" );\n\trow_name_print( row );\n\tprintf( \" has value: %s\\n\", vips_buf_all( &itext->value ) );\n#endif /*DEBUG*/\n\n\t/* If this is a non-edited row, update the source.\n\t */\n\tif( !itext->edited || row == row->top_row ) {\n\t\tconst char *new_formula;\n\n\t\tif( expr && expr->compile && expr->compile->rhstext ) \n\t\t\tnew_formula = expr->compile->rhstext;\n\t\telse \n\t\t\tnew_formula = vips_buf_all( &itext->decompile );\n\n\t\tIM_SETSTR( itext->formula_default, new_formula );\n\n\t\t/* Don't use itext_set_formula(), as we don't want to set\n\t\t * _modified or recomp.\n\t\t */\n\t\tIM_SETSTR( itext->formula, itext->formula_default );\n\t}\n\n\treturn( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) );\n}\n\n/* Build param lists.\n */\nstatic void *\nitext_update_heap_sub( Symbol *sym, VipsBuf *buf )\n{\n\tvips_buf_appendf( buf, \"%s \", IOBJECT( sym )->name );\n\n\treturn( NULL );\n}\n\n/* heapmodel->modified is set ... parse, compile, and mark for recomp.\n */\nstatic void *\nitext_update_heap( Heapmodel *heapmodel )\n{\n\tiText *itext = ITEXT( heapmodel );\n        Row *row = heapmodel->row;\n\tExpr *expr = row->expr;\n\n#ifdef DEBUG\n\tprintf( \"itext_update_heap: \" );\n\trow_name_print( HEAPMODEL( itext )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* We can have no modified text, but come here anyway. For example, we\n\t * could try eval, find an error due to an undefined symbol, and have\n\t * to retry later. Clearing the row error later will mark us modified, \n\t * even though we have no text of our own.\n\t */\n\tif( itext->formula ) {\n\t\tchar txt[MAX_STRSIZE];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\t\tParseRhsSyntax syntax;\n\n\t\tif( row->sym &&\n\t\t\tis_super( row->sym ) ) {\n\t\t\t/* A super member ... special syntax.\n\t\t\t */\n\t\t\tvips_buf_appendf( &buf, \"%s\", itext->formula );\n\n\t\t\tsyntax = PARSE_SUPER;\n\t\t}\n\t\telse {\n\t\t\t/* Build a new params + '=' + rhs string.\n\t\t\t */\n\t\t\tif( expr->compile ) \n\t\t\t\t(void) slist_map( expr->compile->param, \n\t\t\t\t\t(SListMapFn) itext_update_heap_sub, \n\t\t\t\t\t&buf );\n\t\t\tvips_buf_appendf( &buf, \"= %s;\", itext->formula );\n\n\t\t\tsyntax = PARSE_PARAMS;\n\t\t}\n\n\t\t/* Parse and compile.\n\t\t */\n\t\texpr_error_clear( expr );\n\t\tattach_input_string( vips_buf_all( &buf ) );\n\t\tif( !parse_rhs( expr, syntax ) ) {\n\t\t\texpr_error_set( expr );\n\t\t\treturn( heapmodel );\n\t\t}\n\t}\n\n\t/* Mark for recomp.\n\t */\n\t(void) expr_dirty( expr, link_serial_new() );\n\n\treturn( HEAPMODEL_CLASS( parent_class )->update_heap( heapmodel ) );\n}\n\nstatic void *\nitext_clear_edited( Heapmodel *heapmodel )\n{\n\tiText *itext = ITEXT( heapmodel );\n\n#ifdef DEBUG\n\tprintf( \"itext_clear_edited: \" );\n\trow_name_print( HEAPMODEL( itext )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( itext->edited ) {\n\t\titext_set_edited( itext, FALSE );\n\n\t\t/*\n\n\t\t\tFIXME ... formula_default is not always set for cloned\n\t\t\tedited rows! fix this properly\n\n\t\t */\n\t\tif( itext->formula_default )\n\t\t\titext_set_formula( itext, itext->formula_default );\n\t\telse \n\t\t\tprintf( \"itext_clear_edited: FIXME!\\n\" );\n\n\t\tif( heapmodel->row->expr )\n\t\t\texpr_dirty( heapmodel->row->expr, link_serial_new() );\n\n\t\t/* Don't clear HEAPMODEL( itext )->modified, we want to make\n\t\t * sure we re-parse and compile the default value to break any\n\t\t * old links we might have.\n\t\t */\n\t}\n\n\treturn( HEAPMODEL_CLASS( parent_class )->clear_edited( heapmodel ) );\n}\n\nstatic void\nitext_parent_add( iContainer *child )\n{\n\tiText *itext = ITEXT( child );\n\tRow *row;\n\n\tg_assert( IS_RHS( child->parent ) );\n\n\tICONTAINER_CLASS( parent_class )->parent_add( child );\n\n\trow = HEAPMODEL( itext )->row;\n\n#ifdef DEBUG\n\tprintf( \"itext_new: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Top rows default to edited.\n\t */\n\tif( row == row->top_row )\n\t\titext->edited = TRUE;\n}\n\nstatic gboolean\nitext_load( Model *model, \n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\tiText *itext = ITEXT( model );\n\n\tchar formula[MAX_STRSIZE];\n\tchar formula2[MAX_STRSIZE];\n\n\tg_assert( IS_RHS( parent ) );\n\n\tif( get_sprop( xnode, \"formula\", formula, MAX_STRSIZE ) ) {\n\t\tmodel_loadstate_rewrite( state, formula, formula2 );\n\t\titext_set_formula( itext, formula2 ); \n\t\titext_set_edited( itext, TRUE );\n\t}\n\n\treturn( MODEL_CLASS( parent_class )->load( model, \n\t\tstate, parent, xnode ) );\n}\n\nstatic View *\nitext_view_new( Model *model, View *parent )\n{\n\treturn( itextview_new() );\n}\n\nstatic xmlNode *\nitext_save( Model *model, xmlNode *xnode )\n{\n\tiText *itext = ITEXT( model );\n\tRow *row = HEAPMODEL( model )->row;\n\n\txmlNode *xthis;\n\n\tif( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )\n\t\treturn( NULL );\n\n\tif( itext->edited || row->top_row == row )\n\t\tif( !set_sprop( xthis, \"formula\", itext->formula ) )\n\t\t\treturn( NULL );\n\n\treturn( xthis );\n}\n\nstatic void\nitext_class_init( iTextClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tiContainerClass *icontainer_class = (iContainerClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tHeapmodelClass *heapmodel_class = (HeapmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->finalize = itext_finalize;\n\n\tiobject_class->info = itext_info;\n\n\ticontainer_class->parent_add = itext_parent_add;\n\n\tmodel_class->view_new = itext_view_new;\n\tmodel_class->save = itext_save;\n\tmodel_class->load = itext_load;\n\n\theapmodel_class->update_model = itext_update_model;\n\theapmodel_class->update_heap = itext_update_heap;\n\theapmodel_class->clear_edited = itext_clear_edited;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\nitext_init( iText *itext )\n{\n\tModel *model = MODEL( itext );\n\n\tmodel->display = FALSE;\n\n\titext->formula = NULL;\n\titext->formula_default = NULL;\n\tvips_buf_init( &itext->value );\n\tvips_buf_init( &itext->decompile );\n\tvips_buf_set_dynamic( &itext->value, LINELENGTH );\n\tvips_buf_set_dynamic( &itext->decompile, LINELENGTH );\n\titext->edited = FALSE;\n\n\t/* Some defaults changed in _parent_add() above.\n\t */\n}\n\nGType\nitext_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( iTextClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) itext_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( iText ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) itext_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_HEAPMODEL, \n\t\t\t\"iText\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\niText *\nitext_new( Rhs *rhs )\n{\n\tiText *itext;\n\n\titext = ITEXT( g_object_new( TYPE_ITEXT, NULL ) );\n\ticontainer_child_add( ICONTAINER( rhs ), ICONTAINER( itext ), -1 );\n\n\treturn( itext );\n}\n\nvoid\nitext_set_edited( iText *itext, gboolean edited )\n{\n\tHeapmodel *heapmodel = HEAPMODEL( itext );\n\n\tif( itext->edited != edited ) {\n#ifdef DEBUG\n\t\tprintf( \"itext_set_edited: \" );\n\t\trow_name_print( heapmodel->row );\n\t\tprintf( \" %s\\n\", bool_to_char( edited ) );\n#endif /*DEBUG*/\n\n\t\titext->edited = edited;\n\t\tiobject_changed( IOBJECT( itext ) );\n\t}\n\n\tif( edited ) \n\t\theapmodel_set_modified( heapmodel, TRUE );\n}\n\ngboolean\nitext_set_formula( iText *itext, const char *formula )\n{\n\tif( !itext->formula || strcmp( itext->formula, formula ) != 0 ) {\n#ifdef DEBUG\n\t\tprintf( \"itext_set_formula: \" );\n\t\trow_name_print( HEAPMODEL( itext )->row );\n\t\tprintf( \" \\\"%s\\\"\\n\", formula );\n#endif /*DEBUG*/\n\n\t\tIM_SETSTR( itext->formula, formula );\n\n\t\theapmodel_set_modified( HEAPMODEL( itext ), TRUE );\n\n\t\tiobject_changed( IOBJECT( itext ) );\n\n\t\treturn( TRUE );\n\t}\n\n\treturn( FALSE );\n}\n"
  },
  {
    "path": "src/itext.h",
    "content": "/* a text button in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_ITEXT (itext_get_type())\n#define ITEXT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_ITEXT, iText ))\n#define ITEXT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_ITEXT, iTextClass))\n#define IS_ITEXT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_ITEXT ))\n#define IS_ITEXT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_ITEXT ))\n#define ITEXT_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_ITEXT, iTextClass ))\n\nstruct _iText {\n\tHeapmodel parent_class;\n\n\tVipsBuf value;\t\t\t/* The value displayed as a [char] */\n\tchar *formula;\t\t\t/* The formula we edit */\n\tchar *formula_default;\t\t/* Formula we inherit */\n\tVipsBuf decompile;\t\t/* The value decompiled to a [char] */\n\n\t/* TRUE if the formula has been entered by the user and should be\n\t * saved.\n\t * \n\t * Can't use classmodel edited, as text must inherit from heapmodel.\n\t * Some duplication of code ... see itext_clear_edited()\n\t */\n\tgboolean edited;\n};\n\ntypedef struct _iTextClass {\n\tHeapmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} iTextClass;\n\nGType itext_get_type( void );\niText *itext_new( Rhs *rhs );\n\ngboolean itext_value( Reduce *rc, VipsBuf *buf, PElement *root );\nvoid itext_value_ev( Reduce *rc, VipsBuf *buf, PElement *root );\ngboolean itext_make_value_string( Expr *expr, VipsBuf *buf );\n\nvoid itext_set_edited( iText *text, gboolean edited );\ngboolean itext_set_formula( iText *text, const char *formula );\n"
  },
  {
    "path": "src/itextview.c",
    "content": "/* a view of a text thingy\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\nstatic void \nitextview_refresh( vObject *vobject )\n{\n\tiTextview *itextview = ITEXTVIEW( vobject );\n\tiText *itext = ITEXT( VOBJECT( itextview )->iobject );\n\tRow *row = HEAPMODEL( itext )->row;\n\n\tconst char *display;\n\n#ifdef DEBUG\n\tprintf( \"itextview_refresh: \" );\n\trow_name_print( row );\n\tprintf( \" (%p)\\n\", vobject );\n#endif /*DEBUG*/\n\n\t/* Only reset edit mode if the text hasn't been changed. We\n\t * don't want the user to lose work.\n\t */\n\tif( !itextview->formula->changed ) \n\t\tswitch( row->ws->mode ) {\n\t\tcase WORKSPACE_MODE_REGULAR:\n\t\t\tformula_set_edit( itextview->formula, FALSE );\n\t\t\tformula_set_sensitive( itextview->formula, TRUE );\n\t\t\tbreak;\n\n\t\tcase WORKSPACE_MODE_FORMULA:\n\t\t\tformula_set_edit( itextview->formula, TRUE );\n\t\t\tformula_set_sensitive( itextview->formula, TRUE );\n\t\t\tbreak;\n\n\t\tcase WORKSPACE_MODE_NOEDIT:\n\t\t\tformula_set_edit( itextview->formula, FALSE );\n\t\t\tformula_set_sensitive( itextview->formula, FALSE );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tg_assert_not_reached();\n\t\t}\n\n\t/* We display the formula if this is a class ... we assume the members\n\t * and/or the graphic will represent the value.\n\t */\n\tif( row->is_class )\n\t\tdisplay = itext->formula;\n\telse\n\t\tdisplay = vips_buf_all( &itext->value );\n\n\tif( itextview->formula && itext->value.base )\n\t\tformula_set_value_expr( itextview->formula,\n\t\t\tdisplay, itext->formula );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\nitextview_link( View *view, Model *model, View *parent )\n{\n\tiTextview *itextview = ITEXTVIEW( view );\n\tiText *itext = ITEXT( model );\n\tRow *row = HEAPMODEL( itext )->row;\n\n#ifdef DEBUG\n\tprintf( \"itextview_link: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\t/* Edit mode defaults to edit mode for workspace.\n\t */\n        formula_set_edit( itextview->formula, \n\t\trow->ws->mode == WORKSPACE_MODE_FORMULA );\n}\n\n/* Reset edit mode ... go back to whatever is set for this ws.\n */\nstatic void \nitextview_reset( View *view )\n{\n\tiTextview *itextview = ITEXTVIEW( view );\n\tiText *itext = ITEXT( VOBJECT( itextview )->iobject );\n\tRow *row = HEAPMODEL( itext )->row;\n\n#ifdef DEBUG\n\tprintf( \"itextview_reset: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tformula_set_edit( ITEXTVIEW( view )->formula, \n\t\trow->ws->mode == WORKSPACE_MODE_FORMULA );\n\n\tVIEW_CLASS( parent_class )->reset( view );\n}\n\n/* Re-read the text in a tally entry. \n */\nstatic void *\nitextview_scan( View *view )\n{\n\tiTextview *itextview = ITEXTVIEW( view );\n\tiText *itext = ITEXT( VOBJECT( itextview )->iobject );\n\n#ifdef DEBUG\n\tRow *row = HEAPMODEL( itext )->row;\n\n\tprintf( \"itextview_scan: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( formula_scan( itextview->formula ) &&\n\t\titext_set_formula( itext, itextview->formula->expr ) )\n\t\titext_set_edited( itext, TRUE );\n\n\treturn( VIEW_CLASS( parent_class )->scan( view ) );\n}\n\nstatic void\nitextview_class_init( iTextviewClass *class )\n{\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = itextview_refresh;\n\n\tview_class->link = itextview_link;\n\tview_class->reset = itextview_reset;\n\tview_class->scan = itextview_scan;\n}\n\nvoid\nitextview_edit_cb( Formula *formula, iTextview *itextview )\n{\n\tview_resettable_register( VIEW( itextview ) );\n}\n\nvoid\nitextview_activate_cb( Formula *formula, iTextview *itextview )\n{\n\tiText *itext = ITEXT( VOBJECT( itextview )->iobject );\n\tRow *row = HEAPMODEL( itext )->row;\n\n\t/* Reset edits on this row and all children. Our (potentially) next\n\t * text will invlidate all of them.\n\t */\n\t(void) icontainer_map_all( ICONTAINER( row ),\n\t\t(icontainer_map_fn) heapmodel_clear_edited, NULL );\n\n\t/* Make sure we scan this text, even if it's not been edited.\n\t */\n\tview_scannable_register( VIEW( itextview ) );\n\n\tworkspace_set_modified( row->ws, TRUE );\n\n\tsymbol_recalculate_all();\n}\n\nstatic void\nitextview_enter_cb( Formula *formula, iTextview *itextview )\n{\n\tiText *itext = ITEXT( VOBJECT( itextview )->iobject );\n\tRow *row = HEAPMODEL( itext )->row;\n\n\trow_set_status( row );\n\trow_show_dependents( row );\n}\n\nstatic void\nitextview_leave_cb( Formula *formula, iTextview *itextview )\n{\n\tiText *itext = ITEXT( VOBJECT( itextview )->iobject );\n\tRow *row = HEAPMODEL( itext )->row;\n\n\trow_hide_dependents( row );\n}\n\nstatic void\nitextview_init( iTextview *itextview )\n{\n\titextview->formula = formula_new();\n\n        gtk_signal_connect( GTK_OBJECT( itextview->formula ), \"edit\", \n\t\tGTK_SIGNAL_FUNC( itextview_edit_cb ), itextview );\n        gtk_signal_connect_object( GTK_OBJECT( itextview->formula ), \"changed\", \n\t\tGTK_SIGNAL_FUNC( view_changed_cb ), itextview );\n        gtk_signal_connect( GTK_OBJECT( itextview->formula ), \"activate\",\n                GTK_SIGNAL_FUNC( itextview_activate_cb ), itextview );\n        gtk_signal_connect( GTK_OBJECT( itextview->formula ), \"enter\", \n\t\tGTK_SIGNAL_FUNC( itextview_enter_cb ), itextview );\n        gtk_signal_connect( GTK_OBJECT( itextview->formula ), \"leave\", \n\t\tGTK_SIGNAL_FUNC( itextview_leave_cb ), itextview );\n\n        gtk_box_pack_start( GTK_BOX( itextview ), \n\t\tGTK_WIDGET( itextview->formula ), TRUE, FALSE, 0 );\n        gtk_widget_show( GTK_WIDGET( itextview->formula ) );\n}\n\nGtkType\nitextview_get_type( void )\n{\n\tstatic GtkType itextview_type = 0;\n\n\tif( !itextview_type ) {\n\t\tstatic const GtkTypeInfo itextview_info = {\n\t\t\t\"iTextview\",\n\t\t\tsizeof( iTextview ),\n\t\t\tsizeof( iTextviewClass ),\n\t\t\t(GtkClassInitFunc) itextview_class_init,\n\t\t\t(GtkObjectInitFunc) itextview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\titextview_type = gtk_type_unique( TYPE_VIEW, &itextview_info );\n\t}\n\n\treturn( itextview_type );\n}\n\nView *\nitextview_new( void )\n{\n\tiTextview *itextview = gtk_type_new( TYPE_ITEXTVIEW );\n\n\treturn( VIEW( itextview ) );\n}\n"
  },
  {
    "path": "src/itextview.h",
    "content": "/* a textview button in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_ITEXTVIEW (itextview_get_type())\n#define ITEXTVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_ITEXTVIEW, iTextview ))\n#define ITEXTVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_ITEXTVIEW, iTextviewClass ))\n#define IS_ITEXTVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_ITEXTVIEW ))\n#define IS_ITEXTVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_ITEXTVIEW ))\n\ntypedef struct _iTextview {\n\tView view;\n\n\t/* Widgets.\n\t */\n        Formula *formula;\n} iTextview;\n\ntypedef struct _iTextviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} iTextviewClass;\n\nGtkType itextview_get_type( void );\nView *itextview_new( void );\n"
  },
  {
    "path": "src/iwindow.c",
    "content": "/* make and manage base windows ... dialog (messagebox, file box), top\n * level windows\n */\n\n/*\n\n    Copyright (C) 1991-2001, The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n  \n    build interface:\n\n\tiwnd = iwindow_new( type );\n\tiwindow_set_*( iwnd, ... );\n\tiwindow_build( iwnd );\n\n    destroy interface:\n\n    \tiwindow_kill()\n\n\t\t'cancellable' kill ... user popdown can return IWINDOW_ERROR\n\t\tor IWINDOW_NO to prevent popdown\n\n\tgtk_widget_destroy()\n\n\t\tnon-cancellable ... popdown is not called\n\n\tso ... don't free() in popdown, subclass iwnd and free() in _destroy()\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* Cursor bitmaps.\n */\n#include \"BITMAPS/dropper_src.xbm\"\n#include \"BITMAPS/dropper_msk.xbm\"\n#include \"BITMAPS/magin_src.xbm\"\n#include \"BITMAPS/magout_src.xbm\"\n#include \"BITMAPS/mag_msk.xbm\"\n#include \"BITMAPS/watch_1.xbm\"\n#include \"BITMAPS/watch_2.xbm\"\n#include \"BITMAPS/watch_3.xbm\"\n#include \"BITMAPS/watch_4.xbm\"\n#include \"BITMAPS/watch_5.xbm\"\n#include \"BITMAPS/watch_6.xbm\"\n#include \"BITMAPS/watch_7.xbm\"\n#include \"BITMAPS/watch_8.xbm\"\n#include \"BITMAPS/watch_msk.xbm\"\n\nstatic GtkWindowClass *parent_class = NULL;\n\n/* List of all iwindows.\n */\nstatic GSList *iwindow_all = NULL;\n\n/* All our cursors.\n */\nstatic GdkCursor *iwindow_cursor[IWINDOW_SHAPE_LAST] = { NULL };\n\n#ifdef DEBUG\n/* Human-readable names for cursor shapes.\n */\nstatic const char *iwindow_cursor_name[] = {\n\t\"IWINDOW_SHAPE_DROPPER\",\n\t\"IWINDOW_SHAPE_PEN\",\n\t\"IWINDOW_SHAPE_SMUDGE\",\n\t\"IWINDOW_SHAPE_SMEAR\",\n\t\"IWINDOW_SHAPE_TEXT\",\n\t\"IWINDOW_SHAPE_RECT\",\n\t\"IWINDOW_SHAPE_FLOOD\",\n\t\"IWINDOW_SHAPE_MOVE\",\n\t\"IWINDOW_SHAPE_EDIT\",\n\t\"IWINDOW_SHAPE_MAGIN\",\t\n\t\"IWINDOW_SHAPE_MAGOUT\",\t\n\t\"IWINDOW_SHAPE_TOP\",\n\t\"IWINDOW_SHAPE_BOTTOM\",\n\t\"IWINDOW_SHAPE_LEFT\",\n\t\"IWINDOW_SHAPE_RIGHT\",\n\t\"IWINDOW_SHAPE_TOPRIGHT\",\n\t\"IWINDOW_SHAPE_TOPLEFT\",\n\t\"IWINDOW_SHAPE_BOTTOMRIGHT\",\n\t\"IWINDOW_SHAPE_BOTTOMLEFT\",\n\t\"IWINDOW_SHAPE_HGLASS1\",\n\t\"IWINDOW_SHAPE_HGLASS2\",\n\t\"IWINDOW_SHAPE_HGLASS3\",\n\t\"IWINDOW_SHAPE_HGLASS4\",\n\t\"IWINDOW_SHAPE_HGLASS5\",\n\t\"IWINDOW_SHAPE_HGLASS6\",\n\t\"IWINDOW_SHAPE_HGLASS7\",\n\t\"IWINDOW_SHAPE_HGLASS8\",\n\t\"IWINDOW_SHAPE_NONE\"\n};\n#endif /*DEBUG*/\n\nint\niwindow_number( void )\n{\n\treturn( g_slist_length( iwindow_all ) );\n}\n\n/* Pick an iwindow at random. Used if we need a window for a dialog, and we're\n * not sure which to pick. During shutdown we can have no windows. \n */\niWindow *\niwindow_pick_one( void )\n{\n\tif( !iwindow_all )\n\t\treturn( NULL ); \n\n\treturn( IWINDOW( iwindow_all->data ) );\n}\n\n/* Over all windows.\n */\nvoid *\niwindow_map_all( iWindowMapFn fn, void *a )\n{\n\treturn( slist_map( iwindow_all, (SListMapFn) fn, a ) );\n}\n\n/* Make a custom cursor ... source, mask, width, height and hot spot position.\n */\nstatic GdkCursor *\niwindow_make_cursor_data( guchar *src_bits, guchar *msk_bits, \n\tint w, int h, int x, int y )\n{\n\tGdkPixmap *src;\n\tGdkPixmap *msk;\n\tGdkCursor *cursor;\n\tGdkColor fg = { 0, 255 << 8, 255 << 8, 255 << 8 };\n\tGdkColor bg = { 0, 0, 0, 0 };\n\n\tsrc = gdk_bitmap_create_from_data( NULL, \n\t\t(const char *) src_bits, w, h );\n\tmsk = gdk_bitmap_create_from_data( NULL, \n\t\t(const char *) msk_bits, w, h );\n\tcursor = gdk_cursor_new_from_pixmap( src, msk, &fg, &bg, x, y );\n\tgdk_pixmap_unref( src );\n\tgdk_pixmap_unref( msk );\n\n\treturn( cursor );\n}\n\n/* Build all the cursors.\n */\nstatic void\niwindow_make_cursors( void )\n{\n\t/* Init standard cursors with this table.\n\t */\n\tstatic GdkCursorType standards[] = {\n\t\tGDK_CURSOR_IS_PIXMAP,\t/* IWINDOW_SHAPE_DROPPER */\n\t\tGDK_PENCIL,\t\t/* IWINDOW_SHAPE_PEN */\n\t\tGDK_HAND2,\t\t/* IWINDOW_SHAPE_SMUDGE */\n\t\tGDK_SPIDER,\t\t/* IWINDOW_SHAPE_SMEAR */\n\t\tGDK_GOBBLER,\t\t/* IWINDOW_SHAPE_TEXT */\n\t\tGDK_SIZING,\t\t/* IWINDOW_SHAPE_RECT */\n\t\tGDK_TREK,\t\t/* IWINDOW_SHAPE_FLOOD */\n\t\tGDK_FLEUR,\t\t/* IWINDOW_SHAPE_MOVE */\n\t\tGDK_CROSSHAIR,\t\t/* IWINDOW_SHAPE_EDIT */\n\t\tGDK_CURSOR_IS_PIXMAP, \t/* IWINDOW_SHAPE_MAGIN */\n\t\tGDK_CURSOR_IS_PIXMAP, \t/* IWINDOW_SHAPE_MAGOUT */\n\t\tGDK_TOP_SIDE,\t\t/* IWINDOW_SHAPE_TOP */\n\t\tGDK_BOTTOM_SIDE,\t/* IWINDOW_SHAPE_BOTTOM */\n\t\tGDK_LEFT_SIDE,\t\t/* IWINDOW_SHAPE_LEFT */\n\t\tGDK_RIGHT_SIDE,\t\t/* IWINDOW_SHAPE_RIGHT */\n\t\tGDK_TOP_RIGHT_CORNER,\t/* IWINDOW_SHAPE_TOPRIGHT */\n\t\tGDK_TOP_LEFT_CORNER,\t/* IWINDOW_SHAPE_TOPLEFT */\n\t\tGDK_BOTTOM_RIGHT_CORNER,/* IWINDOW_SHAPE_BOTTOMRIGHT, */\n\t\tGDK_BOTTOM_LEFT_CORNER,\t/* IWINDOW_SHAPE_BOTTOMLEFT */\n\t};\n\n\t/* All the bits for the rotating cursor.\n\t */\n\tstatic guchar *watch_bits[] = {\n\t\twatch_1_bits,\n\t\twatch_2_bits,\n\t\twatch_3_bits,\n\t\twatch_4_bits,\n\t\twatch_5_bits,\n\t\twatch_6_bits,\n\t\twatch_7_bits,\n\t\twatch_8_bits,\n\t};\n\n\tint i;\n\n\tif( iwindow_cursor[0] )\n\t\treturn;\n\n\t/* Easy ones first.\n\t */\n\tfor( i = 0; i < IM_NUMBER( standards ); i++ )\n\t\tif( standards[i] != GDK_CURSOR_IS_PIXMAP )\n\t\t\tiwindow_cursor[i] = gdk_cursor_new( standards[i] );\n\n\t/* Custom cursors.\n\t */\n\tiwindow_cursor[IWINDOW_SHAPE_DROPPER] = iwindow_make_cursor_data( \n\t\tdropper_src_bits, dropper_msk_bits,\n\t\tdropper_src_width, dropper_src_height, 0, 15 );\n\tiwindow_cursor[IWINDOW_SHAPE_MAGIN] = iwindow_make_cursor_data( \n\t\tmagin_src_bits, mag_msk_bits, \n\t\tmag_msk_width, mag_msk_height, 6, 6 );\n\tiwindow_cursor[IWINDOW_SHAPE_MAGOUT] = iwindow_make_cursor_data( \n\t\tmagout_src_bits, mag_msk_bits,\n\t\tmag_msk_width, mag_msk_height, 6, 6 );\n\n\t/* The hglasses.\n\t */\n\tfor( i = 0; i < IM_NUMBER( watch_bits ); i++ )\n\t\tiwindow_cursor[IWINDOW_SHAPE_HGLASS1 + i] = \n\t\t\tiwindow_make_cursor_data( \n\t\t\t\twatch_bits[i], watch_msk_bits,\n\t\t\t\twatch_1_width, watch_1_height, 7, 7 );\n}\n\n/* Get the work window.\n */\nstatic GdkWindow *\niwindow_get_work_window( iWindow *iwnd )\n{\n\tif( iwnd->work_window )\n\t\treturn( iwnd->work_window );\n\telse\n\t\treturn( GTK_WIDGET( iwnd )->window );\n}\n\n/* Update the cursor for a window.\n */\nstatic void *\niwindow_cursor_update( iWindow *iwnd )\n{\n\tif( GTK_WIDGET_REALIZED( GTK_WIDGET( iwnd ) ) ) {\n\t\tGSList *p;\n\t\tiWindowShape best_shape;\n\t\tint best_priority;\n\n\t\t/* Global shape set? Use that for the whole window.\n\t\t */\n\t\tif( iwnd->shape != IWINDOW_SHAPE_NONE ) {\n\t\t\tgdk_window_set_cursor( GTK_WIDGET( iwnd )->window, \n\t\t\t\tiwindow_cursor[iwnd->shape] );\n\t\t\tgdk_window_set_cursor( iwindow_get_work_window( iwnd ),\n\t\t\t\tiwindow_cursor[iwnd->shape] );\n\t\t\tgdk_flush();\n\n\t\t\treturn( NULL );\n\t\t}\n\n\t\t/* No global shape ... make sure there's no global cursor on\n\t\t * this window.\n\t\t */\n\t\tgdk_window_set_cursor( GTK_WIDGET( iwnd )->window, NULL );\n\t\tgdk_window_set_cursor( iwindow_get_work_window( iwnd ), NULL );\n\n\t\t/* And set the work area to the highest priority non-NONE \n\t\t * shape we can find .\n\n\t\t\tFIXME ... could avoid the search if we sorted the\n\t\t\tcontext list by priority on each context_new(),\n\t\t\tbut not very important.\n\n\t\t */\n\t\tbest_shape = IWINDOW_SHAPE_NONE;\n\t\tbest_priority = -1;\n\t\tfor( p = iwnd->contexts; p; p = p->next ) {\n\t\t\tiWindowCursorContext *cntxt = \n\t\t\t\t(iWindowCursorContext *) p->data;\n\n\t\t\tif( cntxt->shape != IWINDOW_SHAPE_NONE &&\n\t\t\t\tcntxt->priority > best_priority ) {\n\t\t\t\tbest_shape = cntxt->shape;\n\t\t\t\tbest_priority = cntxt->priority;\n\t\t\t}\n\t\t}\n\n\t\t/* Pref to disable crosshair.\n\t\t */\n\t\tif( best_shape == IWINDOW_SHAPE_EDIT && !DISPLAY_CROSSHAIR )\n\t\t\tbest_shape = IWINDOW_SHAPE_NONE;\n\n\t\tgdk_window_set_cursor( \n\t\t\tiwindow_get_work_window( iwnd ),\n\t\t\tiwindow_cursor[best_shape] );\n\t\tgdk_flush();\n\t}\n\n\treturn( NULL );\n}\n\n/* Set a global cursor for a window.\n */\nstatic void *\niwindow_cursor_set( iWindow *iwnd, iWindowShape *shape )\n{\n\tif( iwnd->shape != *shape ) {\n\t\tiwnd->shape = *shape;\n\t\tiwindow_cursor_update( iwnd );\n\t}\n\n\treturn( NULL );\n}\n\nstatic gboolean hourglass_showing = FALSE;\n\nstatic void\nhourglass_begin( void )\n{\n\thourglass_showing = TRUE;\n}\n\nstatic void\nhourglass_update( void )\n{\n\tif( hourglass_showing ) {\n\t\tstatic iWindowShape shape = IWINDOW_SHAPE_HGLASS1;\n\n\t\tiwindow_map_all( (iWindowMapFn) iwindow_cursor_set, &shape );\n\n\t\tshape += 1;\n\t\tif( shape > IWINDOW_SHAPE_HGLASS8 )\n\t\t\tshape = IWINDOW_SHAPE_HGLASS1;\n\t}\n}\n\nstatic void\nhourglass_end( void )\n{\n\tif( hourglass_showing ) {\n\t\tiWindowShape shape = IWINDOW_SHAPE_NONE;\n\n\t\tiwindow_map_all( (iWindowMapFn) iwindow_cursor_set, &shape );\n\t\thourglass_showing = FALSE;\n\t}\n}\n\niWindowCursorContext *\niwindow_cursor_context_new( iWindow *iwnd, int priority, const char *name )\n{\n\tiWindowCursorContext *cntxt = INEW( NULL, iWindowCursorContext );\n\n#ifdef DEBUG\n\tprintf( \"iwindow_cursor_context_new: %s\\n\", name );\n#endif /*DEBUG*/\n\n\tcntxt->iwnd = iwnd;\n\tcntxt->priority = priority;\n\tcntxt->name = name;\n\tcntxt->shape = IWINDOW_SHAPE_NONE;\n\tiwnd->contexts = g_slist_prepend( iwnd->contexts, cntxt );\n\n\treturn( cntxt );\n}\n\nvoid\niwindow_cursor_context_destroy( iWindowCursorContext *cntxt )\n{\n\tiWindow *iwnd = cntxt->iwnd;\n\n\tiwnd->contexts = g_slist_remove( iwnd->contexts, cntxt );\n\tIM_FREE( cntxt );\n\tiwindow_cursor_update( iwnd );\n}\n\nvoid\niwindow_cursor_context_set_cursor( iWindowCursorContext *cntxt, \n\tiWindowShape shape )\n{\n\tif( cntxt->shape != shape ) {\n#ifdef DEBUG\n\t\tprintf( \"iwindow_cursor_context_set_cursor: %s = %s\\n\",\n\t\t\tcntxt->name, iwindow_cursor_name[shape] );\n#endif /*DEBUG*/\n\n\t\tcntxt->shape = shape;\n\t\tiwindow_cursor_update( cntxt->iwnd );\n\t}\n}\n\niWindowSusp *\niwindow_susp_new( iWindowFn fn, \n\tiWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys )\n{\n        iWindowSusp *susp;\n\n        if( !(susp = INEW( NULL, iWindowSusp )) )\n\t\treturn( NULL );\n\n        susp->fn = fn; \n        susp->iwnd = iwnd; \n        susp->client = client; \n        susp->nfn = nfn;\n        susp->sys = sys;\n\n        return( susp );\n}\n\n/* Trigger a suspension's reply, and free it.\n */\nvoid \niwindow_susp_return( void *sys, iWindowResult result )\n{\n\tiWindowSusp *susp = IWINDOW_SUSP( sys );\n\n        susp->nfn( susp->sys, result );\n\n        im_free( susp );\n}\n\nvoid\niwindow_susp_trigger( iWindowSusp *susp )\n{\n\tsusp->fn( susp->iwnd, susp->client, susp->nfn, susp->sys );\n\tim_free( susp );\n}\n\n/* Compose two iWindowFns ... if this one succeeded, trigger the next in turn.\n * Otherwise bail out.\n */\nvoid\niwindow_susp_comp( void *sys, iWindowResult result )\n{\n\tiWindowSusp *susp = IWINDOW_SUSP( sys );\n\n\tif( result == IWINDOW_YES ) \n\t\tiwindow_susp_trigger( susp ); \n\telse \n\t\tiwindow_susp_return( sys, result );\n}\n\n/* Null window callback.\n */\nvoid \niwindow_true_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) \n{ \n\tnfn( sys, IWINDOW_YES );\n}\n\nvoid \niwindow_false_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) \n{ \n\tnfn( sys, IWINDOW_NO );\n}\n\n/* Null notify callback.\n */\nvoid iwindow_notify_null( void *client, iWindowResult result ) { }\n\n/* Final end of a window. Destroy!\n */\nstatic void\niwindow_final_death( iWindow *iwnd )\n{\n#ifdef DEBUG\n\tprintf( \"iwindow_final_death: %s\\n\", iwnd->title );\n#endif /*DEBUG*/\n\n\tg_assert( iwnd->pending == 0 && iwnd->destroy );\n\n\t/* Clean up.\n\t */\n\tgtk_widget_destroy( GTK_WIDGET( iwnd ) );\n}\n\n/* A notify comes back ... adjust the pending count. If this is a zombie and\n * this is the final pending, it's final death. \n */\nvoid\niwindow_notify_return( iWindow *iwnd )\n{\n#ifdef DEBUG\n\tprintf( \"iwindow_notify_return: %s (pending = %d)\\n\", \n\t\tiwnd->title, iwnd->pending );\n#endif /*DEBUG*/\n\n\tg_assert( iwnd->pending > 0 );\n\n\tiwnd->pending--;\n\tif( iwnd->destroy && iwnd->pending == 0 ) {\n#ifdef DEBUG\n\t\tprintf( \"iwindow_notify_return: zombie death %s\\n\",\n\t\t\tiwnd->title );\n#endif /*DEBUG*/\n\t\tiwindow_final_death( iwnd );\n\t}\n}\n\n/* Send a notify off, tell the client to come back to back.\n */\nvoid\niwindow_notify_send( iWindow *iwnd, \n\tiWindowFn fn, void *client, iWindowNotifyFn back, void *sys )\n{\n#ifdef DEBUG\n\tprintf( \"iwindow_notify_send: %s (pending = %d)\\n\", \n\t\tiwnd->title, iwnd->pending );\n#endif /*DEBUG*/\n\n\tiwnd->pending++;\n\tif( fn )\n\t\tfn( iwnd, client, back, sys );\n\telse\n\t\tback( sys, IWINDOW_YES );\n}\n\nstatic void\niwindow_finalize( GObject *gobject )\n{\n\tiWindow *iwnd = IWINDOW( gobject );\n\n#ifdef DEBUG\n\tprintf( \"iwindow_finalize: %s\\n\", iwnd->title );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\tiwindow_all = g_slist_remove( iwindow_all, iwnd );\n\tIM_FREE( iwnd->title );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n\n\t/* Last window and we've got through startup? Quit the application.\n\t */\n\tif( iwindow_number() == 0 && \n\t\t!main_starting )\n\t\tmain_quit_test();\n}\n\nstatic void\niwindow_destroy( GtkObject *gobject )\n{\n\tiWindow *iwnd = IWINDOW( gobject );\n\n#ifdef DEBUG\n\tprintf( \"iwindow_destroy: %s\\n\", iwnd->title );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\tFREESID( iwnd->parent_unmap_sid, iwnd->parent_window );\n\tUNREF( iwnd->action_group ); \n\tUNREF( iwnd->ui_manager ); \n\n\t/* Now we've destroyed, we must stop popdown from being called, since \n\t * the view will have junked a lot of stuff.\n\t */\n\tiwnd->destroy = TRUE;\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( gobject );\n}\n\nstatic void\niwindow_popdown_notify( iWindow *iwnd, iWindowResult result )\n{\n#ifdef DEBUG\n\tprintf( \"iwindow_popdown_notify: %p %s\\n\", iwnd, iwnd->title );\n#endif /*DEBUG*/\n\n\tif( result == IWINDOW_ERROR )\n\t\tiwindow_alert( GTK_WIDGET( iwnd ), GTK_MESSAGE_ERROR );\n\telse if( result == IWINDOW_YES )\n\t\tiwindow_kill( iwnd );\n\n\tif( result != IWINDOW_YES ) {\n#ifdef DEBUG\n\t\tprintf( \"iwindow_popdown_notify: %s: kill cancelled!\\n\", \n\t\t\tiwnd->title );\n#endif /*DEBUG*/\n\n\t\t/* Cancel popdown.\n\t\t */\n\t\tiwnd->destroy = FALSE;\n\t}\n\telse {\n\t\t/* Popdown confirmed! Trigger class popdown. _real_popdown()\n\t\t * does an unmap to hide the window during the rest of the\n\t\t * destroy.\n\t\t */\n\t\tIWINDOW_GET_CLASS( iwnd )->popdown( GTK_WIDGET( iwnd ) );\n\t}\n\n\tcalli_string_filenamef( (calli_string_fn) gtk_accel_map_save,\n\t\t\"%s\" G_DIR_SEPARATOR_S \"accel_map\", get_savedir() );\n\n\t/* If this is the final pending response and ->destroy is true, this \n\t * will destroy the window.\n\t */\n\tiwindow_notify_return( iwnd );\n}\n\nstatic gboolean\niwindow_delete_event( GtkWidget *widget, GdkEventAny *event )\n{\n\tiWindow *iwnd = IWINDOW( widget );\n\n#ifdef DEBUG\n\tprintf( \"iwindow_delete_event: %s\\n\", iwnd->title );\n#endif /*DEBUG*/\n\n\tif( !iwnd->destroy ) {\n#ifdef DEBUG\n\t\tprintf( \"iwindow_delete_event: starting destroy\\n\" );\n#endif /*DEBUG*/\n\n\t\tiwindow_kill( iwnd );\n\t}\n\n\t/* Never delete here ... wait for iwindow_popdown_notify to\n\t * confirm the kill.\n\t */\n\treturn( TRUE );\n}\n\nstatic gboolean\niwindow_configure_event( GtkWidget *widget, GdkEventConfigure *event )\n{\n\tiWindow *iwnd = IWINDOW( widget );\n\n\tif( iwnd->width_pref ) {\n\t\t/* Save window size in global prefs.\n\t\t */\n\t\tprefs_set( iwnd->width_pref, \"%d\", event->width );\n\t\tprefs_set( iwnd->height_pref, \"%d\", event->height );\n\t}\n\n\treturn( GTK_WIDGET_CLASS( parent_class )->\n\t\tconfigure_event( widget, event ) );\n}\n\n/* Our parent has been destroyed, kill us too.\n */\nstatic void\niwindow_parent_unmap_cb( GtkWidget *par, iWindow *iwnd )\n{\n#ifdef DEBUG\n\tprintf( \"iwindow_parent_unmap_cb: %s\\n\", iwnd->title );\n#endif /*DEBUG*/\n\n\t/* Here for dead parent ... if parent is dead, we won't need to remove\n\t * the dead-dad signal. \n\t */\n\tiwnd->parent_unmap_sid = 0;\n\n\tiwindow_kill( iwnd );\n}\n\nstatic GtkActionEntry iwnd_actions[] = {\n\t/* Common menus.\n\t */\n\t{ \"FileMenu\", NULL, N_( \"_File\" ) },\n\t{ \"NewMenu\", NULL, N_( \"_New\" ) },\n\t{ \"EditMenu\", NULL, N_( \"_Edit\" ) },\n\t{ \"ViewMenu\", NULL, N_( \"_View\" ) },\n\t{ \"HelpMenu\", NULL, N_( \"_Help\" ) },\n\n\t/* Common items.\n\t */\n\t{ \"Close\", \n\t\tGTK_STOCK_CLOSE, N_( \"_Close\" ), NULL,\n\t\tN_( \"Close\" ), \n\t\tG_CALLBACK( iwindow_kill_action_cb ) },\n\n\t{ \"Quit\", \n\t\tGTK_STOCK_QUIT, N_( \"_Quit\" ), \"<control>q\",\n\t\tN_( \"Quit nip2\" ), \n\t\tG_CALLBACK( main_quit_test ) },\n\t{ \"Guide\", \n\t\tGTK_STOCK_HELP, N_( \"_Contents\" ), \"F1\",\n\t\tN_( \"Open the users guide\" ), \n\t\tG_CALLBACK( mainw_guide_action_cb ) },\n\n\t{ \"About\", \n\t\tNULL, N_( \"_About\" ), NULL,\n\t\tN_( \"About this program\" ), \n\t\tG_CALLBACK( mainw_about_action_cb ) },\n\n\t{ \"Homepage\", \n\t\tNULL, N_( \"_Website\" ), NULL,\n\t\tN_( \"Open the VIPS Homepage\" ), \n\t\tG_CALLBACK( mainw_homepage_action_cb ) }\n};\n\nstatic void \niwindow_real_build( GtkWidget *widget )\n{\n\tiWindow *iwnd = IWINDOW( widget );\n\tGdkScreen *screen = gtk_widget_get_screen( GTK_WIDGET( iwnd ) );\n\n\tGtkAccelGroup *accel_group;\n\n#ifdef DEBUG\n\tprintf( \"iwindow_real_build: %s\\n\", iwnd->title );\n#endif /*DEBUG*/\n\n        gtk_container_set_border_width( GTK_CONTAINER( iwnd ), 0 );\n\n        iwnd->work = gtk_vbox_new( FALSE, 0 );\n        gtk_container_add( GTK_CONTAINER( iwnd ), iwnd->work );\n\n\t/* Use the type name (eg. \"Imageview\") for the name of the\n\t * actiongroup.\n\t */\n\tiwnd->action_group = gtk_action_group_new( G_OBJECT_TYPE_NAME( iwnd ) );\n\tgtk_action_group_set_translation_domain( iwnd->action_group, \n\t\tGETTEXT_PACKAGE );\n\tgtk_action_group_add_actions( iwnd->action_group, \n\t\tiwnd_actions, G_N_ELEMENTS( iwnd_actions ), \n\t\tGTK_WINDOW( iwnd ) );\n\n\tiwnd->ui_manager = gtk_ui_manager_new();\n\tgtk_ui_manager_insert_action_group( iwnd->ui_manager, \n\t\tiwnd->action_group, 0 );\n\n\taccel_group = gtk_ui_manager_get_accel_group( iwnd->ui_manager );\n\tgtk_window_add_accel_group( GTK_WINDOW( iwnd ), accel_group );\n\n\t/* Call per-instance build.\n\t */\n        if( iwnd->build )\n\t\tiwnd->build( iwnd, iwnd->work, \n\t\t\tiwnd->build_a, iwnd->build_b, iwnd->build_c );\n\n\tif( iwnd->title )\n\t\tgtk_window_set_title( GTK_WINDOW( iwnd ), iwnd->title );\n\n\tif( iwnd->width_pref ) {\n\t\tint width = watch_int_get( main_watchgroup, \n\t\t\tiwnd->width_pref, 640 );\n\t\tint height = watch_int_get( main_watchgroup, \n\t\t\tiwnd->height_pref, 480 );\n\n\t\tgtk_window_set_default_size( GTK_WINDOW( iwnd ), \n\t\t\tIM_MIN( width, gdk_screen_get_width( screen ) ),\n\t\t\tIM_MIN( height, gdk_screen_get_height( screen ) ) );\n\t}\n\n\t/* Link to parent.\n\t */\n        if( iwnd->parent_window ) {\n\t\tif( IWINDOW_GET_CLASS( iwnd )->transient &&\n\t\t\tiwnd->parent_window &&\n\t\t\tiwnd != iwnd->parent_window )\n\t\t\tgtk_window_set_transient_for( GTK_WINDOW( iwnd ),\n\t\t\t\tGTK_WINDOW( iwnd->parent_window ) );\n\n\t\t/* We watch our parent's \"unmap\" rather than \"destroy\" since\n\t\t * we use gtk_widget_unmap() to hide killed windows during\n\t\t * popdown (see iwindow_popdown_notify()).\n\t\t */\n\t\tiwnd->parent_unmap_sid = gtk_signal_connect( \n\t\t\tGTK_OBJECT( iwnd->parent_window ), \n\t\t\t\"unmap\",\n\t\t\tGTK_SIGNAL_FUNC( iwindow_parent_unmap_cb ), iwnd );\n\n\t\t/* Show the parent. For example, if this is the ^Q\n\t\t * save-or-quit dialog and the parent is a mainw, we want to\n\t\t * pop the mainw up.\n\t\t */\n\t\tgtk_window_present( GTK_WINDOW( iwnd->parent_window ) );\n\t}\n\n        gtk_widget_show( iwnd->work );\n}\n\nstatic void \niwindow_real_popdown( GtkWidget *widget )\n{\n\tgtk_widget_unmap( widget );\n}\n\nstatic void\niwindow_class_init( iWindowClass *class )\n{\n\tGObjectClass *object_class = (GObjectClass *) class;\n\tGtkObjectClass *gobject_class = (GtkObjectClass *) class;\n\tGtkWidgetClass *widget_class = (GtkWidgetClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Init methods.\n\t */\n\tobject_class->finalize = iwindow_finalize;\n\n\tgobject_class->destroy = iwindow_destroy;\n\n\twidget_class->delete_event = iwindow_delete_event;\n\twidget_class->configure_event = iwindow_configure_event;\n\n\tclass->build = iwindow_real_build;\n\tclass->popdown = iwindow_real_popdown;\n\n\tclass->transient = FALSE;\n\n\t/* Create signals.\n\t */\n\n\t/* Static class data init.\n\t */\n\tiwindow_make_cursors();\n\n\t/* Link to busy signals.\n\t */\n\tg_signal_connect( progress_get(), \"begin\", hourglass_begin, NULL );\n\tg_signal_connect( progress_get(), \"update\", hourglass_update, NULL );\n\tg_signal_connect( progress_get(), \"end\", hourglass_end, NULL );\n}\n\nstatic void\niwindow_init( iWindow *iwnd )\n{\n#ifdef DEBUG\n\tprintf( \"iwindow_init: %s\\n\", iwnd->title );\n#endif /*DEBUG*/\n\n\tiwnd->work = NULL;\n\n\tiwnd->parent = NULL;\n\tiwnd->parent_window = NULL;\n        iwnd->parent_unmap_sid = 0;\n\n\t/* Might as well.\n\t */\n\tiwnd->accel_group = gtk_accel_group_new();\n\tgtk_window_add_accel_group( GTK_WINDOW( iwnd ), iwnd->accel_group );\n\tg_object_unref( iwnd->accel_group );\n\tiwnd->infobar = NULL;\n\n\tiwnd->title = NULL;\n\n\tiwnd->build = NULL;\n\tiwnd->popdown = iwindow_true_cb;\n\n\tiwnd->destroy = FALSE;\n\tiwnd->pending = 0;\n\n\tiwnd->shape = IWINDOW_SHAPE_NONE;\n\tiwnd->contexts = NULL;\n\tiwnd->work_window = NULL;\n\n\tiwnd->width_pref = NULL;\n\tiwnd->height_pref = NULL;\n\n\tiwindow_all = g_slist_prepend( iwindow_all, iwnd );\n}\n\nGtkType\niwindow_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"iWindow\",\n\t\t\tsizeof( iWindow ),\n\t\t\tsizeof( iWindowClass ),\n\t\t\t(GtkClassInitFunc) iwindow_class_init,\n\t\t\t(GtkObjectInitFunc) iwindow_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( GTK_TYPE_WINDOW, &info );\n\t}\n\n\treturn( type );\n}\n\nGtkWidget *\niwindow_new( GtkWindowType type )\n{\n\tiWindow *iwnd = gtk_type_new( TYPE_IWINDOW );\n\tGtkWindow *gwnd = GTK_WINDOW( iwnd );\n\n\t/* Init superclass.\n\t */\n\tgwnd->type = type;\n\n\treturn( GTK_WIDGET( iwnd ) );\n}\n\nvoid \niwindow_set_title( iWindow *iwnd, const char *title, ... )\n{\n\tva_list ap;\n\tchar buf[1024];\n\n        va_start( ap, title );\n        (void) im_vsnprintf( buf, 1024, title, ap );\n        va_end( ap );\n\n\tif( !iwnd->title || strcmp( iwnd->title, buf ) != 0 ) {\n\t\tIM_SETSTR( iwnd->title, buf );\n\t\tgtk_window_set_title( GTK_WINDOW( iwnd ), iwnd->title );\n\t}\n}\n\nvoid \niwindow_set_build( iWindow *iwnd, \n\tiWindowBuildFn build, void *build_a, void *build_b, void *build_c )\n{\n\tiwnd->build = build;\n\tiwnd->build_a = build_a; \n\tiwnd->build_b = build_b; \n\tiwnd->build_c = build_c;\n}\n\nvoid \niwindow_set_popdown( iWindow *iwnd, iWindowFn popdown, void *popdown_a )\n{\n\tiwnd->popdown = popdown;\n\tiwnd->popdown_a = popdown_a;\n}\n\nvoid \niwindow_set_size_prefs( iWindow *iwnd, \n\tconst char *width_pref, const char *height_pref )\n{\n\tiwnd->width_pref = width_pref;\n\tiwnd->height_pref = height_pref;\n}\n\nvoid \niwindow_set_work_window( iWindow *iwnd, GdkWindow *work_window )\n{\n\tiwnd->work_window = work_window;\n\tiwindow_cursor_update( iwnd );\n}\n\nvoid \niwindow_set_parent( iWindow *iwnd, GtkWidget *parent )\n{\n\tg_assert( !iwnd->parent );\n\n\tiwnd->parent = parent;\n\n\t/* Get parent window now, we sometimes need it after parent has been\n\t * destroyed.\n\t */\n\tif( parent )\n\t\tiwnd->parent_window = \n\t\t\tIWINDOW( iwindow_get_root( GTK_WIDGET( parent ) ) );\n}\n\nvoid *\niwindow_kill( iWindow *iwnd )\n{\n#ifdef DEBUG\n\tprintf( \"iwindow_kill: %p %s\\n\", iwnd, iwnd->title );\n#endif /*DEBUG*/\n\n\tif( !iwnd->destroy ) {\n#ifdef DEBUG\n\t\tprintf( \"... starting destroy for %s\\n\", iwnd->title );\n#endif /*DEBUG*/\n\n\t\tiwnd->destroy = TRUE;\n\n\t\t/* Don't kill directly, wait for popdown_notify to do it.\n\t\t */\n\t\tiwindow_notify_send( iwnd, iwnd->popdown, iwnd->popdown_a,\n\t\t\t(iWindowNotifyFn) iwindow_popdown_notify, iwnd );\n\t}\n\n\treturn( NULL );\n}\n\n/* ... as an action.\n */\nvoid\niwindow_kill_action_cb( GtkAction *action, iWindow *iwnd )\n{\n\tiwindow_kill( iwnd );\n}\n\nvoid \niwindow_build( iWindow *iwnd )\n{\n#ifdef DEBUG\n\tprintf( \"iwindow_build: %s\\n\", iwnd->title );\n#endif /*DEBUG*/\n\n\tIWINDOW_GET_CLASS( iwnd )->build( GTK_WIDGET( iwnd ) );\n}\n\n/* Get the enclosing window for a widget.\n */\nGtkWidget *\niwindow_get_root( GtkWidget *widget )\n{\n\tGtkWidget *toplevel = gtk_widget_get_toplevel( widget );\n\tGtkWidget *child = gtk_bin_get_child( GTK_BIN( toplevel ) );\n\n\t/* If this is a menu pane, get the widget that popped this menu up.\n\t */\n\tif( GTK_IS_MENU( child ) ) {\n\t\tGtkWidget *parent = \n\t\t\tgtk_menu_get_attach_widget( GTK_MENU( child ) );\n\n\t\treturn( iwindow_get_root( parent ) );\n\t}\n\telse\n\t\treturn( toplevel );\n}\n\n/* Get the enclosing no-parent window for a widget.\n */\nGtkWidget *\niwindow_get_root_noparent( GtkWidget *widget )\n{\n\tGtkWidget *toplevel = iwindow_get_root( widget );\n\n\t/* If this is a transient, get the window we popped up from.\n\t */\n\tif( IS_IWINDOW( toplevel ) && IWINDOW( toplevel )->parent ) \n\t\treturn( iwindow_get_root_noparent( \n\t\t\tIWINDOW( toplevel )->parent ) );\n\telse\n\t\treturn( toplevel );\n}\n\nvoid\niwindow_alert( GtkWidget *parent, GtkMessageType type )\n{\n\tGtkWidget *toplevel;\n\n\tif( !parent )\n\t\tparent = GTK_WIDGET( mainw_pick_one() );\n\n\tif( parent && \n\t\t(toplevel = iwindow_get_root( parent )) &&\n\t\tIS_IWINDOW( toplevel ) &&\n\t\tIWINDOW( toplevel )->infobar ) \n\t\tinfobar_set( IWINDOW( toplevel )->infobar, type, \n\t\t\terror_get_top(), \"%s\", error_get_sub() );\n\telse \n\t\tswitch( type ) {\n\t\tcase GTK_MESSAGE_INFO:\n\t\t\tbox_info( parent, \n\t\t\t\terror_get_top(), \"%s\", error_get_sub() );\n\t\t\tbreak;\n\n\t\tcase GTK_MESSAGE_ERROR:\n\t\t\tbox_alert( parent );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n}\n\n"
  },
  {
    "path": "src/iwindow.h",
    "content": "/* make and manage windows ... subclass off this for dialog boxes\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#ifndef IWINDOW_H\n#define IWINDOW_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n#define TYPE_IWINDOW (iwindow_get_type())\n#define IWINDOW( obj ) (GTK_CHECK_CAST( (obj), TYPE_IWINDOW, iWindow ))\n#define IWINDOW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_IWINDOW, iWindowClass ))\n#define IS_IWINDOW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_IWINDOW ))\n#define IS_IWINDOW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_IWINDOW ))\n#define IWINDOW_GET_CLASS( obj ) \\\n\t(GTK_CHECK_GET_CLASS( (obj), TYPE_IWINDOW, iWindowClass ))\n\ntypedef struct _iWindow iWindow;\n\n/* Our cursor shapes. \n */\ntypedef enum _iWindowShape {\n\t/* Tool shapes.\n\t */\n\tIWINDOW_SHAPE_DROPPER = 0,\n\tIWINDOW_SHAPE_PEN,\n\tIWINDOW_SHAPE_SMUDGE,\n\tIWINDOW_SHAPE_SMEAR,\n\tIWINDOW_SHAPE_TEXT,\n\tIWINDOW_SHAPE_RECT,\n\tIWINDOW_SHAPE_FLOOD,\n\tIWINDOW_SHAPE_MOVE,\n\tIWINDOW_SHAPE_EDIT,\n\tIWINDOW_SHAPE_MAGIN,\t\n\tIWINDOW_SHAPE_MAGOUT,\t\n\n\t/* Resize shapes.\n\t */\n\tIWINDOW_SHAPE_TOP,\n\tIWINDOW_SHAPE_BOTTOM,\n\tIWINDOW_SHAPE_LEFT,\n\tIWINDOW_SHAPE_RIGHT,\n\tIWINDOW_SHAPE_TOPRIGHT,\n\tIWINDOW_SHAPE_TOPLEFT,\n\tIWINDOW_SHAPE_BOTTOMRIGHT,\n\tIWINDOW_SHAPE_BOTTOMLEFT,\n\n\t/* Watch positions.\n\t */\n\tIWINDOW_SHAPE_HGLASS1,\n\tIWINDOW_SHAPE_HGLASS2,\n\tIWINDOW_SHAPE_HGLASS3,\n\tIWINDOW_SHAPE_HGLASS4,\n\tIWINDOW_SHAPE_HGLASS5,\n\tIWINDOW_SHAPE_HGLASS6,\n\tIWINDOW_SHAPE_HGLASS7,\n\tIWINDOW_SHAPE_HGLASS8,\n\n\t/* No shape set (shape we inherit).\n\t */\n\tIWINDOW_SHAPE_NONE,\n\n\tIWINDOW_SHAPE_LAST\n} iWindowShape;\n\n/* Keep a set of these, one for each of the clients who might want to set the\n * shape for a window.\n */\ntypedef struct {\n\tiWindow *iwnd;\n\tint priority;\t\t\t/* Higher priority == more on top */\n\tconst char *name;\t\t/* For debugging */\n\n\t/* Shape currently requested by this user.\n\t */\n\tiWindowShape shape;\n} iWindowCursorContext;\n\n/* The result from a window/dialog/whatever ... not just a bool.\n */\ntypedef enum iwindow_result {\n\tIWINDOW_ERROR = 0,\t\t/* Tried but failed */\n\tIWINDOW_YES,\t\t\t/* User tried the action */\n\tIWINDOW_NO\t\t\t/* User cancelled */\n} iWindowResult;\n\n/* Our callbacks don't return iWindowResult, instead\n * they are given a notify function (plus an environment parameter) which\n * they use to inform their caller of their iWindowResult.\n */\ntypedef void (*iWindowNotifyFn)( void *, iWindowResult );\n\n/* What our callbacks look like.\n */\ntypedef void (*iWindowFn)( iWindow *, void *, iWindowNotifyFn, void * );\n\n/* Build function for window contents.\n */\ntypedef void (*iWindowBuildFn)( iWindow *, \n\tGtkWidget *, void *, void *, void * );\n\n/* A suspension ... an iWindowFn plus a set of args we are saving for later.\n */\ntypedef struct {\n\tiWindowFn fn;\n\tiWindow *iwnd;\n\tvoid *client;\t\t\t\n\tiWindowNotifyFn nfn;\n\tvoid *sys;\n} iWindowSusp;\n\n#define IWINDOW_SUSP( X ) ((iWindowSusp *) (X))\n\nstruct _iWindow {\n\tGtkWindow parent_object;\n\n\t/* Parent window. Used for (eg.) image displays windows which we need\n\t * to float over the main workspace.\n\t */\n\tGtkWidget *parent;\t\t/* Our parent widget */\n\tiWindow *parent_window;\t\t/* Our parent window */\n\tguint parent_unmap_sid; \t/* Watch parent death here */\n\n\tGtkWidget *work;\n\tGtkAccelGroup *accel_group;\n\tInfobar *infobar;\n\n\tchar *title;\n\n\t/* Action stuff. We init this and add a few common actions to help out\n\t * subclasses.\n\t */\n\tGtkActionGroup *action_group;\n\tGtkUIManager *ui_manager;\n\n\t/* Per instance build function.\n\t */\n\tiWindowBuildFn build;\n\tvoid *build_a, *build_b, *build_c;\n\n\t/* Called before cancellable popdown ... _TRUE from this will \n\t * destroy window, _FALSE won't, _ERROR won't and pops an error box.\n\t */\n\tiWindowFn popdown;\n\tvoid *popdown_a;\n\n\t/* Notify handling.\n\t */\n\tgboolean destroy;\t\t/* True if being destroyed */\n\tint pending;\t\t\t/* Number of notifies waiting on */\n\n\t/* Cursor handling.\n\t */\n\tiWindowShape shape;\t\t/* Global shape ... for hglass */\n\tGSList *contexts;\t\t/* Set of other requested shapes */\n\tGdkWindow *work_window;\t\t/* The window we actually set */\n\n\t/* Size memorization.\n\t */\n\tconst char *width_pref;\t\t/* Prefs we save width/height in */\n\tconst char *height_pref;\n};\n\ntypedef struct _iWindowClass {\n\tGtkWindowClass parent_class;\n\n\t/* Per class build/popdown functions.\n\t */\n\tvoid (*build)( GtkWidget * );\n\tvoid (*popdown)( GtkWidget * );\n\n\t/* Whether windows of this class should be marked as transient for\n\t * their parents (eg. dialogs usually are).\n\t */\n\tgboolean transient;\n} iWindowClass;\n\nint iwindow_number( void );\niWindow *iwindow_pick_one( void );\ntypedef void (*iWindowMapFn)( iWindow *, void * );\nvoid *iwindow_map_all( iWindowMapFn fn, void *a );\n\niWindowCursorContext *iwindow_cursor_context_new( iWindow *, \n\tint, const char * );\nvoid iwindow_cursor_context_set_cursor( iWindowCursorContext *, iWindowShape );\nvoid iwindow_cursor_context_destroy( iWindowCursorContext *cntxt );\n\niWindowSusp *iwindow_susp_new( iWindowFn, \n\tiWindow *, void *, iWindowNotifyFn, void * );\nvoid iwindow_susp_trigger( iWindowSusp * ); \nvoid iwindow_susp_return( void *, iWindowResult );\nvoid iwindow_susp_comp( void *, iWindowResult );\n\nvoid iwindow_notify_send( iWindow *iwnd, \n\tiWindowFn fn, void *client, iWindowNotifyFn back, void *sys );\nvoid iwindow_notify_return( iWindow *iwnd );\n\nvoid iwindow_true_cb( iWindow *, void *, iWindowNotifyFn nfn, void *sys );\nvoid iwindow_false_cb( iWindow *, void *, iWindowNotifyFn nfn, void *sys );\nvoid iwindow_notify_null( void *client, iWindowResult result );\n\nGtkType iwindow_get_type( void );\n\nGtkWidget *iwindow_new( GtkWindowType );\nvoid iwindow_set_title( iWindow *, const char *, ... )\n\t__attribute__((format(printf, 2, 3)));\nvoid iwindow_set_build( iWindow *, iWindowBuildFn, void *, void *, void * );\nvoid iwindow_set_popdown( iWindow *, iWindowFn, void * );\nvoid iwindow_set_size_prefs( iWindow *, const char *, const char * );\nvoid iwindow_set_work_window( iWindow *iwnd, GdkWindow *work_window );\nvoid iwindow_set_parent( iWindow *, GtkWidget *par );\n\nvoid iwindow_build( iWindow * );\nvoid *iwindow_kill( iWindow * );\nvoid iwindow_kill_action_cb( GtkAction *action, iWindow *iwnd );\n\nGtkWidget *iwindow_get_root( GtkWidget *widget );\nGtkWidget *iwindow_get_root_noparent( GtkWidget *widget );\nvoid iwindow_alert( GtkWidget *parent, GtkMessageType type );\n\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n\n#endif /* IWINDOW_H */\n"
  },
  {
    "path": "src/lex.l",
    "content": "%{\n/* Lexer for image processing expressions.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#include \"ip.h\"\n\n#ifdef HAVE_FLEX\n\n/* Flex has a different input mechanism :(\n */\n\n#define YY_INPUT(buf,result,max_size) { \\\n\textern int ip_input( void ); \\\n\tint c = ip_input(); \\\n\tresult = (c == 0) ? YY_NULL : (buf[0] = c, 1); \\\n}\n\n#undef unput\n#define unput ip_unput\n\n#else /*HAVE_FLEX*/\n\n/* Assume this is plain lex.\n */\n\n/* Redefine input, output, unput and yywrap.\n */\n#undef input\n#undef output\n#undef unput\n#undef YYLMAX\n\n/* See parse.y for input and unput.\n */\n#define output(A) (error( \"output called by lex\" ))\n\n#define YYLMAX MAX_STRSIZE\n\n#define unput ip_unput\n#define input ip_input\n#endif /*HAVE_FLEX*/\n\n/* Stuff from bison.\n */\n#include \"parse.h\"\n\n/* Read a string into a buffer. Read up to the \" character, \" can be\n * escaped with '\\'.\n */\nstatic void\nread_string( char *buf )\n{\n\tint ch;\n\tint i;\n\n\t/* Read up to \\n, \", EOF, ignoring \\\"\n\t * Don't forget about \"\\\\\" though.\n\t */\n\tfor( i = 0; (ch = ip_input()); i++ ) {\n\t\tif( ch == EOF || ch == '\\n' || ch == '\"' || ch == '\\0' )\n\t\t\tbreak;\n\t\tif( i >= MAX_STRSIZE )\n\t\t\tyyerror( _( \"line too long\" ) );\n\n\t\tbuf[i] = ch;\n\n\t\tif( ch == '\\\\' ) {\n\t\t\tch = ip_input();\n\n\t\t\tif( ch == EOF || ch == '\\n' || ch == '\\0' )\n\t\t\t\tbreak;\n\t\t\tif( i >= MAX_STRSIZE )\n\t\t\t\tyyerror( _( \"line too long\" ) );\n\n\t\t\tbuf[++i] = ch;\n\t\t}\n\t}\n\tbuf[i] = '\\0';\n\n\tif( ch == '\\n' )\n\t\tyyerror( _( \"end of line inside string\" ) );\n\tif( ch == EOF || ch == '\\0' )\n\t\tyyerror( _( \"no end of string\" ) );\n}\n\n/* Read a char constant. The leading ' has already been seen. Cases to consider:\n * \t'\\n'\n * \t'\\\\'\n * \t'''\t(illegal in C, but I think we allow it)\n * \t'\\''\n */\nstatic int\nread_char( void )\n{\n\tint ch;\n\n\tch = ip_input();\n\n\tif( ch == EOF || ch == '\\n' || ch == '\\0' )\n\t\tyyerror( _( \"bad char constant\" ) );\n\tif( ch == '\\\\' ) {\n\t\tchar buf[3];\n\t\tchar buf2[3];\n\n\t\tbuf[0] = ch;\n\t\tbuf[1] = ch = ip_input();\n\t\tbuf[2] = '\\0';\n\n\t\tif( ch == EOF || ch == '\\n' || ch == '\\0' )\n\t\t\tyyerror( _( \"bad char constant\" ) );\n\n\t\tmy_strccpy( buf2, buf );\n\n\t\tch = buf2[0];\n\t}\n\n\tif( '\\'' != ip_input() )\n\t\tyyerror( _( \"bad char constant\" ) );\n\n\treturn( ch );\n}\n\n\n%}\n\n%Start DOT\n%Start BINARY \n\n%option noyywrap\n%%\n\\/\\* { \n\tint ch;\n\n\twhile( (ch = input()) != EOF )\n\t\tif( ch == '*' ) {\n\t\t\tif( (ch = input()) == '/' )\n\t\t\t\tbreak;\n\t\t\telse\n\t\t\t\tunput( ch );\n\t\t}\n\t\telse if( ch == '/' ) {\n\t\t\tif( (ch = input()) == '*' ) \n\t\t\t\tyyerror( _( \"nested comment\" ) );\n\t\t\telse\n\t\t\t\tunput( ch );\n\t\t}\n\n\tif( ch == EOF )\n\t\tyyerror( _( \"no end of comment\" ) );\n}\n# |\n(\\/\\/) { \n\tint ch;\n\n\t/* Read string up to \\n, EOF.\n\t */\n\twhile( (ch = input()) != EOF && ch != '\\n' && ch != '\\0')\n\t\t;\n}\n\n\\#separator { BEGIN 0; return( TK_SEPARATOR ); }\n\\#dialog { BEGIN 0; return( TK_DIALOG ); }\nclass { BEGIN 0; return( TK_CLASS ); }\nscope { BEGIN 0; return( TK_SCOPE ); }\nchar { BEGIN 0; return( TK_CHAR ); }\nshort { BEGIN 0; return( TK_SHORT ); }\nint { BEGIN 0; return( TK_INT ); }\nfloat { BEGIN 0; return( TK_FLOAT ); }\ndouble { BEGIN 0; return( TK_DOUBLE ); }\nsigned { BEGIN 0; return( TK_SIGNED ); }\nunsigned { BEGIN 0; return( TK_UNSIGNED ); }\ncomplex\t{ BEGIN 0; return( TK_COMPLEX ); }\nif { BEGIN 0; return( TK_IF ); }\nthen { BEGIN 0; return( TK_THEN ); }\nelse { BEGIN 0; return( TK_ELSE ); }\n\\.\\.\\. { BEGIN 0; return( TK_DOTDOTDOT ); }\n\\.\\. { BEGIN 0; return( TK_DOTDOTDOT ); }\n\ntrue |\nTRUE { \t\n\tBEGIN BINARY;\n\n\tyylval.yy_const.type = PARSE_CONST_BOOL;\n\tyylval.yy_const.val.bol = TRUE;\n\n\treturn( TK_CONST );\n}\nfalse |\nFALSE { \t\n\tBEGIN BINARY;\n\n\tyylval.yy_const.type = PARSE_CONST_BOOL;\n\tyylval.yy_const.val.bol = FALSE;\n\n\treturn( TK_CONST );\n}\n\n<DOT>[a-zA-Z_][a-zA-Z0-9_']* {\n\tBEGIN BINARY;\n\n\tyylval.yy_name = im_strdupn( yytext );\n\n\treturn( TK_TAG );\n}\n[a-zA-Z_][a-zA-Z0-9_']* {\n\tchar *name = model_loadstate_rewrite_name( yytext );\n\n\tBEGIN BINARY;\n\n\tif( name ) {\n\t\tyylval.yy_name = im_strdupn( name );\n\t\tvips_buf_change( &lex_text, yytext, name );\n\t}\n\telse \n\t\tyylval.yy_name = im_strdupn( yytext );\n\n\treturn( TK_IDENT );\n}\n\\$[a-zA-Z_][a-zA-Z0-9_']* {\n\tBEGIN BINARY;\n\n\tyylval.yy_const.type = PARSE_CONST_STR;\n\tyylval.yy_const.val.str = im_strdupn( yytext + 1 );\n\n\treturn( TK_CONST );\n}\n\n\\( { BEGIN 0; return( '(' ); }\n\\) { BEGIN BINARY; return( ')' ); }\n\\+\\+ { BEGIN 0; return( TK_JOIN ); }\n\\-\\- { BEGIN 0; return( TK_DIFF ); }\n<BINARY>\\+ |\n<BINARY>\\- { BEGIN 0; return( *yytext ); }\n\\- { BEGIN 0; return( TK_UMINUS ); }\n\\+ { BEGIN 0; return( TK_UPLUS ); }\n\\< { BEGIN 0; return( TK_LESS ); }\n\\<\\= { BEGIN 0; return( TK_LESSEQ ); }\n\\> { BEGIN 0; return( TK_MORE ); }\n\\>\\= { BEGIN 0; return( TK_MOREEQ ); }\n\\=\\> { BEGIN 0; return( TK_TO ); }\n\\& { BEGIN 0; return( TK_BAND ); }\n\\&\\& { BEGIN 0; return( TK_LAND ); }\n\\:\\: { BEGIN 0; return( TK_SUCHTHAT ); }\n\\*\\* { BEGIN 0; return( TK_POW ); }\n\\>\\> { BEGIN 0; return( TK_RSHIFT ); }\n\\<\\< { BEGIN 0; return( TK_LSHIFT ); }\n\\<\\- { BEGIN 0; return( TK_FROM ); }\n\\| { BEGIN 0; return( TK_BOR ); }\n\\|\\| { BEGIN 0; return( TK_LOR ); }\n\\=\\= { BEGIN 0; return( TK_EQ ); }\n\\=\\=\\= { BEGIN 0; return( TK_PEQ ); }\n\\!\\= { BEGIN 0; return( TK_NOTEQ ); }\n\\!\\=\\= { BEGIN 0; return( TK_PNOTEQ ); }\n\\\\ { BEGIN 0; return( TK_LAMBDA ); }\n\\^ |\n\\? |\n\\* |\n\\/ |\n\\% |\n\\, |\n\\! |\n\\; |\n\\[ |\n\\: |\n\\= |\n\\~ |\n\\@ |\n\\{ |\n\\} { BEGIN 0; return( *yytext ); }\n\\. { BEGIN DOT; return( *yytext ); }\n\\] { BEGIN BINARY; return( *yytext ); }\n\n0x[0-9a-fA-F]+ {\n\tunsigned int i;\n\n\tBEGIN BINARY;\n\n\tif( sscanf( yytext, \"0x%x\", &i ) != 1 )\n\t\tnip2yyerror( _( \"bad number %s\" ), yytext );\n\n\tyylval.yy_const.type = PARSE_CONST_NUM;\n\tyylval.yy_const.val.num = i;\n\n\treturn( TK_CONST );\n}\n[0-9]*(\\.[0-9]+)?([eE][+-]?[0-9]+)?[ij]? {\n\tdouble d;\n\tint ch;\n\n\tBEGIN BINARY;\n\n\td = g_ascii_strtod( yytext, NULL );\n\n\tyylval.yy_const.type = PARSE_CONST_NUM;\n\tyylval.yy_const.val.num = d;\n\n\tch = yytext[strlen( yytext ) - 1];\n\tif( ch == 'i' || ch == 'j' )\n\t\tyylval.yy_const.type = PARSE_CONST_COMPLEX;\n\n\treturn( TK_CONST );\n}\n\n\\' {\n\tBEGIN BINARY;\n\n\tyylval.yy_const.type = PARSE_CONST_CHAR;\n\tyylval.yy_const.val.ch = read_char();\n\n\treturn( TK_CONST );\n}\n\\\" { \n\tModelLoadState *state = model_loadstate;\n\n\tchar buf[MAX_STRSIZE];\n\tchar buf2[MAX_STRSIZE];\n\n\tBEGIN BINARY;\n\n\tread_string( buf );\n\n\t/* We need to keep buf as exactly the string in the source, \n\t * including before interpretation of \\ escapes, for the\n\t * vips_buf_change() to work.\n\t */\n\tmy_strccpy( buf2, buf );\n\n\tif( state &&\n\t\tstate->rewrite_path ) {\n\t\tchar buf3[FILENAME_MAX];\n\n\t\tpath_compact( buf2 );\n\n\t\t/* We've interpreted \\n etc. in my_strccpy() above, plus we\n\t\t * have nativised paths from / to \\ and therefore introduced\n\t\t * backslashes that weren't there before.\n\t\t *\n\t\t * Before we write source code out again, we must reescape\n\t\t * everything.\n\t\t */\n\t\tmy_strecpy( buf3, buf2, TRUE );\n\n\t\tvips_buf_change( &lex_text, buf, buf3 );\n\t}\n\n\tif( strcmp( buf2, \"\" ) == 0 ) \n\t\tyylval.yy_const.type = PARSE_CONST_ELIST;\n\telse {\n\t\tyylval.yy_const.type = PARSE_CONST_STR;\n\t\tyylval.yy_const.val.str = im_strdupn( buf2 );\n\t}\n\n\treturn( TK_CONST );\n}\n\n[ \\t\\n\\r\\m\\01] ;\n\n. {\n\tnip2yyerror( _( \"illegal character \\\"%c\\\"\" ), *yytext );\n}\n"
  },
  {
    "path": "src/link.c",
    "content": "/* Links between top-level syms and the exprs which reference them\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n#define DEBUG_DIRTY\n */\n\n#include \"ip.h\"\n\nvoid *\nlink_expr_destroy( LinkExpr *le )\n{\n\tGSList **llinks = le->dynamic ? &le->link->dynamic_links : \n\t\t&le->link->static_links;\n\tGSList **elinks = le->dynamic ? &le->expr->dynamic_links : \n\t\t&le->expr->static_links;\n\n#ifdef DEBUG\n\tprintf( \"link_expr_destroy: removing expr \" );\n\tsymbol_name_print( le->expr->sym );\n\tprintf( \"referencing link->child = \" );\n\tsymbol_name_print( le->link->child );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t*llinks = slist_remove_all( *llinks, le );\n\t*elinks = slist_remove_all( *elinks, le );\n\n        im_free( le );\n\n\treturn( NULL );\n}\n\nstatic LinkExpr *\nlink_expr_new( Link *link, Expr *expr, gboolean dynamic )\n{\n\tGSList **llinks = dynamic ? &link->dynamic_links : &link->static_links;\n\tGSList **elinks = dynamic ? &expr->dynamic_links : &expr->static_links;\n        LinkExpr *le;\n\n\tg_assert( expr_get_root_dynamic( expr )->sym == link->parent );\n\n#ifdef DEBUG\n\tprintf( \"link_expr_new: expr \" );\n\tsymbol_name_print( expr->sym );\n\tprintf( \"references link->child = \" );\n\tsymbol_name_print( link->child );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n        if( !(le = INEW( NULL, LinkExpr )) )\n\t\treturn( NULL );\n\n        le->link = link; \n        le->expr = expr; \n        le->count = 1; \n        le->dynamic = dynamic; \n\n\t*llinks = g_slist_prepend( *llinks, le );\n\t*elinks = g_slist_prepend( *elinks, le );\n\n        return( le );\n}\n\n/* Make a new serial number.\n */\nint\nlink_serial_new( void )\n{\n\tstatic int serial = 0;\n\n\treturn( serial++ );\n}\n\n/* Fwd ref. \n */\nstatic void *symbol_dirty_set( Symbol *sym );\n\n/* child has become dirty ... update parent's dirty count.\n */\nstatic void *\nlink_dirty_child( Link *link )\n{\n\tg_assert( link->parent->ndirtychildren >= 0 );\n\n\tlink->parent->ndirtychildren += 1;\n\n\tif( link->parent->ndirtychildren == 1 ) \n\t\t/* Parent had no dirty children ... it does now.\n\t\t */\n\t\tsymbol_dirty_set( link->parent );\n\n\tsymbol_state_change( link->parent );\n\n\treturn( NULL );\n}\n\n/* link->parent no longer has link->child as a dirty child (cleaned or\n * removed) ... update counts.\n */\nstatic void *\nlink_clean_child( Link *link )\n{\n\tSymbol *parent = link->parent;\n\n\t/* One fewer dirty children!\n\t */\n\tparent->ndirtychildren--;\n\tg_assert( parent->ndirtychildren >= 0 );\n\n\t/* Have we just cleaned the last dirty child of link->parent? If we\n\t * have and if link->parent has an error, clear the error so that\n\t * link->parent gets a chance to recalc. The new value of\n\t * link->child might fix the problem.\n\t */\n\tif( parent->ndirtychildren == 0 ) \n\t\texpr_error_clear( parent->expr );\n\n\tsymbol_state_change( parent );\n\n\treturn( NULL );\n}\n\n/* Junk a link.\n */\nvoid *\nlink_destroy( Link *link )\n{\n#ifdef DEBUG\n\tprintf( \"link_destroy: destroying link from \" );\n\tsymbol_name_print( link->parent );\n\tprintf( \"to \" );\n\tsymbol_name_print( link->child );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( link->child->dirty )\n\t\t(void) link_clean_child( link );\n\n\tlink->parent->topchildren = \n\t\tslist_remove_all( link->parent->topchildren, link );\n\tlink->child->topparents = \n\t\tslist_remove_all( link->child->topparents, link );\n\tslist_map( link->static_links, \n\t\t(SListMapFn) link_expr_destroy, NULL );\n\tslist_map( link->dynamic_links, \n\t\t(SListMapFn) link_expr_destroy, NULL );\n\n        im_free( link );\n\n\treturn( NULL );\n}\n\n/* Make a new link.\n */\nstatic Link *\nlink_new( Symbol *child, Symbol *parent )\n{\n        Link *link;\n\n\tg_assert( is_top( parent ) && is_top( child ) );\n\tg_assert( parent != child );\n\n#ifdef DEBUG\n\tprintf( \"link_new: making link from \" );\n\tsymbol_name_print( parent );\n\tprintf( \"to \" );\n\tsymbol_name_print( child );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n        if( !(link = INEW( NULL, Link )) )\n\t\treturn( NULL );\n\n        link->parent = parent; \n        link->child = child; \n        link->serial = 0; \n        link->static_links = NULL; \n        link->dynamic_links = NULL; \n\n\tparent->topchildren = g_slist_prepend( parent->topchildren, link );\n\tchild->topparents = g_slist_prepend( child->topparents, link );\n\n\t/* If the new child is dirty, note it.\n\t */\n\tif( child->dirty )\n\t\tlink_dirty_child( link );\n\n        return( link );\n}\n\nstatic Link *\nlink_find_child_sub( Link *link, Symbol *child )\n{\n\tif( link->child == child )\n\t\treturn( link );\n\n\treturn( NULL );\n}\n\n/* Look up connection between child and parent.\n */\nstatic Link *\nlink_find_child( Symbol *child, Symbol *parent )\n{\n\treturn( (Link *) slist_map( parent->topchildren,\n\t\t(SListMapFn) link_find_child_sub, child ) );\n}\n\nstatic void *\nlink_expr_find_expr_sub( LinkExpr *le, Expr *expr )\n{\n\tif( le->expr == expr )\n\t\treturn( le );\n\n\treturn( NULL );\n}\n\n/* Look up a linkexpr by expr.\n */\nstatic LinkExpr *\nlink_expr_find_expr( Link *link, Expr *expr, gboolean dynamic )\n{\n\tGSList *links = dynamic ? link->dynamic_links : link->static_links;\n\n\treturn( (LinkExpr *) slist_map( links,\n\t\t(SListMapFn) link_expr_find_expr_sub, expr ) );\n}\n\n/* Add a reference from expr to child to the link graph.\n */\nvoid *\nlink_add( Symbol *child, Expr *expr, gboolean dynamic )\n{\n\tExpr *parent = expr_get_root_dynamic( expr );\n\tLink *link;\n\tLinkExpr *le;\n\n#ifdef DEBUG\n\tprintf( \"link_add: child = \" );\n\tsymbol_name_print( child );\n\tprintf( \"; expr = \" );\n\texpr_name_print( expr );\n\tprintf( \"; dynamic = %s\\n\", bool_to_char( dynamic ) );\n#endif /*DEBUG*/\n\n\tg_assert( parent );\n\tg_assert( parent->sym );\n\tg_assert( is_top( child ) && is_top( parent->sym ) );\n\tg_assert( child != parent->sym );\n\n\tif( !(link = link_find_child( child, parent->sym )) ) {\n\t\tif( !(link = link_new( child, parent->sym )) )\n\t\t\treturn( child );\n\t}\n\n\tif( !(le = link_expr_find_expr( link, expr, dynamic )) ) {\n\t\tif( !(le = link_expr_new( link, expr, dynamic )) )\n\t\t\treturn( child );\n\t}\n\telse\n\t\tle->count++;\n\n\treturn( NULL );\n}\n\n/* Remove a ref from expr to child.\n */\nvoid *\nlink_remove( Symbol *child, Expr *expr, gboolean dynamic )\n{\n\tSymbol *parent = expr_get_root_dynamic( expr )->sym;\n\tLink *link = link_find_child( child, parent );\n\tLinkExpr *le = link_expr_find_expr( link, expr, dynamic );\n\n\tg_assert( is_top( parent ) && is_top( child ) );\n\tg_assert( parent != child );\n\tg_assert( link );\n\n\tle->count--;\n\tif( le->count == 0 ) {\n\t\tif( link_expr_destroy( le ) )\n\t\t\treturn( child );\n\t}\n\tif( !link->static_links && !link->dynamic_links ) {\n\t\tif( link_destroy( link ) )\n\t\t\treturn( child );\n\t}\n\n\treturn( NULL );\n}\n\n/* Is this a ref to a top-level? Add to link graph if it is.\n */\nstatic void *\nlink_children_expr_sub( Symbol *child, Expr *expr )\n{\n\tif( is_top( child ) ) {\n\t\tExpr *root = expr_get_root_dynamic( expr );\n\n\t\t/* Don't need to record recursive refs.\n\t\t */\n\t\tif( root && root->sym && root->sym != child ) {\n\t\t\tif( link_add( child, expr, FALSE ) )\n\t\t\t\treturn( child );\n\t\t}\n\t}\n\n\treturn( NULL );\n}\n\n/* Fwd.\n */\nstatic void *link_children( Symbol *child, Symbol *parent );\n\n/* Add any refs to top-level syms within this local to the\n * top-level sym we are within.\n */\nstatic void *\nlink_children_expr( Expr *expr, Symbol *parent )\n{\n\tif( expr->compile ) {\n\t\tCompile *compile = expr->compile;\n\n\t\t/* Add refs which local makes directly.\n\t\t */\n\t\tif( slist_map( compile->children, \n\t\t\t(SListMapFn) link_children_expr_sub, expr ) )\n\t\t\treturn( expr );\n\n\t\t/* ... and recurse for sub-children.\n\t\t */\n\t\t(void) icontainer_map( ICONTAINER( compile ),\n\t\t\t(icontainer_map_fn) link_children, parent, NULL );\n\t}\n\n        return( NULL );\n}\n\n/* Add any refs to top-level syms within this local to the\n * top-level sym we are within.\n */\nstatic void *\nlink_children( Symbol *child, Symbol *parent )\n{\n        if( child->expr ) {\n\t\tif( link_children_expr( child->expr, parent ) )\n\t\t\treturn( child );\n\t}\n\n        return( NULL );\n}\n\n/* row is editing sym's value ... add any dependancies the user has included\n * there.\n */\nstatic void *\nlink_row( Model *model, Symbol *parent )\n{\n\tif( !IS_ROW( model ) || !ROW( model )->expr ) \n\t\treturn( NULL );\n\n        /* Add any stuff in this row.\n         */\n        return( link_children_expr( ROW( model )->expr, parent ) );\n}\n\nstatic void *\nsymbol_ndirty_sub( Link *link, int *nd )\n{\n\tif( link->child->dirty )\n\t\t*nd += 1;\n\n\treturn( NULL );\n}\n\n/* Count the number of dirty children. Used to generate initial leaf counts\n * and for assert() checking.\n */\nint\nsymbol_ndirty( Symbol *sym )\n{\n\tint nd = 0;\n\n\t(void) slist_map( sym->topchildren, \n\t\t(SListMapFn) symbol_ndirty_sub, &nd );\n\n\treturn( nd );\n}\n\n/* Fix a leaf count. \n */\nvoid *\nsymbol_fix_counts( Symbol *sym )\n{\n#ifdef DEBUG\n\tint old_count = sym->ndirtychildren;\n#endif /*DEBUG*/\n\n\tsym->ndirtychildren = symbol_ndirty( sym );\n\n#ifdef DEBUG\n\tg_assert( sym->ndirtychildren == old_count );\n#endif /*DEBUG*/\n\n\tsymbol_state_change( sym );\n\n\treturn( NULL );\n}\n\n/* Junk all old links, static + dynamic.\n */\nvoid\nsymbol_link_destroy( Symbol *sym )\n{\n\t(void) slist_map( sym->topchildren, (SListMapFn) link_destroy, NULL );\n}\n\n/* Scan a symbol, remaking all the links.\n */\nvoid\nsymbol_link_build( Symbol *sym )\n{\n\tg_assert( is_top( sym ) );\n\n        /* Make static links for our expr and all subexprs. If this symbol \n\t * is being edited, get stuff from the edited value.\n         */\n        if( sym->expr ) {\n\t\tif( sym->expr->row )\n\t\t\t(void) icontainer_map_all( \n\t\t\t\tICONTAINER( sym->expr->row ), \n\t\t\t\t(icontainer_map_fn) link_row, sym );\n\t\telse\n\t\t\t(void) link_children_expr( sym->expr, sym );\n\t}\n\n#ifdef DEBUG\n\tprintf( \"symbol_link_build: \" );\n\tsymbol_name_print( sym );\n\tprintf( \"\\n\" );\n\tdump_links( sym );\n#endif /*DEBUG*/\n\n}\n\nstatic void *\nlink_dirty_set_sub( LinkExpr *le, int serial )\n{\n\treturn( expr_dirty( le->expr, serial ) );\n}\n\n/* Mark exprs in parent dirty. These may be sub exprs, so parent is not\n * necessarily going to be symbol_dirty_set() ... eg. A2 may be displaying an\n * instance of class \"fred\", and we might have edited one of A2's members to\n * refer to A1 ... but A2 depends on A1, fred does not.\n */\nstatic void *\nlink_dirty_set( Link *link, int serial )\n{\n\t/* Mark exprs in parent dirty.\n\t */\n\tif( slist_map( link->static_links, \n\t\t(SListMapFn) link_dirty_set_sub, GINT_TO_POINTER( serial ) ) ||\n\t    slist_map( link->dynamic_links, \n\t    \t(SListMapFn) link_dirty_set_sub, GINT_TO_POINTER( serial ) ) )\n\t\treturn( link );\n\n\treturn( NULL );\n}\n\n/* Walk the link graph, marking stuff for recomputation ... link->child has\n * changed, mark link->parent dirty.\n */\nstatic void *\nlink_dirty_walk( Link *link, int serial )\n{\n\t/* Have we walked down this link before? \n\t */\n\tif( link->serial == serial )\n\t\treturn( NULL );\n\tlink->serial = serial;\n\n\t/* Mark all exprs in parent dirty.\n\t */\n\treturn( link_dirty_set( link, serial ) );\n}\n\n/* A symbol has changed ... walk the link graph, marking stuff dirty as\n * required. We don't mark this sym dirty.\n */\nvoid *\nsymbol_dirty_intrans( Symbol *sym, int serial )\n{\n\tg_assert( is_top( sym ) );\n\n\treturn( slist_map( sym->topparents, \n\t\t(SListMapFn) link_dirty_walk, GINT_TO_POINTER( serial ) ) );\n}\n\nstatic void *\nsymbol_dirty_set( Symbol *sym )\n{\n\tg_assert( is_top( sym ) );\n\n\t/* Clear error, to make sure we will recomp it.\n\t */\n\tif( sym->expr )\n\t\texpr_error_clear( sym->expr );\n\n\tif( !sym->dirty ) {\n#ifdef DEBUG_DIRTY\n\t\tprintf( \"symbol_dirty_set: \" );\n\t\tsymbol_name_print( sym );\n\t\tprintf( \"(%p)\\n\", sym );\n#endif /*DEBUG_DIRTY*/\n\n\t\t/* Change of state.\n\t\t */\n\t\tsym->dirty = TRUE;\n\n\t\t/* Update dirty counts on our parents.\n\t\t */\n\t\t(void) slist_map( sym->topparents,\n\t\t\t(SListMapFn) link_dirty_child, NULL );\n\n\t\t/* Note change in leaf set and display.\n\t\t */\n\t\tsymbol_state_change( sym );\n\t}\n\n\treturn( NULL );\n}\n\n/* ... mark this one as well.\n */\nvoid *\nsymbol_dirty( Symbol *sym, int serial )\n{\n\tg_assert( is_top( sym ) );\n\n\tsymbol_dirty_set( sym );\n\n\treturn( symbol_dirty_intrans( sym, serial ) );\n}\n\nvoid *\nlink_dirty_total( Link *link, int serial )\n{\n\tstatic int recursion_depth = 0;\n\n\t/* Entering: note new recursion.\n\t */\n\tif( recursion_depth++ > 1000 ) {\n\t\terror_top( _( \"Circular dependency.\" ) );\n\t\terror_sub( _( \"Circular dependency detected near \"\n\t\t\t\"symbol \\\"%s\\\".\" ),\n\t\t\tIOBJECT( link->parent )->name );\n\t\trecursion_depth = 0;\n\t\treturn( link );\n\t}\n\n\t/* Mark this sub-tree as dirty.\n\t */\n\tsymbol_dirty( link->child, serial );\n\n\t/* ... and repeat for any parents.\n\t */\n\tif( link->child->type != SYM_ZOMBIE )\n\t\tif( slist_map( link->child->topchildren, \n\t\t\t(SListMapFn) link_dirty_total, \n\t\t\t\tGINT_TO_POINTER( serial ) ) )\n\t\t\treturn( link );\n\n\t/* Pop recursion measure.\n\t */\n\trecursion_depth--;\n\n\treturn( NULL );\n}\n\n/* As above, but mark children as dirty as well. Used by force recalc to make\n * sure that everything is completely rebuilt. Be careful of cycles!\n */\nvoid *\nsymbol_dirty_total( Symbol *sym, int serial )\n{\n\tif( sym->type == SYM_ZOMBIE )\n\t\treturn( NULL );\n\n\t/* No children: just mark this sub-tree as dirty.\n\t */\n\tif( !sym->topchildren && symbol_dirty( sym, serial ) )\n\t\treturn( sym );\n\n\tif( slist_map( sym->topchildren, \n\t\t(SListMapFn) link_dirty_total, GINT_TO_POINTER( serial ) ) )\n\t\treturn( sym );\n\n\treturn( NULL );\n}\n\n/* Mark a symbol as clean. Knock down the leaf count of the things which refer\n * to us ... one of them may turn into a leaf as a result.\n */\nvoid *\nsymbol_dirty_clear( Symbol *sym )\n{\n\tg_assert( is_top( sym ) );\n\n\tif( sym->dirty ) {\n#ifdef DEBUG_DIRTY\n\t\tprintf( \"symbol_dirty_clear: \" );\n\t\tsymbol_name_print( sym );\n\t\tprintf( \"(%p)\\n\", sym );\n#endif /*DEBUG_DIRTY*/\n\n\t\t/* Change of state.\n\t\t */\n\t\tsym->dirty = FALSE;\n\t\tsymbol_state_change( sym );\n\n\t\t/* Update dirty counts on our parents.\n\t\t */\n\t\t(void) slist_map( sym->topparents,\n\t\t\t(SListMapFn) link_clean_child, NULL );\n\t}\n\n\treturn( NULL );\n}\n"
  },
  {
    "path": "src/link.h",
    "content": "/* Links between top-level syms and the exprs which reference them\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n/* A sub-link ... the expr in parent that actually references child, plus\n * the number of times it makes the reference.\n */\nstruct _LinkExpr {\n\tLink *link;\t\t/* Link we are part of */\n\n\tExpr *expr;\t\t/* Expr that references child */\n\tint count;\t\t/* Number of times expr references child */\n\tgboolean dynamic;\t/* True for dynamic link */\n};\n\n/* A link object!\n */\nstruct _Link {\n\tSymbol *parent;\t\t/* This top-level symbol contains exprs ... */\n\tSymbol *child;\t\t/* ... which reference this symbol */\n\n\t/* Link serial number ... when we walk the symbol graph marking\n\t * stuff dirty, use this to stop repeat trips along links, and\n\t * avoid getting stuck in cycles.\n\t */\n\tint serial;\n\n\t/* The expressions inside parent which contain direct references to\n\t * child. If parent is in the tally, there can be lots of these.\n\t *\n\t * Two sort of links: static links, which we can deduce from\n\t * compile-time analysis of the expr and which only change when\n\t * the user edits and we recompile, and dynamic links which we\n\t * clear when we regenerate the heap image of the function, and add\n\t * to during evaluation.\n\t */\n\tGSList *static_links;\n\tGSList *dynamic_links;\n};\n\nvoid *link_expr_destroy( LinkExpr *le );\nvoid *link_destroy( Link *link );\nvoid *link_add( Symbol *child, Expr *expr, gboolean dynamic );\nvoid *link_remove( Symbol *child, Expr *expr, gboolean dynamic );\n\nint symbol_ndirty( Symbol *sym );\nvoid *symbol_fix_counts( Symbol *sym );\nvoid symbol_link_destroy( Symbol *sym );\nvoid symbol_link_build( Symbol *sym );\n\nint link_serial_new( void );\nvoid *symbol_dirty_intrans( Symbol *sym, int serial );\nvoid *symbol_dirty( Symbol *sym, int serial );\nvoid *symbol_dirty_total( Symbol *sym, int serial );\n\nvoid *symbol_dirty_clear( Symbol *sym );\n"
  },
  {
    "path": "src/log",
    "content": "workspacegroupview_switch_page_cb: 0 moving tab\n\nview_model_child_remove: child Workspace \"test\"; parent Workspacegroup \"(null)\"\nview_model_child_remove: parent_view = view of Workspacegroup \"(null)\"\nview_viewchild_test_child_model: model Workspace \"test\"\nview_viewchild_destroy: view Workspacegroupview watching model Workspace\n\nworkspacegroupview_switch_page_cb: 0 about to add\n\nview_model_child_add: parent Workspacegroup \"tab1\"\nview_viewchild_test_child_model: model Workspace \"test\"\nview_viewchild_new: view \"Workspacegroupview\" watching Workspace \"test\"\nview_viewchild_changed: Workspace \"test\", adding view\nview_real_link: linking Workspaceview to model Workspace \"test\"\nview_real_child_add: parent Workspacegroupview, child Workspaceview\nview_viewchild_test_child_model: model Workspace \"test\"\nview_viewchild_test_child_model: model Workspace \"test\"\nview_viewchild_new: view \"Workspaceview\" watching Column \"B\"\nview_viewchild_changed: Column \"B\", adding view\nview_real_link: linking Columnview to model Column \"B\"\nview_real_child_add: parent Workspaceview, child Columnview\nview_viewchild_test_child_model: model Column \"B\"\nview_viewchild_new: view \"Columnview\" watching Subcolumn \"(null)\"\nview_viewchild_changed: Subcolumn \"(null)\", adding view\nview_real_link: linking Subcolumnview to model Subcolumn \"(null)\"\nview_real_child_add: parent Columnview, child Subcolumnview\nview_viewchild_test_child_model: model Subcolumn \"(null)\"\nview_viewchild_new: view \"Subcolumnview\" watching Row \"B1\"\nview_viewchild_changed: Row \"B1\", adding view\nview_real_link: linking Rowview to model Row \"B1\"\nview_real_child_add: parent Subcolumnview, child Rowview\nview_viewchild_test_child_model: model Row \"B1\"\nview_viewchild_new: view \"Rowview\" watching Rhs \"(null)\"\nview_viewchild_changed: Rhs \"(null)\", adding view\nview_real_link: linking Rhsview to model Rhs \"(null)\"\nview_real_child_add: parent Rowview, child Rhsview\nview_viewchild_test_child_model: model Rhs \"(null)\"\nview_viewchild_new: view \"Rhsview\" watching iImage \"Image\"\nview_viewchild_changed: iImage \"Image\", adding view\nview_real_link: linking iImageview to model iImage \"Image\"\nview_real_child_add: parent Rhsview, child iImageview\nview_viewchild_test_child_model: model iImage \"Image\"\nview_viewchild_new: view \"Rhsview\" watching Subcolumn \"(null)\"\nview_viewchild_changed: Subcolumn \"(null)\", adding view\nview_real_link: linking Subcolumnview to model Subcolumn \"(null)\"\nview_real_child_add: parent Rhsview, child Subcolumnview\nview_viewchild_test_child_model: model Subcolumn \"(null)\"\nview_viewchild_test_child_model: model Subcolumn \"(null)\"\nview_viewchild_new: view \"Rhsview\" watching iText \"(null)\"\nview_viewchild_changed: iText \"(null)\", adding view\nview_real_link: linking iTextview to model iText \"(null)\"\nview_real_child_add: parent Rhsview, child iTextview\nview_viewchild_test_child_model: model iText \"(null)\"\nview_viewchild_test_child_model: model iText \"(null)\"\nview_viewchild_test_child_model: model iText \"(null)\"\nview_viewchild_new: view \"Workspaceview\" watching Column \"A\"\nview_viewchild_changed: Column \"A\", adding view\nview_real_link: linking Columnview to model Column \"A\"\nview_real_child_add: parent Workspaceview, child Columnview\nview_viewchild_test_child_model: model Column \"A\"\nview_viewchild_test_child_model: model Column \"A\"\nview_viewchild_new: view \"Columnview\" watching Subcolumn \"(null)\"\nview_viewchild_changed: Subcolumn \"(null)\", adding view\nview_real_link: linking Subcolumnview to model Subcolumn \"(null)\"\nview_real_child_add: parent Columnview, child Subcolumnview\nview_viewchild_test_child_model: model Subcolumn \"(null)\"\nview_viewchild_new: view \"Subcolumnview\" watching Row \"A1\"\nview_viewchild_changed: Row \"A1\", adding view\nview_real_link: linking Rowview to model Row \"A1\"\nview_real_child_add: parent Subcolumnview, child Rowview\nview_viewchild_test_child_model: model Row \"A1\"\nview_viewchild_new: view \"Rowview\" watching Rhs \"(null)\"\nview_viewchild_changed: Rhs \"(null)\", adding view\nview_real_link: linking Rhsview to model Rhs \"(null)\"\nview_real_child_add: parent Rowview, child Rhsview\nview_viewchild_test_child_model: model Rhs \"(null)\"\nview_viewchild_new: view \"Rhsview\" watching iText \"(null)\"\nview_viewchild_changed: iText \"(null)\", adding view\nview_real_link: linking iTextview to model iText \"(null)\"\nview_real_child_add: parent Rhsview, child iTextview\nview_viewchild_test_child_model: model iText \"(null)\"\nview_viewchild_new: view \"Subcolumnview\" watching Row \"A2\"\nview_viewchild_changed: Row \"A2\", adding view\nview_real_link: linking Rowview to model Row \"A2\"\nview_real_child_add: parent Subcolumnview, child Rowview\nview_viewchild_test_child_model: model Row \"A2\"\nview_viewchild_test_child_model: model Row \"A2\"\nview_viewchild_new: view \"Rowview\" watching Rhs \"(null)\"\nview_viewchild_changed: Rhs \"(null)\", adding view\nview_real_link: linking Rhsview to model Rhs \"(null)\"\nview_real_child_add: parent Rowview, child Rhsview\nview_viewchild_test_child_model: model Rhs \"(null)\"\nview_viewchild_new: view \"Rhsview\" watching iText \"(null)\"\nview_viewchild_changed: iText \"(null)\", adding view\nview_real_link: linking iTextview to model iText \"(null)\"\nview_real_child_add: parent Rhsview, child iTextview\nview_viewchild_test_child_model: model iText \"(null)\"\nview_viewchild_new: view \"Subcolumnview\" watching Row \"A3\"\nview_viewchild_changed: Row \"A3\", adding view\nview_real_link: linking Rowview to model Row \"A3\"\nview_real_child_add: parent Subcolumnview, child Rowview\nview_viewchild_test_child_model: model Row \"A3\"\nview_viewchild_test_child_model: model Row \"A3\"\nview_viewchild_test_child_model: model Row \"A3\"\nview_viewchild_new: view \"Rowview\" watching Rhs \"(null)\"\nview_viewchild_changed: Rhs \"(null)\", adding view\nview_real_link: linking Rhsview to model Rhs \"(null)\"\nview_real_child_add: parent Rowview, child Rhsview\nview_viewchild_test_child_model: model Rhs \"(null)\"\nview_viewchild_new: view \"Rhsview\" watching iText \"(null)\"\nview_viewchild_changed: iText \"(null)\", adding view\nview_real_link: linking iTextview to model iText \"(null)\"\nview_real_child_add: parent Rhsview, child iTextview\nview_viewchild_test_child_model: model iText \"(null)\"\nworkspacegroupview_switch_page_cb: 0 tab move done\nview_model_front: test\n\n"
  },
  {
    "path": "src/log.c",
    "content": "/* Abstract base class for a log window: errors, link report, log, etc.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n/* Send log to stdout as well\n#define DEBUG_FILE\n */\n\n#include \"ip.h\"\n\nstatic iWindowClass *parent_class = NULL;\n\nstatic void\nlog_build( GtkWidget *widget ) \n{\n\tLog *log = LOG( widget );\n\tiWindow *iwnd = IWINDOW( widget );\n\tLogClass *log_class = LOG_GET_CLASS( log );\n\n\tGError *error;\n\tGtkWidget *mbar;\n\n\tGtkWidget *swin;\n\tPangoFontDescription *font_desc;\n\n\tIWINDOW_CLASS( parent_class )->build( widget );\n\n\tgtk_action_group_add_actions( iwnd->action_group, \n\t\tlog_class->actions, log_class->n_actions, \n\t\tGTK_WINDOW( log ) );\n\tgtk_action_group_add_toggle_actions( iwnd->action_group, \n\t\tlog_class->toggle_actions, log_class->n_toggle_actions, \n\t\tGTK_WINDOW( log ) );\n\n\tif( !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager,\n\t\tlog_class->ui_description, -1, &error ) ) {\n\t\tg_message( \"building menus failed: %s\", error->message );\n\t\tg_error_free( error );\n\t\texit( EXIT_FAILURE );\n\t}\n\n\tmbar = gtk_ui_manager_get_widget( iwnd->ui_manager, \n\t\tlog_class->menu_bar_name );\n\tgtk_box_pack_start( GTK_BOX( iwnd->work ), mbar, FALSE, FALSE, 0 );\n        gtk_widget_show( mbar );\n\n\tswin = gtk_scrolled_window_new( NULL, NULL );\n\tgtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ),\n\t\tGTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );\n\tgtk_box_pack_start( GTK_BOX( iwnd->work ), swin, TRUE, TRUE, 0 );\n\tgtk_widget_show( swin );\n\n\tlog->view = gtk_text_view_new();\n\tgtk_text_view_set_editable( GTK_TEXT_VIEW( log->view ), FALSE );\n\tgtk_text_view_set_cursor_visible( GTK_TEXT_VIEW( log->view ), \n\t\tFALSE );\n\tfont_desc = pango_font_description_from_string( \"Monospace\" );\n\tgtk_widget_modify_font( log->view, font_desc );\n\tpango_font_description_free( font_desc );\n\n\tgtk_container_add( GTK_CONTAINER( swin ), log->view );\n\tgtk_widget_show( log->view );\n}\n\nstatic void\nlog_class_init( LogClass *class )\n{\n\tiWindowClass *iwindow_class = (iWindowClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tiwindow_class->build = log_build;\n\n\tclass->actions = NULL;\n\tclass->n_actions = 0;\n\tclass->toggle_actions = NULL;\n\tclass->n_toggle_actions = 0;\n\tclass->action_name = NULL;\n\tclass->ui_description = NULL;\n\tclass->menu_bar_name = NULL;\n}\n\nstatic void\nlog_init( Log *log )\n{\n}\n\nGtkType\nlog_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Log\",\n\t\t\tsizeof( Log ),\n\t\t\tsizeof( LogClass ),\n\t\t\t(GtkClassInitFunc) log_class_init,\n\t\t\t(GtkObjectInitFunc) log_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_IWINDOW, &info );\n\t}\n\n\treturn( type );\n}\n\nvoid\nlog_clear_action_cb( GtkAction *action, Log *log )\n{\n\tGtkTextView *text_view = GTK_TEXT_VIEW( log->view );\n\tGtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view );\n\n\tgtk_text_buffer_set_text( text_buffer, \"\", 0 );\n}\n\nvoid\nlog_text( Log *log, const char *buf )\n{\n\tGtkTextView *text_view = GTK_TEXT_VIEW( log->view );\n\tGtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view );\n\tGtkTextMark *mark = gtk_text_buffer_get_insert( text_buffer );\n\tGtkTextIter iter;\n\n\tgtk_text_buffer_get_end_iter( text_buffer, &iter );\n\tgtk_text_buffer_move_mark( text_buffer, mark, &iter );\n\tgtk_text_buffer_insert_at_cursor( text_buffer, buf, -1 );\n\tgtk_text_view_scroll_to_mark( text_view, mark, \n\t\t0.0, TRUE, 0.5, 1 );\n\n#ifdef DEBUG_FILE\n\tprintf( \"%s\", buf );\n#endif \n}\n\nvoid\nlog_textf( Log *log, const char *fmt, ... )\n{\n\tva_list ap;\n \tchar buf[MAX_STRSIZE];\n\n        va_start( ap, fmt );\n        (void) im_vsnprintf( buf, MAX_STRSIZE, fmt, ap );\n        va_end( ap );\n\n\tlog_text( log, buf );\n}\n"
  },
  {
    "path": "src/log.h",
    "content": "/* Abstract base class for a log window: errors, link report, log, etc.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_LOG (log_get_type())\n#define LOG( obj ) (G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_LOG, Log ))\n#define LOG_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_LOG, LogClass))\n#define IS_LOG( obj ) (G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_LOG ))\n#define IS_LOG_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_LOG ))\n#define LOG_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_LOG, LogClass ))\n\nstruct _Log {\n\tiWindow parent_class;\n\n\tGtkWidget *view;\t/* The textview we use to show the log */\n};\n\ntypedef struct _LogClass {\n\tiWindowClass parent_class;\n\n\t/* How we want the menu bar built.\n\t */\n\tGtkActionEntry *actions;\n\tint n_actions;\n\tGtkToggleActionEntry *toggle_actions;\n\tint n_toggle_actions;\n\tconst char *action_name;\n\tconst char *ui_description;\n\tconst char *menu_bar_name;\n} LogClass;\n\nGtkType log_get_type( void );\n\nvoid log_clear_action_cb( GtkAction *action, Log *log );\nvoid log_text( Log *log, const char *buf );\nvoid log_textf( Log *log, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\n"
  },
  {
    "path": "src/main.c",
    "content": "/* main() ... start everything up. See mainw.c for main window stuff.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* \n#define DEBUG\n */\n\n/* Show all paint actions with flashing stuff.\n#define DEBUG_UPDATES\n */\n\n/* Stop startup creation of externs for all VIPS functions etc.\n#define DEBUG_NOAUTO\n */\n\n/* Stop on any gtk error/warning/whatever. Usually set by configure for dev\n * builds. \n#define DEBUG_FATAL\n */\n\n/* But some themes can trigger warnings, argh, so sometimes we need to\n * undef it. VipsObject sets can trigger warnings. libgoffice will warn about\n * precision issues if run under valgrind.\n */\n#undef DEBUG_FATAL\n\n/* Time startup.\n#define DEBUG_TIME\n */\n\n/* On quit, make sure we free stuff we can free. \n#define DEBUG_LEAK\n */\n\n/* Sometimes we need to be able to disable these at build time.\n#undef DEBUG_LEAK\n#undef DEBUG_FATAL\n */\n\n/* General stuff. \n */\nWorkspaceroot *main_workspaceroot = NULL;\t/* All the workspaces */\nToolkitgroup *main_toolkitgroup = NULL;\t\t/* All the toolkits */\nSymbol *main_symbol_root = NULL;\t\t/* Root of symtable */\nWatchgroup *main_watchgroup = NULL;\t\t/* All of the watches */\nImageinfogroup *main_imageinfogroup = NULL;\t/* All of the images */\n\nvoid *main_c_stack_base = NULL;\t\t\t/* Base of C stack */\n\ngboolean main_starting = TRUE;\t\t\t/* In startup */\n\nstatic const char *main_argv0 = NULL;\t\t/* argv[0] */\nstatic iOpenFile *main_stdin = NULL;\t\t/* stdin as an iOpenFile */\nstatic GtkIconFactory *main_icon_factory = NULL;/* Add stocks to this */\n\nstatic char *main_option_script = NULL;\nstatic char *main_option_expression = NULL;\ngboolean main_option_batch = FALSE;\nstatic gboolean main_option_no_load_menus = FALSE;\nstatic gboolean main_option_no_load_args = FALSE;\nstatic gboolean main_option_stdin_ws = FALSE;\nstatic gboolean main_option_stdin_def = FALSE;\nstatic char *main_option_output = NULL;\nstatic char **main_option_set = NULL;\nstatic gboolean main_option_benchmark = FALSE;\ngboolean main_option_time_save = FALSE;\ngboolean main_option_profile = FALSE;\ngboolean main_option_i18n = FALSE;\ngboolean main_option_verbose = FALSE;\nstatic gboolean main_option_print_main = FALSE;\nstatic gboolean main_option_version = FALSE;\nstatic gboolean main_option_test = FALSE;\nstatic char *main_option_prefix = NULL;\n\nstatic GOptionEntry main_option[] = {\n\t{ \"expression\", 'e', 0, G_OPTION_ARG_STRING, &main_option_expression, \n\t\tN_( \"evaluate and print EXPRESSION\" ), \n\t\t\"EXPRESSION\" },\n\t{ \"script\", 's', 0, G_OPTION_ARG_FILENAME, &main_option_script, \n\t\tN_( \"load FILE as a set of definitions\" ), \n\t\t\"FILE\" },\n\t{ \"output\", 'o', 0, G_OPTION_ARG_FILENAME, &main_option_output, \n\t\tN_( \"write value of 'main' to FILE\" ), \"FILE\" },\n\t{ \"batch\", 'b', 0, G_OPTION_ARG_NONE, &main_option_batch, \n\t\tN_( \"run in batch mode\" ), NULL },\n\t{ \"set\", '=', 0, G_OPTION_ARG_STRING_ARRAY, &main_option_set, \n\t\tN_( \"set values\" ), NULL },\n\t{ \"verbose\", 'V', 0, G_OPTION_ARG_NONE, &main_option_verbose, \n\t\tN_( \"verbose error output\" ), NULL },\n\t{ \"no-load-menus\", 'm', 0, G_OPTION_ARG_NONE, \n\t\t&main_option_no_load_menus, \n\t\tN_( \"don't load menu definitions\" ), NULL },\n\t{ \"no-load-args\", 'a', 0, G_OPTION_ARG_NONE, &main_option_no_load_args, \n\t\tN_( \"don't try to load command-line arguments\" ), NULL },\n\t{ \"stdin-ws\", 'w', 0, G_OPTION_ARG_NONE, &main_option_stdin_ws, \n\t\tN_( \"load stdin as a workspace\" ), NULL },\n\t{ \"stdin-def\", 'd', 0, G_OPTION_ARG_NONE, &main_option_stdin_def, \n\t\tN_( \"load stdin as a set of definitions\" ), NULL },\n\t{ \"print-main\", 'p', 0, G_OPTION_ARG_NONE, &main_option_print_main, \n\t\tN_( \"print value of 'main' to stdout\" ), \n\t\tNULL },\n\t{ \"benchmark\", 'c', 0, G_OPTION_ARG_NONE, &main_option_benchmark, \n\t\tN_( \"start up and shut down\" ), \n\t\tNULL },\n\t{ \"time-save\", 't', 0, G_OPTION_ARG_NONE, &main_option_time_save, \n\t\tN_( \"time image save operations\" ), \n\t\tNULL },\n\t{ \"profile\", 'r', 0, G_OPTION_ARG_NONE, &main_option_profile, \n\t\tN_( \"profile workspace calculation\" ), \n\t\tNULL },\n\t{ \"prefix\", 'x', 0, G_OPTION_ARG_FILENAME, &main_option_prefix, \n\t\tN_( \"start as if installed to PREFIX\" ), \"PREFIX\" },\n\t{ \"i18n\", 'i', 0, G_OPTION_ARG_NONE, &main_option_i18n, \n\t\tN_( \"output strings for internationalisation\" ), \n\t\tNULL },\n\t{ \"version\", 'v', 0, G_OPTION_ARG_NONE, &main_option_version, \n\t\tN_( \"print version number\" ), \n\t\tNULL },\n\t{ \"test\", 'T', 0, G_OPTION_ARG_NONE, &main_option_test, \n\t\tN_( \"test for errors and quit\" ), NULL },\n\t{ NULL }\n};\n\n/* Accumulate startup errors here.\n */\nstatic char main_start_error_txt[MAX_STRSIZE];\nstatic VipsBuf main_start_error = VIPS_BUF_STATIC( main_start_error_txt );\n\nstatic void\nmain_log_add( const char *fmt, ... )\n{\n\tva_list ap;\n\n        va_start( ap, fmt );\n\tvips_buf_vappendf( &main_start_error, fmt, ap );\n        va_end( ap );\n}\n\nstatic const char *\nmain_log_get( void )\n{\n\treturn( vips_buf_all( &main_start_error ) );\n}\n\nstatic gboolean\nmain_log_is_empty( void )\n{\n\treturn( vips_buf_is_empty( &main_start_error ) );\n}\n\n/* NULL log handler. Used to suppress output on win32 without DEBUG_FATAL.\n */\n#ifndef DEBUG_FATAL\n#ifdef OS_WIN32 \nstatic void\nmain_log_null( const char *log_domain, GLogLevelFlags log_level,\n\tconst char *message, void *user_data )\n{\n}\n#endif /*OS_WIN32*/ \n#endif /*!DEBUG_FATAL*/\n\n/* Print all errors and quit. Batch mode only.\n */\nstatic void\nmain_error_exit( const char *fmt, ... )\n{\n\tva_list args;\n\n        va_start( args, fmt );\n        (void) vfprintf( stderr, fmt, args );\n        va_end( args );\n\tfprintf( stderr, \"\\n\" );  \n\n\tif( strcmp( error_get_top(), \"\" ) != 0 ) {\n\t\tfprintf( stderr, \"%s\\n\", error_get_top() ); \n\t\tif( strcmp( error_get_sub(), \"\" ) != 0 ) \n\t\t\tfprintf( stderr, \"%s\\n\", error_get_sub() ); \n\t}\n\n\tif( main_option_verbose ) {\n\t\tchar txt[MAX_STRSIZE];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\tslist_map( expr_error_all,\n\t\t\t(SListMapFn) expr_error_print, &buf );\n\t\tfprintf( stderr, \"%s\", vips_buf_all( &buf ) );\n\t}\n\n\texit( 1 );\n}\n\n/* Output a single main.\n */\nstatic void\nmain_print_main( Symbol *sym )\n{\n\tPElement *root;\n\n\troot = &sym->expr->root;\n\tif( !symbol_recalculate_check( sym ) ||\n\t\t!reduce_pelement( reduce_context, reduce_spine_strict, root ) ) \n\t\tmain_error_exit( _( \"error calculating \\\"%s\\\"\" ), \n\t\t\tsymbol_name_scope( sym ) );\n\n\tif( main_option_output ) {\n\t\tchar filename[FILENAME_MAX];\n\n\t\tim_strncpy( filename, main_option_output, FILENAME_MAX );\n\t\tif( !group_save_item( root, filename ) )\n\t\t\tmain_error_exit( _( \"error saving \\\"%s\\\"\" ), \n\t\t\t\tsymbol_name_scope( sym ) );\n\t}\n\n\tif( main_option_print_main )\n\t\tgraph_value( root );\n}\n\nstatic void *\nmain_print_ws( Workspace *ws, gboolean *found )\n{\n\tSymbol *sym;\n\n\tif( (sym = compile_lookup( ws->sym->expr->compile, \"main\" )) ) {\n\t\tmain_print_main( sym );\n\t\t*found = TRUE;\n\t}\n\n\treturn( NULL );\n}\n\n/* Clean up our application and quit. Not interactive! Do any \"has been\n * modified, OK to quit?\" stuff before this, see main_quit_test().\n */\nstatic void\nmain_quit( void )\n{\n#if HAVE_FFTW || HAVE_FFTW3\n\tiOpenFile *of;\n#endif /*HAVE_FFTW || HAVE_FFTW3*/\n\n#ifdef DEBUG\n\tprintf( \"main_quit: cleaning up ...\\n\" );\n#endif/*DEBUG*/\n\n\tif( main_option_print_main || \n\t\tmain_option_output ) {\n\t\tSymbol *sym;\n\t\tgboolean found;\n\n\t\tsymbol_recalculate_all();\n\n\t\t/* Process all the mains we can find: one at the top level,\n\t\t * one in each workspace.\n\t\t */\n\t\tfound = FALSE;\n\t\tif( (sym = compile_lookup( \n\t\t\tsymbol_root->expr->compile, \"main\" )) ) {\n\t\t\tmain_print_main( sym );\n\t\t\tfound = TRUE;\n\t\t}\n\t\tworkspace_map( (workspace_map_fn) main_print_ws, &found, NULL );\n\n\t\tif( !found )\n\t\t\tmain_error_exit( \"%s\", _( \"no \\\"main\\\" found\" ) );\n\t}\n\n\t/* Force all our windows down.\n\t */\n\tiwindow_map_all( (iWindowMapFn) iwindow_kill, NULL );\n\n\t/* Saves recent and stuff like that.\n\t */\n\tmainw_shutdown();\n\n\t/* Dump wisdom back again.\n\t */\n#if HAVE_FFTW || HAVE_FFTW3\n\tif( (of = ifile_open_write( \"%s\" G_DIR_SEPARATOR_S \"wisdom\", \n\t\tget_savedir() )) ) {\n\t\tfftw_export_wisdom_to_file( of->fp );\n\t\tifile_close( of );\n\t}\n#endif /*HAVE_FFTW*/\n\n\t/* Remove any ws retain files.\n\t */\n\tworkspacegroup_autosave_clean();\n\n\t/* Junk all symbols. This may remove a bunch of intermediate images\n\t * too.\n\t */\n\tUNREF( main_watchgroup );\n\tUNREF( main_symbol_root );\n\tUNREF( main_toolkitgroup );\n\tUNREF( main_workspaceroot );\n\n\t/* Junk reduction machine ... this should remove all image temps.\n\t */\n\treduce_destroy( reduce_context );\n\n#ifdef DEBUG_LEAK\n\t/* Free other GTK stuff.\n\t */\n\tif( main_icon_factory )\n\t\tgtk_icon_factory_remove_default( main_icon_factory );\n\tjunk_tooltips();\n\n#ifdef HAVE_LIBGOFFICE\n\t/* Not quite sure what this does, but don't do it in batch mode.\n \t */\n\tif( !main_option_batch )\n\t\tlibgoffice_shutdown ();\n#endif /*HAVE_LIBGOFFICE*/\n\n\tpath_rewrite_free_all();\n\n\t/* Should have freed everything now.\n\t */\n\n\t/* Make sure!\n\n\t\tFIXME ... #ifdef this lot out at some point\n\n\t */\n\tUNREF( main_imageinfogroup );\n\theap_check_all_destroyed();\n\tvips_shutdown();\n\tmanaged_check_all_destroyed();\n\tutil_check_all_destroyed();\n\tcall_check_all_destroyed();\n#endif /*DEBUG_LEAK*/\n\n#ifdef DEBUG\n\tprintf( \"main_quit: exit( 0 )\\n\" );\n#endif/*DEBUG*/\n\n\t/* And exit.\n\t */\n\texit( 0 );\n}\n\n/* We mustn't quit recursively!\n */\nstatic gboolean main_quit_running = FALSE;\n\nstatic void\nmain_quit_test_cb( void *sys, iWindowResult result )\n{\n#ifdef DEBUG\n\tprintf( \"main_quit_test_cb:\\n\" );\n#endif/*DEBUG*/\n\n\tif( result == IWINDOW_YES )\n\t\t/* No return from this.\n\t\t */\n\t\tmain_quit();\n\telse\n\t\t/* Quit has been cancelled.\n\t\t */\n\t\tmain_quit_running = FALSE;\n}\n\n/* Check before quitting. \n */\nvoid\nmain_quit_test( void )\n{\n\tif( main_quit_running ) {\n#ifdef DEBUG\n\t\tprintf( \"main_quit_test: recursive quit blocked\\n\" );\n#endif/*DEBUG*/\n\t\treturn;\n\t}\n\tmain_quit_running = TRUE;\n\n#ifdef DEBUG\n\tprintf( \"main_quit_test:\\n\" );\n#endif/*DEBUG*/\n\n\t/* Flush any pending preference saves before we look for dirty\n\t * objects.\n\t */\n\twatchgroup_flush( main_watchgroup );\n\n\t/* Close registered models.\n\t */\n\tfilemodel_inter_close_registered_cb( iwindow_pick_one(), NULL,\n\t\tmain_quit_test_cb, NULL );\n}\n\nstatic void\nmain_watchgroup_changed_cb( void )\n{\n\t/* Only set this in GUI mode. Otherwise, let the user control CPUs \n\t * with the env variable and --vips-concurrency args.\n\t */\n\tif( !main_option_batch )\n\t\tim_concurrency_set( VIPS_CPUS );\n}\n\n/* Try to load a thing, anything at all. Actually, we don't load plugins\n * experimentally, win32 pops up an annoying error dialog if you try that.\n */\nstatic gboolean\nmain_load( Workspace *ws, const char *filename )\n{\n\tWorkspacegroup *new_wsg;\n\n\tif( (new_wsg = workspacegroup_new_from_file( main_workspaceroot, \n\t\tfilename, filename )) ) {\n\t\tMainw *mainw;\n\n\t\tif( !main_option_batch ) {\n\t\t\tmainw = mainw_new( new_wsg );\n\t\t\tgtk_widget_show( GTK_WIDGET( mainw ) );\n\t\t}\n\n\t\tmainw_recent_add( &mainw_recent_workspace, filename );\n\n\t\treturn( TRUE );\n\t}\n\n\terror_clear();\n\n\t/* workspace_load_file() needs to recalc to work, try to avoid that by\n\t * doing .defs first.\n\t */\n\tif( is_file_type( &filesel_dfile_type, filename ) ) {\n\t\tif( toolkit_new_from_file( main_toolkitgroup, filename ) )\n\t\t\treturn( TRUE );\n\t}\n\n\t/* Try as matrix or image. Have to do these via definitions.\n\t */\n\tif( workspace_load_file( ws, filename ) ) \n\t\treturn( TRUE );\n\n\terror_clear();\n\n\terror_top( _( \"Unknown file type.\" ) );\n\terror_sub( _( \"Unable to load \\\"%s\\\".\" ), filename );\n\n\treturn( FALSE );\n}\n\n#ifndef DEBUG_NOAUTO\nstatic void *\nmain_load_plug( char *name )\n{\n\tif( !calli_string_filename( (calli_string_fn) im_load_plugin,\n\t\tname, NULL, NULL, NULL ) ) {\n\t\terror_top( _( \"Unable to load.\" ) );\n\t\terror_sub( _( \"Error loading plug-in \\\"%s\\\".\" ), name );\n\t\terror_vips();\n\t\tiwindow_alert( NULL, GTK_MESSAGE_ERROR );\n\t}\n\n\treturn( NULL );\n}\n#endif /*!DEBUG_NOAUTO*/\n\nstatic void *\nmain_load_def( const char *filename )\n{\t\n\tToolkit *kit;\n\n\tif( !main_option_no_load_menus || im_skip_dir( filename )[0] == '_' ) {\n\t\tprogress_update_loading( 0, im_skip_dir( filename ) );\n\n\t\tif( !(kit = toolkit_new_from_file( main_toolkitgroup, \n\t\t\tfilename )) )\n\t\t\tiwindow_alert( NULL, GTK_MESSAGE_ERROR );\n\t\telse \n\t\t\tfilemodel_set_auto_load( FILEMODEL( kit ) );\n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\nmain_load_wsg( const char *filename )\n{\n\tWorkspacegroup *wsg;\n\n#ifdef DEBUG\n\tprintf( \"main_load_wsg: %s\\n\", filename );\n#endif/*DEBUG*/\n\n\tprogress_update_loading( 0, im_skip_dir( filename ) );\n\n\tif( !(wsg = workspacegroup_new_from_file( main_workspaceroot, \n\t\tfilename, filename )) ) \n\t\tiwindow_alert( NULL, GTK_MESSAGE_ERROR );\n\telse {\n\t\tfilemodel_set_auto_load( FILEMODEL( wsg ) );\n\t}\n\n\treturn( NULL );\n}\n\n#ifndef DEBUG_NOAUTO\n/* Link all the packages in a function.\n */\nstatic void *\nmain_link_package( im_package *pack)\n{\n\tchar name[MAX_STRSIZE];\n\tToolkit *kit;\n        int i;\n\n\tim_snprintf( name, MAX_STRSIZE, \"_%s\", pack->name );\n\tkit = toolkit_new( main_toolkitgroup, name );\n\n        for( i = 0; i < pack->nfuncs; i++ ) \n\t\tif( call_is_callable( pack->table[i] ) ) {\n\t\t\tSymbol *sym;\n\n\t\t\tsym = symbol_new( symbol_root->expr->compile,\n\t\t\t\tpack->table[i]->name );\n\t\t\tg_assert( sym->type == SYM_ZOMBIE );\n\t\t\tsym->type = SYM_EXTERNAL;\n\t\t\tsym->function = pack->table[i];\n\t\t\tsym->fn_nargs = call_n_args( pack->table[i] );\n\t\t\t(void) tool_new_sym( kit, -1, sym );\n\t\t\tsymbol_made( sym );\n\t\t}\n\n\tfilemodel_set_auto_load( FILEMODEL( kit ) );\n\tfilemodel_set_modified( FILEMODEL( kit ), FALSE );\n\tkit->pseudo = TRUE;\n\n        return( NULL );\n}\n#endif /*!DEBUG_NOAUTO*/\n\n/* Load all plugins and defs.\n */\nstatic void\nmain_load_startup( void )\n{\n\tmainw_recent_freeze();\n\n/* Stop load of builtins, plugs and vips ... handy for debugging if you're\n * tracing symbol.c\n */\n#ifdef DEBUG_NOAUTO\n\tprintf( \"*** DEBUG_NOAUTO set, not loading builtin, plugs and vips\\n\" );\n#else /*!DEBUG_NOAUTO*/\n\n#ifdef DEBUG\n\tprintf( \"built-ins init\\n\" );\n#endif/*DEBUG*/\n\n\t/* Add builtin toolkit.\n\t */\n\tbuiltin_init();\n\n#ifdef DEBUG\n\tprintf( \"plug-ins init\\n\" );\n#endif/*DEBUG*/\n\n\t/* Load any plug-ins on PATH_START. \n\t */\n\t(void) path_map( PATH_START, \"*.plg\", \n\t\t(path_map_fn) main_load_plug, NULL );\n\n\t/* Link all VIPS functions as SYM_EXTERNAL.\n\t */\n        (void) im_map_packages( (VSListMap2Fn) main_link_package, NULL );\n#endif /*!DEBUG_NOAUTO*/\n\n\t/* Load up all defs and wses.\n\t */\n#ifdef DEBUG\n\tprintf( \"definitions init\\n\" );\n#endif/*DEBUG*/\n\t(void) path_map( PATH_START, \"*.def\", \n\t\t(path_map_fn) main_load_def, NULL );\n\n#ifdef DEBUG\n\tprintf( \"ws init\\n\" );\n#endif/*DEBUG*/\n\t(void) path_map( PATH_START, \"*.ws\", \n\t\t(path_map_fn) main_load_wsg, NULL );\n\n\tmainw_recent_thaw();\n}\n\nstatic void *\nmain_junk_auto_load( Filemodel *filemodel )\n{\n\tg_assert( IS_FILEMODEL( filemodel ) );\n\n\tif( filemodel->auto_load )\n\t\tIDESTROY( filemodel );\n\n\treturn( NULL );\n}\n\n/* Remove and reload all menus/plugins/workspaces.\n */\nvoid\nmain_reload( void )\n{\n\tprogress_begin();\n\n\t/* Remove.\n\t */\n\ttoolkitgroup_map( main_toolkitgroup, \n\t\t(toolkit_map_fn) main_junk_auto_load, NULL, NULL );\n\tworkspace_map( (workspace_map_fn) main_junk_auto_load, NULL, NULL );\n\tim_close_plugins();\n\n\t/* Reload.\n\t */\n\tmain_load_startup();\n\n\t/* We may have changed our prefs ... link the watches to the\n\t * new prefs workspace.\n\t */\n\twatch_relink_all();\n\n\tprogress_end();\n}\n\n/* Use a file to paint a named stock item.\n */\nstatic void\nmain_file_for_stock( GtkIconFactory *icon_factory,\n\tconst char *stock, const char *file )\n{\n\tGtkIconSource *icon_source;\n\tGtkIconSet *icon_set;\n\tchar buf[FILENAME_MAX];\n\n\tim_snprintf( buf, FILENAME_MAX, \n\t\t\"$VIPSHOME/share/$PACKAGE/data/%s\", file );\n\tpath_expand( buf );\n\ticon_source = gtk_icon_source_new(); \n\tgtk_icon_source_set_filename( icon_source, buf );\n\ticon_set = gtk_icon_set_new();\n\tgtk_icon_set_add_source( icon_set, icon_source );\n\tgtk_icon_source_free( icon_source );\n\tgtk_icon_factory_add( icon_factory, stock, icon_set );\n\tgtk_icon_set_unref( icon_set );\n}\n\n/* Make our custom icon sets.\n */\nstatic void\nmain_register_icons( void )\n{\n\tstatic const GtkStockItem stock_item[] = {\n/* Can be (eg.) \n *\n *   { GTK_STOCK_COPY, N_(\"_Copy\"), GDK_CONTROL_MASK, 'c', GETTEXT_PACKAGE },\n *\n */\n\t\t{ STOCK_NEXT_ERROR, \n\t\t\tN_( \"Next _Error\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_DROPPER, N_( \"Ink dropper\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_DUPLICATE, N_( \"D_uplicate\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_PAINTBRUSH, N_( \"Pen\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_LINE, N_( \"Line\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_TEXT, N_( \"Text\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_SMUDGE, N_( \"Smudge\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_FLOOD, N_( \"Flood\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_FLOOD_BLOB, N_( \"Flood Blob\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_RECT, N_( \"Fill Rectangle\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_MOVE, N_( \"Pan\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_SELECT, N_( \"Select\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_LOCK, N_( \"Locked\" ), 0, 0, GETTEXT_PACKAGE },\n\n\t\t/* And the LEDs we use.\n\t\t */\n\t\t{ STOCK_LED_RED, N_( \"Red LED\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_LED_GREEN, N_( \"Green LED\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_LED_BLUE, N_( \"Blue LED\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_LED_YELLOW, N_( \"Yellow LED\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_LED_CYAN, N_( \"Cyan LED\" ), 0, 0, GETTEXT_PACKAGE },\n\t\t{ STOCK_LED_OFF, N_( \"Off LED\" ), 0, 0, GETTEXT_PACKAGE }\n\t};\n\n\tGtkIconSet *icon_set;\n\n\tgtk_stock_add_static( stock_item, IM_NUMBER( stock_item ) );\n\tmain_icon_factory = gtk_icon_factory_new();\n\n\t/* Make a colour picker stock ... take the stock icon and add our own\n\t * text (gtk defines no text for the standard version of this stock\n\t * icon).\n\t */\n\ticon_set = gtk_icon_factory_lookup_default( GTK_STOCK_COLOR_PICKER );\n\tgtk_icon_factory_add( main_icon_factory, STOCK_DROPPER, icon_set );\n\n\t/* For Next Error, use JUMP_TO.\n\t */\n\ticon_set = gtk_icon_factory_lookup_default( GTK_STOCK_JUMP_TO );\n\tgtk_icon_factory_add( main_icon_factory, STOCK_NEXT_ERROR, icon_set );\n\n\t/* For clone, use the DND_MULTIPLE icon (close enough).\n\t */\n\ticon_set = gtk_icon_factory_lookup_default( GTK_STOCK_DND_MULTIPLE );\n\tgtk_icon_factory_add( main_icon_factory, STOCK_DUPLICATE, icon_set );\n\n\t/* Link to our stock .pngs.\n\t */\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_PAINTBRUSH, \"stock-tool-ink-22.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_LINE, \"stock-tool-path-22.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_TEXT, \"stock-tool-text-22.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_SMUDGE, \"stock-tool-smudge-22.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_FLOOD, \"stock-tool-bucket-fill-22.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_FLOOD_BLOB, \"stock-tool-bucket-fill-22.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_RECT, \"stock-tool-rect-select-22.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_MOVE, \"stock-tool-move-22.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_SELECT, \"stock-tool-select-22.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_LOCK, \"stock-padlock-closed-22.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_ALERT, \"stock-alert-22.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_LED_RED, \"stock-led-red-18.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_LED_GREEN, \"stock-led-green-18.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_LED_BLUE, \"stock-led-blue-18.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_LED_YELLOW, \"stock-led-yellow-18.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_LED_CYAN, \"stock-led-cyan-18.png\" );\n\tmain_file_for_stock( main_icon_factory, \n\t\tSTOCK_LED_OFF, \"stock-led-off-18.png\" );\n\n\tgtk_icon_factory_add_default( main_icon_factory );\n\tg_object_unref( main_icon_factory );\n}\n\n/* Init the display connection stuff.\n */\nstatic void\nmain_x_init( int *argc, char ***argv )\n{\n\tchar buf[FILENAME_MAX];\n\n#ifdef DEBUG\n\tprintf( \"X11 init\\n\" );\n#endif/*DEBUG*/\n\n\t(void) calli_string_filename( \n\t\t(calli_string_fn) gtk_rc_add_default_file, \n\t\t\t\"$VIPSHOME\" G_DIR_SEPARATOR_S \"share\" G_DIR_SEPARATOR_S \n\t\t\tPACKAGE G_DIR_SEPARATOR_S \"rc\" G_DIR_SEPARATOR_S \n\t\t\t\"ipgtkrc\", NULL, NULL, NULL );\n\tgtk_init( argc, argv );\n\n\t/* Set the default icon. \n\t */\n\tim_strncpy( buf, \n\t\t\"$VIPSHOME/share/$PACKAGE/data/vips-128.png\", FILENAME_MAX );\n\tpath_expand( buf );\n\tgtk_window_set_default_icon_from_file( buf, NULL );\n\n\t/* Turn off startup notification. Startup is done when we pop our\n\t * first window, not when we make this secret window.\n\t */\n\tgtk_window_set_auto_startup_notification( FALSE );\n\n#ifdef DEBUG_UPDATES\n\tprintf( \"*** debug updates is on\\n\" );\n\tgdk_window_set_debug_updates( TRUE );\n#endif /*DEBUG_UPDATES*/\n\n\tmain_register_icons();\n\n\t/* Next window we make is end of startup.\n\t */\n\tgtk_window_set_auto_startup_notification( TRUE );\n\n\t/* Load up any saved accelerators.\n\t */\n\tcalli_string_filenamef( (calli_string_fn) gtk_accel_map_load,\n\t\t\"%s\" G_DIR_SEPARATOR_S \"accel_map\", get_savedir() );\n}\n\nstatic void *\nmain_toobig_done_sub( const char *filename )\n{\n\tunlinkf( \"%s\", filename );\n\n\treturn( NULL );\n}\n\n/* OK in \"flush temps\" yesno.\n */\nstatic void\nmain_toobig_done( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\t/* Don't \"rm *\", too dangerous. \n\t */\n\tpath_map_dir( PATH_TMP, \"*.v\",\n\t\t(path_map_fn) main_toobig_done_sub, NULL );\n\tpath_map_dir( PATH_TMP, \"*.ws\",\n\t\t(path_map_fn) main_toobig_done_sub, NULL );\n\n\t/* _stdenv.def:magick can generate .tif files.\n\t */\n\tpath_map_dir( PATH_TMP, \"*.tif\",\n\t\t(path_map_fn) main_toobig_done_sub, NULL );\n\n\t/* autotrace can make some others.\n\t */\n\tpath_map_dir( PATH_TMP, \"*.ppm\",\n\t\t(path_map_fn) main_toobig_done_sub, NULL );\n\tpath_map_dir( PATH_TMP, \"*.svg\",\n\t\t(path_map_fn) main_toobig_done_sub, NULL );\n\n\t/* Tell space-free indicators to update.\n\t */\n\tif( main_imageinfogroup )\n\t\tiobject_changed( IOBJECT( main_imageinfogroup ) );\n\n\tnfn( sys, IWINDOW_YES );\n}\n\n/* Test for a bunch of stuff in the TMP area. Need to do this before\n * we load args in case there are large JPEGs there. Only bother in\n * interactive mode: we won't be able to question the user without an\n * X connection.\n */\nstatic void\nmain_check_temp( double total )\n{\n\tif( total > 10 * 1024 * 1024 ) {\n\t\tchar txt[256];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\t\tchar tmp[FILENAME_MAX];\n\n\t\tim_strncpy( tmp, PATH_TMP, FILENAME_MAX );\n\t\tpath_expand( tmp );\n\t\tvips_buf_append_size( &buf, total );\n\n\t\tbox_yesno( NULL,\n\t\t\tmain_toobig_done, iwindow_true_cb, NULL,\n\t\t\tNULL, NULL,\n\t\t\t_( \"Empty temp area\" ),\n\t\t\t_( \"Many files in temp area.\" ),\n\t\t\t_( \"The temp area \\\"%s\\\" contains %s of files. \"\n\t\t\t\"Would you like to empty the temp area? \"\n\t\t\t\"This will delete any workspace backups and \"\n\t\t\t\"cannot be undone.\" ),\n\t\t\ttmp, vips_buf_all( &buf ) );\n\t}\n}\n\n/* Make sure a savedir exists. Used to build the \"~/.nip2-xx/tmp\" etc.\n * directory tree.\n */\nstatic void\nmain_mkdir( const char *dir )\n{\n\tif( !existsf( \"%s\" G_DIR_SEPARATOR_S \"%s\", get_savedir(), dir ) )\n\t\tif( !mkdirf( \"%s\" G_DIR_SEPARATOR_S \"%s\", get_savedir(), dir ) )\n\t\t\terror_exit( _( \"unable to make %s %s: %s\" ),\n\t\t\t\tget_savedir(), dir, g_strerror( errno ) );\n}\n\nstatic gboolean\nmain_set( const char *str )\n{\n\tSymbol *sym;\n\n\tattach_input_string( str );\n\tif( !(sym = parse_set_symbol()) ) \n\t\treturn( FALSE );\n\n\t/* Put the input just after the '=', ready to parse a RHS into the\n\t * symbol.\n\t */\n\tattach_input_string( str + \n\t\tIM_CLIP( 0, input_state.charpos - 1, strlen( str ) ) );\n\n\tif( !symbol_user_init( sym ) || \n\t\t!parse_rhs( sym->expr, PARSE_RHS ) ) {\n\t\t/* Another parse error.\n\t\t */\n\t\texpr_error_get( sym->expr );\n\n\t\t/* Block changes to error_string ... symbol_destroy() \n\t\t * can set this for compound objects.\n\t\t */\n\t\terror_block();\n\t\tIDESTROY( sym );\n\t\terror_unblock();\n\n\t\treturn( FALSE );\n\t}\n\n\tsymbol_made( sym );\n\n\t/* Is there a row? Make sure any modified text there can't zap our new\n\t * text.\n\t */\n\tif( sym->expr->row ) {\n\t\tRow *row = sym->expr->row;\n\n\t\theapmodel_set_modified( \n\t\t\tHEAPMODEL( row->child_rhs->itext ), FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic char prefix_buffer[FILENAME_MAX];\nstatic gboolean prefix_valid = FALSE;\n\n/* Override the install guess from vips. Handy for testing. \n */\nstatic void\nset_prefix( const char *prefix )\n{\n\tim_strncpy( prefix_buffer, prefix, FILENAME_MAX );\n\tnativeize_path( prefix_buffer );\n\tabsoluteize_path( prefix_buffer );\n\tsetenvf( \"VIPSHOME\", \"%s\", prefix_buffer );\n\tprefix_valid = TRUE;\n}\n\n/* Guess VIPSHOME, if we can.\n */\nconst char *\nget_prefix( void )\n{\n\tif( !prefix_valid ) {\n\t\tconst char *prefix;\n\n\t\tif( !(prefix = im_guess_prefix( main_argv0, \"VIPSHOME\" )) ) {\n\t\t\terror_top( _( \"Unable to find install area.\" ) );\n\t\t\terror_vips();\n\n\t\t\treturn( NULL );\n\t\t}\n\n\t\tset_prefix( prefix ); \n\t}\n\n\treturn( prefix_buffer );\n}\n\n/* Start here!\n */\nint\nmain( int argc, char *argv[] )\n{\n\tgboolean welcome_message = FALSE;\n\tWorkspacegroup *wsg;\n\tWorkspace *ws;\n\tGError *error = NULL;\n\tGOptionContext *context;\n\tconst char *prefix;\n\tint i;\n\tdouble total = 0.0;\n#ifdef HAVE_GETRLIMIT\n\tstruct rlimit rlp;\n#endif /*HAVE_GETRLIMIT*/\n\tchar name[256];\n#if HAVE_FFTW || HAVE_FFTW3\n\tiOpenFile *of;\n#endif /*HAVE_FFTW*/\n\tToolkit *kit;\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n#ifdef DEBUG_TIME\n\tGTimer *startup_timer = g_timer_new();\n\tprintf( \"DEBUG_TIME: startup timer zeroed ...\\n\" );\n#endif /*DEBUG_TIME*/\n\n\t/* In startup phase.\n\t */\n\tmain_starting = TRUE;\n\n\t/* Want numeric locale to be \"C\", so we have C rules for doing \n\t * double <-> string (ie. no \",\" for decimal point).\n\t */\n\tsetlocale( LC_ALL, \"\" );\n\tsetlocale( LC_NUMERIC, \"C\" );\n\n\t/* Make sure our LC_NUMERIC setting is not trashed.\n \t */\n\tgtk_disable_setlocale();\n\n#ifdef DEBUG\n\tprintf( \"main: sizeof( HeapNode ) == %zd\\n\", sizeof( HeapNode ) );\n\n\t/* Should be 3 pointers, hopefully.\n\t */\n\tif( sizeof( HeapNode ) != 3 * sizeof( void * ) )\n\t\tprintf( \"*** struct packing problem!\\n\" );\n#endif/*DEBUG*/\n\n\t/* Yuk .. shouldn't really write to argv0. This can't change the\n\t * string length.\n\t *\n\t * On win32 we will sometimes get paths with mixed '/' and '\\' which \n\t * confuses vips's prefix guessing. Make sure we have one or the other.\n\t */\n\tnativeize_path( argv[0] );\n\n\tmain_argv0 = argv[0];\n\tmain_c_stack_base = &argc;\n\n\t/* Pass config.h stuff down to .ws files.\n\t */\n\tsetenvf( \"PACKAGE\", \"%s\", PACKAGE );\n\tsetenvf( \"VERSION\", \"%s\", VERSION );\n\n#ifdef OS_WIN32\n{\n        /* No HOME on windows ... make one from HOMEDRIVE and HOMEDIR (via\n         * glib).\n         */\n\tconst char *home;\n\tchar buf[FILENAME_MAX];\n\n\tif( !(home = g_getenv( \"HOME\" )) ) \n\t\thome = g_get_home_dir();\n\n\t/* We need native paths.\n\t */\n\tstrncpy( buf, home, FILENAME_MAX );\n\tnativeize_path( buf );\n\tsetenvf( \"HOME\", \"%s\", buf );\n}\n#endif /*OS_WIN32*/\n\n\t/* Name of the dir we store our config stuff in. This can get used by\n\t * Preferences.ws.\n\t */\n\tsetenvf( \"SAVEDIR\", \"%s\", get_savedir() );\n\n\t/* Path separator on this platform.\n\t */\n\tsetenvf( \"SEP\", \"%s\", G_DIR_SEPARATOR_S );\n\n\t/* Executable file extension (eg. \".exe\" on Windows).\n\t */\n\tsetenvf( \"EXEEXT\", \"%s\", VIPS_EXEEXT );\n\n\t/* Start up vips.\n\t */\n\tif( im_init_world( main_argv0 ) )\n\t\terror_exit( \"unable to start VIPS\" );\n\n\t/* The vips8 cache is no use to us. We have our own cache which is\n\t * integrated with our invalidate system. \n\t */\n\tvips_cache_set_max( 0 );\n\n\t/* Init i18n ... get catalogues from $VIPSHOME/share/locale so we're\n\t * relocatable.\n\t */\n\tprefix = get_prefix();\n\tim_snprintf( name, 256, \n\t\t\"%s\" G_DIR_SEPARATOR_S \"share\" G_DIR_SEPARATOR_S \"locale\", \n\t\tprefix );\n#ifdef DEBUG\n\tprintf( \"bindtextdomain: %s\\n\", name );\n#endif /*DEBUG*/\n\ttextdomain( GETTEXT_PACKAGE );\n\tbindtextdomain( GETTEXT_PACKAGE, name );\n\tbind_textdomain_codeset( GETTEXT_PACKAGE, \"UTF-8\" );\n\n\t/* Set localised application name.\n\t */\n\tg_set_application_name( _( PACKAGE ) );\n\n\tcontext = g_option_context_new( _( \"- image processing spreadsheet\" ) );\n\tg_option_context_add_main_entries( context, \n\t\tmain_option, GETTEXT_PACKAGE );\n\n\t/* Don't start X here! We may be in batch mode.\n\t */\n\tg_option_context_add_group( context, gtk_get_option_group( FALSE ) );\n\tg_option_context_add_group( context, im_get_option_group() );\n\n\tif( !g_option_context_parse( context, &argc, &argv, &error ) ) \n\t\tvfatal( &error );\n\n\tg_option_context_free( context );\n\n\t/* Override the install guess from vips. This won't pick up msg\n\t * cats sadly :( since we have to init i18n before arg parsing. Handy\n\t * for testing without installing.\n\t */\n\tif( main_option_prefix ) \n\t\tset_prefix( main_option_prefix );\n\n\tif( main_option_version ) {\n\t\tprintf( \"%s-%s\", PACKAGE, VERSION );\n\t\tprintf( \"\\n\" );\n\n\t\tprintf( _( \"linked to vips-%s\" ), im_version_string() );\n\t\tprintf( \"\\n\" );\n\n\t\texit( 0 );\n\t}\n\n#ifdef DEBUG_FATAL\n\t/* Set masks for debugging ... stop on any problem. \n\t */\n\tg_log_set_always_fatal( \n\t\tG_LOG_FLAG_RECURSION |\n\t\tG_LOG_FLAG_FATAL |\n\t\tG_LOG_LEVEL_ERROR |\n\t\tG_LOG_LEVEL_CRITICAL |\n\t\tG_LOG_LEVEL_WARNING );\n#else /*!DEBUG_FATAL*/\n#ifdef OS_WIN32 \n\t/* No logging output ... on win32, log output pops up a very annoying\n \t * console text box.\n\t */\n\tg_log_set_handler( \"GLib\", \n\t\tG_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, \n\t\tmain_log_null, NULL );\n\tg_log_set_handler( \"Gtk\", \n\t\tG_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, \n\t\tmain_log_null, NULL );\n\tg_log_set_handler( NULL,\n\t\tG_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, \n\t\tmain_log_null, NULL );\n#endif /*OS_WIN32*/ \n#endif /*DEBUG_FATAL*/\n\n\tmain_stdin = ifile_open_read_stdin();\n\n#ifdef HAVE_GETRLIMIT\n\t/* Make sure we have lots of file descriptors. Some platforms have cur\n\t * as 256 and max at 1024 to keep stdio happy.\n\t */\n\tif( getrlimit( RLIMIT_NOFILE, &rlp ) == 0 ) {\n\t\trlim_t old_limit = rlp.rlim_cur;\n\n\t\trlp.rlim_cur = rlp.rlim_max;\n\t\tif( setrlimit( RLIMIT_NOFILE, &rlp ) == 0 ) {\n#ifdef DEBUG\n\t\t\tprintf( \"set max file descriptors to %d\\n\", \n\t\t\t\t(int) rlp.rlim_max );\n#endif /*DEBUG*/\n\t\t}\n\t\telse if( (int) rlp.rlim_max != -1 ) {\n\t\t\t/* -1 means can't-be-set, at least on os x, so don't\n\t\t\t * warn.\n\t\t\t */\n\t\t\tg_warning( _( \"unable to change max file descriptors\\n\"\n\t\t\t\t\"max file descriptors still set to %d\" ),\n\t\t\t\t(int) old_limit );\n\t\t}\n\t}\n\telse {\n\t\tg_warning( _( \"unable to read max file descriptors\" ) );\n\t}\n#endif /*HAVE_GETRLIMIT*/\n\n\t/* Make our file types.\n\t */\n\tfilesel_startup();\n\n\t/* Set default values for paths.\n\t */\n\tpath_init();\n\n\t/* First time we've been run? Welcome message.\n\t */\n\tif( !existsf( \"%s\", get_savedir() ) ) \n\t\twelcome_message = TRUE;\n\n\t/* Always make these in case some got deleted.\n\t */\n\tmain_mkdir( \"\" );\n\tmain_mkdir( \"tmp\" );\n\tmain_mkdir( \"start\" );\n\tmain_mkdir( \"data\" );\n\n\t/* Init other stuff.\n\t */\n#ifdef HAVE_FFTW3\n\tfftw_import_system_wisdom();\n#endif /*HAVE_FFTW3*/\n#if HAVE_FFTW || HAVE_FFTW3\n\tif( (of = ifile_open_read( \"%s\" G_DIR_SEPARATOR_S \"wisdom\", \n\t\tget_savedir() )) ) {\n\t\tfftw_import_wisdom_from_file( of->fp );\n\t\tifile_close( of );\n\t}\n#endif /*HAVE_FFTW*/\n\n\tmainw_startup();\n\treduce_context = reduce_new();\n\tmain_symbol_root = symbol_root_init();\n\tg_object_ref( G_OBJECT( main_symbol_root ) );\n\tiobject_sink( IOBJECT( main_symbol_root ) );\n\tmodel_base_init();\n\tmain_workspaceroot = workspaceroot_new( \"Workspaces\" );\n\tg_object_ref( G_OBJECT( main_workspaceroot ) );\n\tiobject_sink( IOBJECT( main_workspaceroot ) );\n\tmain_watchgroup = watchgroup_new( main_workspaceroot, \"Preferences\" );\n\tg_object_ref( G_OBJECT( main_watchgroup ) );\n\tiobject_sink( IOBJECT( main_watchgroup ) );\n\tmain_toolkitgroup = toolkitgroup_new( symbol_root );\n\tg_object_ref( G_OBJECT( main_toolkitgroup ) );\n\tiobject_sink( IOBJECT( main_toolkitgroup ) );\n\tmain_imageinfogroup = imageinfogroup_new();\n\tg_object_ref( G_OBJECT( main_imageinfogroup ) );\n\tiobject_sink( IOBJECT( main_imageinfogroup ) );\n\n\t/* First pass at command-line options. Just look at the flags that\n\t * imply other flags, don't do any processing yet.\n\t */\n\tif( main_option_script ) {\n\t\tmain_option_batch = TRUE;\n\t\tmain_option_no_load_menus = TRUE;\n\t\tmain_option_no_load_args = TRUE;\n\t\tmain_option_print_main = TRUE;\n\t}\n\n\tif( main_option_test ) {\n\t\tmain_option_batch = TRUE;\n\t\tmain_option_verbose = TRUE;\n\t}\n\n\tif( main_option_expression ) {\n\t\tmain_option_batch = TRUE;\n\t\tmain_option_no_load_menus = TRUE;\n\t\tmain_option_no_load_args = TRUE;\n\t\tmain_option_print_main = TRUE;\n\t}\n\n\tif( main_option_benchmark ) {\n\t\tmain_option_batch = TRUE;\n\t\tmain_option_no_load_menus = FALSE;\n\t}\n\n\tif( main_option_i18n ) {\n\t\t/* Just start up and shutdown, no X. Output constant\n\t\t * i18n strings.\n\t\t */\n\t\tmain_option_batch = TRUE;\n\t\tmain_option_no_load_menus = FALSE;\n\t}\n\n#ifdef DEBUG\n\tif( main_option_batch ) \n\t\tprintf( \"non-interactive mode\\n\" );\n#endif /*DEBUG*/\n\n\t/* Start the X connection. We need this before _load_all(), so that\n\t * we can pop up error dialogs.\n\t */\n\tif( !main_option_batch )\n\t\tmain_x_init( &argc, &argv );\n\n#ifdef HAVE_LIBGOFFICE\n        libgoffice_init();\n\tgo_plugins_init( NULL, NULL, NULL, NULL, TRUE, \n\t\tGO_TYPE_PLUGIN_LOADER_MODULE );\n#endif /*HAVE_LIBGOFFICE*/\n\n\t/* Load start-up stuff. Builtins, plugins, externals etc. We need to\n\t * do this before we load any user code so we can prevent redefinition\n\t * of builtins.\n\t */\n\tmain_load_startup();\n\n\t/* Recalc to build all classes and gets prefs working. \n\t *\n\t * We have to do this in batch\n\t * mode since we can find dirties through dynamic lookups. Even though\n\t * you might think we could just follow recomps.\n\t */\n\tsymbol_recalculate_all_force( TRUE );\n\n#ifdef DEBUG\n\tprintf( \"arg processing\\n\" );\n#endif/*DEBUG*/\n\n\t/* Might make this from stdin/whatever if we have a special\n\t * command-line flag.\n\t */\n\twsg = NULL;\n\tws = NULL;\n\n\t/* Second command-line pass. This time we do any actions.\n\t */\n\tif( main_option_script ) {\n\t\tif( !toolkit_new_from_file( main_toolkitgroup,\n\t\t\tmain_option_script ) )\n\t\t\tmain_log_add( \"%s\\n\", error_get_sub() );\n\t}\n\n\tif( main_option_expression ) {\n\t\tkit = toolkit_new( main_toolkitgroup, \"_expression\" );\n\n\t\tvips_buf_appendf( &buf, \"main = %s;\", main_option_expression );\n\t\tattach_input_string( vips_buf_all( &buf ) );\n\t\t(void) parse_onedef( kit, -1 );\n\n\t\tfilemodel_set_modified( FILEMODEL( kit ), FALSE );\n\t}\n\n\tif( main_option_stdin_def ) {\n\t\tif( !(kit = toolkit_new_from_openfile( \n\t\t\tmain_toolkitgroup, main_stdin )) )\n\t\t\tmain_log_add( \"%s\\n\", error_get_sub() );\n\t}\n\n\tif( main_option_stdin_ws ) {\n\t\tif( !(wsg = workspacegroup_new_from_openfile( \n\t\t\tmain_workspaceroot, main_stdin )) ) \n\t\t\tmain_log_add( \"%s\\n\", error_get_sub() );\n\t\telse \n\t\t\t/* Don't want to have \"stdin\" as the filename.\n\t\t\t */\n\t\t\tfilemodel_set_filename( FILEMODEL( wsg ), NULL );\n\t}\n\n\t/* Make a start workspace and workspacegroup to load\n\t * stuff into.\n\t */\n\tif( !wsg ) {\n\t\twsg = workspacegroup_new_blank( main_workspaceroot, NULL ); \n\t\tws = WORKSPACE( icontainer_get_nth_child( \n\t\t\tICONTAINER( wsg ), 0 ) ); \n\t}\n\n\t/* Reset IM_CONCURRENCY if a watch changes. Need to do this after\n\t * parsing options so we skip in batch mode.\n\t */\n\tg_signal_connect( main_watchgroup, \"watch_changed\", \n\t\tG_CALLBACK( main_watchgroup_changed_cb ), NULL );\n\n\t/* Pass PATH_TMP down to vips via TMPDIR. See im_system(), for\n\t * example. We need to do this after the first recomp so that prefs\n\t * are loaded.\n\t */\n{\n\tchar buf[FILENAME_MAX];\n\n\tim_strncpy( buf, PATH_TMP, FILENAME_MAX );\n\tpath_expand( buf );\n\tsetenvf( \"TMPDIR\", \"%s\", buf );\n\n\tpath_rewrite_add( PATH_TMP, \"$TMPDIR\", TRUE );\n}\n\n\t/* Measure amount of stuff in temp area ... need this for checking\n\t * temps later. We pop a dialog if there are too many, so only useful\n\t * in interactive mode.\n\t */\n\tif( !main_option_batch )\n\t\ttotal = directory_size( PATH_TMP );\n\n\t/* Make nip's argc/argv[].\n\t */\n\tkit = toolkit_new( main_toolkitgroup, \"_args\" );\n\tvips_buf_rewind( &buf );\n\tvips_buf_appendf( &buf, \"argc = %d;\", argc );\n\tattach_input_string( vips_buf_all( &buf ) );\n\t(void) parse_onedef( kit, -1 );\n\n\tvips_buf_rewind( &buf );\n\tvips_buf_appendf( &buf, \"argv = [\" );\n\tfor( i = 0; i < argc; i++ ) {\n\t\t/* Ignore \"--\" args. Consider eg. \n\t\t *\n\t\t * \t./try201.nip2 -o x.v -- -12 ~/pics/shark.jpg \n\t\t *\n\t\t * if we didn't remove --, all scripts would need to. \n\t\t */\n\t\tif( strcmp( argv[i], \"--\" ) == 0 )\n\t\t\tcontinue;\n\n\t\tif( i > 0 )\n\t\t\tvips_buf_appendf( &buf, \", \" );\n\t\tvips_buf_appendf( &buf, \"\\\"%s\\\"\", argv[i] );\n\t}\n\tvips_buf_appendf( &buf, \"];\" );\n\n\tattach_input_string( vips_buf_all( &buf ) );\n\tif( !parse_onedef( kit, -1 ) ) \n\t\tmain_log_add( \"%s\\n\", error_get_sub() );\n\n\tfilemodel_set_modified( FILEMODEL( kit ), FALSE );\n\n\t/* Double-check: we often forget to move the prefs ws to the latest\n\t * version.\n\t */\n#ifdef DEBUG_LEAK\n{\n\tSymbol *wsr_sym = main_workspaceroot->sym;\n\tSymbol *ws_sym = SYMBOL( icontainer_child_lookup( \n\t\tICONTAINER( wsr_sym->expr->compile ), \"Preferences\" ) );\n\n\tif( !ws_sym )\n\t\tprintf( \"No prefs workspace!\\n\" ); \n\telse {\n\t\tWorkspace *ws = ws_sym->ws;\n\n\t\tif( ws->compat_major || \n\t\t\tws->compat_minor )\n\t\t\tprintf( \"Preferences loaded in compat mode!\\n\" );\n\t}\n}\n#endif /*DEBUG_LEAK*/\n\n\tif( !main_option_no_load_args ) {\n\t\t/* Load args as files, if we can. \n\t\t */\n\t\tfor( i = 1; i < argc; i++ ) {\n\t\t\tchar buf[FILENAME_MAX];\n\n\t\t\t/* We want to use the absolute, compact form of the \n\t\t\t * filename object so we don't get a dependency on CWD.\n\t\t\t */\n\t\t\tim_strncpy( buf, argv[i], FILENAME_MAX );\n\t\t\tpath_compact( buf );\n\n\t\t\tif( !main_load( ws, buf ) ) \n\t\t\t\tmain_log_add( \"%s\\n\", error_get_sub() );\n\t\t}\n\t}\n\n\t/* In batch mode give up if there are startup errors.\n\t */\n\tif( main_option_batch ) {\n\t\tif( !main_log_is_empty() ) {\n\t\t\tfprintf( stderr, _( \"Startup error log:\\n%s\" ), \n\t\t\t\tmain_log_get() );\n\t\t\texit( 1 );\n\t\t}\n\t}\n\n\tif( main_option_set ) {\n\t\tint i;\n\n\t\tfor( i = 0; main_option_set[i]; i++ ) {\n\t\t\tif( main_option_verbose ) \n\t\t\t\tprintf( \"main_set: %s\\n\", main_option_set[i] );\n\n\t\t\tif( !main_set( main_option_set[i] ) )\n\t\t\t\tmain_log_add( \"%s\\n%s\", \n\t\t\t\t\terror_get_top(), error_get_sub() );\n\t\t}\n\t}\n\n\t/* Make sure our start ws doesn't have modified set. We may have\n\t * loaded some images or whatever into it.\n\t */\n\tworkspace_set_modified( ws, FALSE );\n\n\t/* If the start ws is empty (we didn't load anything into it) and we\n\t * loaded some other workspaces, we can junk the empty ws. \n\t */\n\tif( icontainer_get_n_children( ICONTAINER( main_workspaceroot ) ) > 2 &&\n\t\tworkspace_is_empty( ws ) ) {\n\t\tIDESTROY( wsg ); \n\t\twsg = NULL;\n\t\tws = NULL;\n\t}\n\n#ifdef DEBUG_TIME\n\tprintf( \"DEBUG_TIME: main init in %gs\\n\",  \n\t\tg_timer_elapsed( startup_timer, NULL ) );\n#endif /*DEBUG_TIME*/\n\n\t/* Are we running interactively? Start the main window and loop.\n\t */\n\tif( !main_option_batch ) {\n\t\tif( wsg ) { \n\t\t\tMainw *mainw;\n\n\t\t\tmainw = mainw_new( wsg );\n\t\t\tgtk_widget_show( GTK_WIDGET( mainw ) );\n\t\t}\n\n\t\t/* Process a few events ... we want the window to be mapped so\n\t\t * that log/welcome/clean? messages we pop appear in the right\n\t\t * place on the screen.\n\t\t */\n\t\twhile( g_main_context_iteration( NULL, FALSE ) )\n\t\t\t;\n\n\t\tif( !main_log_is_empty() ) {\n\t\t\terror_top( _( \"Startup error.\" ) );\n\t\t\terror_sub( _( \"Startup error log:\\n%s\" ), \n\t\t\t\tmain_log_get() );\n\t\t\tiwindow_alert( NULL, GTK_MESSAGE_ERROR );\n\t\t}\n\n\t\tif( welcome_message ) {\n\t\t\tchar save_dir[FILENAME_MAX];\n\t\t\tchar buf[256];\n\n\t\t\tim_snprintf( buf, 256, \n\t\t\t\t_( \"Welcome to %s-%s!\" ), PACKAGE, VERSION );\n\t\t\tim_strncpy( save_dir, get_savedir(), FILENAME_MAX );\n\t\t\tpath_expand( save_dir );\n\t\t\terror_top( \"%s\", buf );\n\t\t\terror_sub( \n_( \"A new directory has been created to hold startup, \"\n\"data and temporary files:\\n\\n\"\n\"     %s\\n\\n\"\n\"If you've used previous versions of %s, you might want \"\n\"to copy files over from your old work area.\" ),\n\t\t\t\tsave_dir, PACKAGE );\n\t\t\tiwindow_alert( NULL, GTK_MESSAGE_INFO );\n\t\t}\n\n\t\tmain_check_temp( total );\n\n#ifdef DEBUG\n\t\tprintf( \"starting event dispatch loop\\n\" );\n#endif/*DEBUG*/\n\n\t\tmain_starting = FALSE;\n\n\t\tsymbol_recalculate_all_force( FALSE );\n\n\t\tgtk_main();\n\t}\n\n\tif( main_option_test ) {\n\t\t/* Make sure we've had at least one recomp.\n\t\t */\n\t\tsymbol_recalculate_all_force( TRUE );\n\t\tif( expr_error_all )\n\t\t\tmain_error_exit( \"--test: errors found\" );\n\t}\n\n\t/* No return from this.\n\t */\n\tmain_quit();\n\n\treturn( 0 );\n}\n\n#ifdef OS_WIN32 \n/* Get non-cmd line args on win32.\n */\nstatic int \nbreakargs( char *program, char *line, char **argv ) \n{ \n\tint argc = 1; \n\n\targv[0] = program; \n\n\twhile( *line && argc < MAX_SYSTEM - 1 ) { \n\t\twhile( *line && isspace( *line ) ) \n\t\t\tline++; \n\n\t\tif( *line == '\"' ) {\n\t\t\t/* Windows-95 quoted arguments \n\t\t\t */ \n\t\t\tchar *start = line + 1; \n\t\t\tchar *end = start; \n\n\t\t\twhile( *end && *end != '\"' ) \n\t\t\t\tend++; \n\n\t\t\tif( *end == '\"' ) { \n\t\t\t\t*end = '\\0'; \n\t\t\t\targv[argc++] = start; \n\t\t\t\tline = end + 1; \n\t\t\t\tcontinue; \n\t\t\t} \n\t\t} \n\n\t\tif( *line ) { \n\t\t\targv[argc++] = line; \n\t\t\twhile( *line && !isspace( *line ) ) \n\t\t\t\tline++; \n\n\t\t\tif( *line ) \n\t\t\t\t*line++ = '\\0'; \n\t\t} \n\t} \n\n\t/* add trailing NULL pointer to argv \n\t */ \n\targv[argc] = NULL; \n\n\treturn( argc ); \n} \n\nint WINAPI \nWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, \n\tLPSTR lpszCmdLine, int nShowCmd ) \n{ \n\tchar *argv[MAX_SYSTEM];\n\tint  argc;                                               \n\tTCHAR program[MAXPATHLEN];                               \n\n\tGetModuleFileName( hInstance, program, sizeof(program) );  \n\targc = breakargs( (char *) program, lpszCmdLine, argv );    \n\n\treturn( main( argc, argv ) );\n} \n#endif /*OS_WIN32*/ \n"
  },
  {
    "path": "src/main.h",
    "content": "/* Declarations supporting main.c.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\nextern Workspaceroot *main_workspaceroot;\t/* All the workspaces */\nextern Toolkitgroup *main_toolkitgroup;\t\t/* All the toolkits */\nextern Symbol *main_symbol_root;\t\t/* Root of symtable */\nextern Watchgroup *main_watchgroup;\t\t/* All of the watches */\nextern Imageinfogroup *main_imageinfogroup;\t/* All of the images */\n\nextern void *main_c_stack_base;\t\t\t/* Base of C stack */\n\nextern gboolean main_starting;\t\t\t/* In startup */\n\nextern gboolean main_option_time_save;\t\t/* Time save image ops */\nextern gboolean main_option_profile;\t\t/* Profile calcualtion */\nextern gboolean main_option_i18n;\t\t/* Output i18n strings */\nextern gboolean main_option_batch;\t\t/* Running in batch mode */\nextern gboolean main_option_verbose;\t\t/* Verbose output */\n\n/* Styles for buttons etc.\n */\nextern GtkStyle *default_style;\nextern GtkStyle *selected_style;\nextern GtkStyle *error_style;\nextern GtkStyle *ok_style;\nextern GtkStyle *tooltip_style;\nextern GtkStyle *leaf_style;\nextern GtkStyle *dirty_style;\n\nvoid main_quit_test( void );\nvoid main_reload( void );\nconst char *get_prefix( void );\n\n"
  },
  {
    "path": "src/mainw.c",
    "content": "/* main processing window\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* \n#define DEBUG\n */\n\n/* Load and save recent items here.\n */\n#define RECENT_WORKSPACE \"recent_workspace\"\n#define RECENT_IMAGE \"recent_image\"\n#define RECENT_MATRIX \"recent_matrix\"\n\n/* Recently loaded/saved workspaces, images and matricies.\n */\nGSList *mainw_recent_workspace = NULL;\nGSList *mainw_recent_image = NULL;\nGSList *mainw_recent_matrix = NULL;\n\n/* Auto-recalc state. Don't do this as a preference, since preferences are\n * workspaces and need to have recalc working to operate.\n */\ngboolean mainw_auto_recalc = TRUE;\n\nstatic gint mainw_layout_timeout = 0;\n\nstatic iWindowClass *parent_class = NULL;\n\n/* All the mainw.\n */\nstatic GSList *mainw_all = NULL;\n\nvoid\nmainw_startup( void )\n{\n\tIM_FREEF( recent_free, mainw_recent_workspace );\n\tIM_FREEF( recent_free, mainw_recent_image );\n\tIM_FREEF( recent_free, mainw_recent_matrix );\n\n\tmainw_recent_workspace = recent_load( RECENT_WORKSPACE );\n\tmainw_recent_image = recent_load( RECENT_IMAGE );\n\tmainw_recent_matrix = recent_load( RECENT_MATRIX );\n}\n\nvoid\nmainw_shutdown( void )\n{\n\trecent_save( mainw_recent_workspace, RECENT_WORKSPACE );\n\trecent_save( mainw_recent_image, RECENT_IMAGE );\n\trecent_save( mainw_recent_matrix, RECENT_MATRIX );\n\n\tIM_FREEF( recent_free, mainw_recent_workspace );\n\tIM_FREEF( recent_free, mainw_recent_image );\n\tIM_FREEF( recent_free, mainw_recent_matrix );\n}\n\nstatic int mainw_recent_freeze_count = 0;\n\nvoid\nmainw_recent_freeze( void )\n{\n\tmainw_recent_freeze_count += 1;\n}\n\nvoid\nmainw_recent_thaw( void )\n{\n\tg_assert( mainw_recent_freeze_count > 0 );\n\n\tmainw_recent_freeze_count -= 1;\n}\n\nvoid\nmainw_recent_add( GSList **recent, const char *filename )\n{\n\tif( !mainw_recent_freeze_count ) {\n\t\tchar buf[FILENAME_MAX];\n\n\t\tim_strncpy( buf, PATH_TMP, FILENAME_MAX );\n\t\tpath_expand( buf );\n\n\t\tif( filename && \n\t\t\tstrcmp( filename, \"\" ) != 0 &&\n\t\t\t!is_prefix( buf, filename ) )\n\t\t\t*recent = recent_add( *recent, filename );\n\t}\n}\n\n/* Pick a mainw at random. Used if we need a window for a dialog, and we're\n * not sure which to pick. \n */\nMainw *\nmainw_pick_one( void )\n{\n\tif( !mainw_all )\n\t\t/* Must be a cast here, since iwindow_pick_one() can return\n\t\t * NULL during shutdown.\n\t\t */\n\t\treturn( (Mainw *) iwindow_pick_one() ); \n\n\treturn( MAINW( mainw_all->data ) );\n}\n\nstatic void\nmainw_finalize( GObject *gobject )\n{\n#ifdef DEBUG\n\tprintf( \"mainw_finalize: %p\\n\", gobject );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_MAINW( gobject ) );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\nmainw_dispose( GObject *object )\n{\n\tMainw *mainw;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_MAINW( object ) );\n\n\tmainw = MAINW( object );\n\n#ifdef DEBUG\n\tprintf( \"mainw_dispose\\n\" );\n#endif /*DEBUG*/\n\n\tIM_FREEF( g_source_remove, mainw->refresh_timeout );\n\n\tFREESID( mainw->changed_sid, mainw->wsg );\n\n\tFREESID( mainw->imageinfo_changed_sid, main_imageinfogroup );\n\tFREESID( mainw->heap_changed_sid, reduce_context->heap );\n\tFREESID( mainw->watch_changed_sid, main_watchgroup );\n\n\tFREESID( mainw->begin_sid, progress_get() );\n\tFREESID( mainw->update_sid, progress_get() );\n\tFREESID( mainw->end_sid, progress_get() );\n\n\tUNREF( mainw->kitgview );\n\n\t/* We don't unref wsg: it's destroyed by mainw_popdown() with\n\t * filemodel_inter_savenclose_cb(). \n\t */\n\n\tmainw_all = g_slist_remove( mainw_all, mainw );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( object );\n}\n\nstatic void *\nmainw_configure_event_sub( Workspace *ws, GdkEventConfigure *event )\n{\n\tMODEL( ws )->window_x = event->x;\n\tMODEL( ws )->window_y = event->y;\n\tMODEL( ws )->window_width = event->width;\n\tMODEL( ws )->window_height = event->height;\n\n\treturn( NULL );\n}\n\nstatic gboolean\nmainw_configure_event( GtkWidget *widget, GdkEventConfigure *event )\n{\n\tMainw *mainw = MAINW( widget );\n\n\t/* We have to record on all wses, since we don't know which will be\n\t * first on reload.\n\t */\n\tworkspacegroup_map( mainw->wsg, \n\t\t(workspace_map_fn) mainw_configure_event_sub, event, NULL );\n\n\treturn( GTK_WIDGET_CLASS( parent_class )->\n\t\tconfigure_event( widget, event ) );\n}\n\nstatic void\nmainw_class_init( MainwClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tGtkWidgetClass *widget_class = (GtkWidgetClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = mainw_finalize;\n\tgobject_class->dispose = mainw_dispose;\n\n\twidget_class->configure_event = mainw_configure_event;\n}\n\nstatic void\nmainw_progress_begin( Progress *progress, Mainw *mainw )\n{\n\tmainw->cancel = FALSE;\n        gtk_widget_show( mainw->progress_box );\n}\n\nstatic void\nmainw_progress_update( Progress *progress, gboolean *cancel, Mainw *mainw )\n{\n\tgtk_progress_bar_set_text( GTK_PROGRESS_BAR( mainw->progress ), \n\t\tvips_buf_all( &progress->feedback ) );\n\tgtk_progress_bar_set_fraction( GTK_PROGRESS_BAR( mainw->progress ), \n\t\tIM_CLIP( 0.0, (double) progress->percent / 100.0, 1.0 ) );\n\n\tif( mainw->cancel )\n\t\t*cancel = TRUE;\n} \n\nstatic void\nmainw_progress_end( Progress *progress, Mainw *mainw )\n{\n        gtk_widget_hide( mainw->progress_box );\n\tmainw->cancel = FALSE;\n}\n\nstatic void\nmainw_init( Mainw *mainw )\n{\n\tmainw->wsg = NULL;\n\n\tmainw->changed_sid = 0;\n\n\tmainw->imageinfo_changed_sid = 0;\n\tmainw->heap_changed_sid = 0;\n\tmainw->watch_changed_sid = 0;\n\n\tmainw->begin_sid = g_signal_connect( progress_get(), \"begin\", \n\t\tG_CALLBACK( mainw_progress_begin ), mainw );\n\tmainw->update_sid = g_signal_connect( progress_get(), \"update\", \n\t\tG_CALLBACK( mainw_progress_update ), mainw );\n\tmainw->end_sid = g_signal_connect( progress_get(), \"end\", \n\t\tG_CALLBACK( mainw_progress_end ), mainw );\n\tmainw->cancel = FALSE;\n\n\tmainw->free_type = FALSE;\n\n\tmainw->toolbar_visible = MAINW_TOOLBAR;\n\tmainw->statusbar_visible = MAINW_STATUSBAR;\n\n\tmainw->kitgview = NULL;\n\tmainw->toolbar = NULL;\n\n\tmainw->statusbar_main = NULL;\n\tmainw->statusbar = NULL;\n\tmainw->space_free = NULL;\n\tmainw->space_free_eb = NULL;\n\tmainw->progress_box = NULL;\n\tmainw->progress = NULL;\n\n\tmainw_all = g_slist_prepend( mainw_all, mainw );\n}\n\nGType\nmainw_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( MainwClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) mainw_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Mainw ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) mainw_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_IWINDOW, \n\t\t\t\"Mainw\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\nmainw_cancel_cb( GtkWidget *wid, Mainw *mainw )\n{\n\tmainw->cancel = TRUE;\n}\n\nvoid\nmainw_find_disc( VipsBuf *buf )\n{\n\tdouble sz = find_space( PATH_TMP );\n\n\tif( sz < 0 )\n\t\tvips_buf_appendf( buf, _( \"No temp area\" ) );\n\telse {\n\t\tchar txt[MAX_STRSIZE];\n\t\tVipsBuf buf2 = VIPS_BUF_STATIC( txt );\n\n\t\tvips_buf_append_size( &buf2, sz );\n\t\tvips_buf_appendf( buf, _( \"%s free\" ), vips_buf_all( &buf2 ) );\n\t}\n}\n\nvoid\nmainw_find_heap( VipsBuf *buf, Heap *heap )\n{\n\t/* How much we can still expand the heap by ... this \n\t * can be -ve if we've closed a workspace, or changed \n\t * the upper limit.\n\t */\n\tint togo = IM_MAX( 0, (heap->mxb - heap->nb) * heap->rsz );\n\n\tvips_buf_appendf( buf, _( \"%d cells free\" ), heap->nfree + togo );\n}\n\nWorkspace *\nmainw_get_workspace( Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( mainw->wsg &&\n\t\t(ws = WORKSPACE( ICONTAINER( mainw->wsg )->current )) )\n\t\treturn( ws );\n\n\treturn( NULL );\n}\n\nWorkspace *\nmainw_next_workspace( Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( mainw->wsg &&\n\t\t(ws = WORKSPACE( \n\t\t\ticontainer_next( ICONTAINER( mainw->wsg ) ) )) )\n\t\treturn( ws );\n\n\treturn( NULL );\n}\n\n/* Update the space remaining indicator. \n */\nstatic void\nmainw_free_update( Mainw *mainw )\n{\n\tHeap *heap = reduce_context->heap;\n\tchar txt[80];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tWorkspace *ws;\n\n\tif( (ws = mainw_get_workspace( mainw )) &&\n\t\tworkspace_selected_any( ws ) ) {\n\t\tvips_buf_appends( &buf, _( \"Selected:\" ) );\n\t\tvips_buf_appends( &buf, \" \" );\n\t\tworkspace_selected_names( ws, &buf, \", \" );\n\t}\n\telse {\n\t\t/* Out of space? Make sure we swap to cell display.\n\t\t */\n\t\tif( !heap->free )\n\t\t\tmainw->free_type = FALSE;\n\n\t\tif( mainw->free_type ) \n\t\t\tmainw_find_heap( &buf, heap );\n\t\telse\n\t\t\tmainw_find_disc( &buf );\n\t}\n\n\tset_glabel( mainw->space_free, \"%s\", vips_buf_all( &buf ) );\n}\n\nstatic void\nmainw_title_update( Mainw *mainw )\n{\n\tWorkspace *ws;\n\tchar txt[512];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tchar *filename;\n\n\tif( mainw->wsg &&\n\t\tFILEMODEL( mainw->wsg )->modified ) \n\t\tvips_buf_appendf( &buf, \"*\" ); \n\n\tif( mainw->wsg &&\n\t\t(filename = FILEMODEL( mainw->wsg )->filename) ) {\n\t\tchar *base = g_path_get_basename( filename ); \n\t\tchar *dir = g_path_get_dirname( filename ); \n\n\t\tvips_buf_appendf( &buf, \"%s (%s)\", base, dir ); \n\n\t\tg_free( base );\n\t\tg_free( dir );\n\t}\n\telse \n\t\tvips_buf_appends( &buf, _( \"unsaved workspace\" ) );\n\n\tif( (ws = mainw_get_workspace( mainw )) ) {\n\t\tvips_buf_appends( &buf, \" - \" );\n\t\tvips_buf_appendf( &buf, \"%s\", NN( IOBJECT( ws->sym )->name ) );\n\t\tif( ws->compat_major ) {\n\t\t\tvips_buf_appends( &buf, \" - \" );\n\t\t\tvips_buf_appends( &buf, _( \"compatibility mode\" ) );\n\t\t\tvips_buf_appendf( &buf, \" %d.%d\", \n\t\t\t\tws->compat_major, \n\t\t\t\tws->compat_minor ); \n\t\t}\n\t}\n\n\tvips_buf_appendf( &buf, \" - %s\", PACKAGE );\n\n\tiwindow_set_title( IWINDOW( mainw ), \"%s\", vips_buf_all( &buf ) );\n}\n\nstatic void \nmainw_status_update( Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( (ws = mainw_get_workspace( mainw )) &&\n\t\tws->status ) \n\t\tgtk_label_set_text( GTK_LABEL( mainw->statusbar ), ws->status );\n\telse {\n\t\tchar txt[256];\n\n\t\tim_snprintf( txt, 256, _( NIP_COPYRIGHT ), PACKAGE );\n\t\tgtk_label_set_markup( GTK_LABEL( mainw->statusbar ), txt );\n\t}\n}\n\nstatic gboolean\nmainw_refresh_timeout_cb( gpointer user_data )\n{\n\tstatic GtkToolbarStyle styles[] = {\n\t\t0,\t\t\t/* Overwrite with system default */\n\t\tGTK_TOOLBAR_ICONS,\n\t\tGTK_TOOLBAR_TEXT,\n\t\tGTK_TOOLBAR_BOTH,\n\t\tGTK_TOOLBAR_BOTH_HORIZ\n\t};\n\tstatic gboolean inited_default_style = FALSE;\n\n\t/* Keep in step with the WorkspaceMode enum.\n\t */\n\tconst static char *view_mode[] = {\n\t\t\"Normal\",\n\t\t\"ShowFormula\",\n\t\t\"NoEdit\"\n\t};\n\n\tMainw *mainw = MAINW( user_data );\n\tiWindow *iwnd = IWINDOW( mainw );\n\tint pref = IM_CLIP( 0, MAINW_TOOLBAR_STYLE, IM_NUMBER( styles ) - 1 );\n\n        GtkAction *action;\n\tWorkspace *ws;\n\n#ifdef DEBUG\n\tprintf( \"mainw_refresh_timeout_cb: %p\\n\", mainw );\n#endif /*DEBUG*/\n\n\tmainw->refresh_timeout = 0;\n\n\tmainw_status_update( mainw );\n\tmainw_free_update( mainw );\n\tmainw_title_update( mainw );\n\n\tif( !inited_default_style ) { \n\t\tstyles[0] = \n\t\t\tgtk_toolbar_get_style( GTK_TOOLBAR( mainw->toolbar ) );\n\t\tinited_default_style = TRUE;\n\t}\n\n\tgtk_toolbar_set_style( GTK_TOOLBAR( mainw->toolbar ), styles[pref] );\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\"AutoRecalculate\" );\n\tgtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),\n\t\tmainw_auto_recalc );\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\"Toolbar\" );\n\tgtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),\n\t\tmainw->toolbar_visible );\n        widget_visible( mainw->toolbar, mainw->toolbar_visible );\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\"Statusbar\" );\n\tgtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),\n\t\tmainw->statusbar_visible );\n        widget_visible( mainw->statusbar_main, mainw->statusbar_visible );\n\n\tif( (ws = mainw_get_workspace( mainw )) ) {\n\t\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\t\"Lock\" );\n\t\tgtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),\n\t\t\tws->locked );\n\n\t\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\t\"Tabdefs\" );\n\t\tgtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),\n\t\t\tws->lpane_open );\n\n\t\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\t\"ToolkitBrowser\" );\n\t\tgtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),\n\t\t\tws->rpane_open );\n\n\t\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\tview_mode[ws->mode] );\n\t\tgtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),\n\t\t\tTRUE );\n\n\t\tworkspace_jump_update( ws, mainw->jump_to_column_menu );\n\n\t\tif( mainw->kitg != ws->kitg ) {\n\t\t\tUNREF( mainw->kitgview );\n\n\t\t\tmainw->kitgview = TOOLKITGROUPVIEW( \n\t\t\t\tmodel_view_new( MODEL( ws->kitg ), NULL ) );\n\t\t\tg_object_ref( G_OBJECT( mainw->kitgview ) );\n\t\t\tgtk_object_sink( GTK_OBJECT( mainw->kitgview ) );\n\t\t\ttoolkitgroupview_set_mainw( mainw->kitgview, mainw );\n\t\t\tgtk_menu_set_accel_group( \n\t\t\t\tGTK_MENU( mainw->kitgview->menu ),\n\t\t\t\tiwnd->accel_group );\n\n\t\t\tmainw->kitg = ws->kitg;\n\t\t}\n\t}\n\n\treturn( FALSE );\n}\n\nstatic void\nmainw_refresh( Mainw *mainw )\n{\n\tIM_FREEF( g_source_remove, mainw->refresh_timeout );\n\n\tmainw->refresh_timeout = g_timeout_add( 100, \n\t\t(GSourceFunc) mainw_refresh_timeout_cb, mainw );\n}\n\nstatic void\nmainw_duplicate_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tWorkspacegroup *new_wsg;\n\tMainw *new_mainw;\n\n\tprogress_begin();\n\n\tif( !(new_wsg = workspacegroup_duplicate( mainw->wsg )) ) {\n\t\tprogress_end();\n\t\tiwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );\n\t\treturn;\n\t}\n\n\tnew_mainw = mainw_new( new_wsg );\n\tgtk_widget_show( GTK_WIDGET( new_mainw ) );\n\n\tsymbol_recalculate_all();\n\n\tprogress_end();\n}\n\nstatic void\nmainw_save_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tworkspacegroup_set_save_type( mainw->wsg, WORKSPACEGROUP_SAVE_ALL );\n\tfilemodel_inter_save( IWINDOW( mainw ), FILEMODEL( mainw->wsg ) );\n}\n\nstatic void\nmainw_save_as_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tworkspacegroup_set_save_type( mainw->wsg, WORKSPACEGROUP_SAVE_ALL );\n\tfilemodel_inter_saveas( IWINDOW( mainw ), FILEMODEL( mainw->wsg ) );\n}\n\n/* Event in the \"space free\" display ... toggle mode on left click.\n */\nstatic gint\nmainw_space_free_event( GtkWidget *widget, GdkEvent *ev, Mainw *mainw )\n{\n\tif( ev->type == GDK_BUTTON_RELEASE ) {\n\t\tmainw->free_type = !mainw->free_type;\n\t\tmainw_free_update( mainw );\n\t}\n\n\treturn( FALSE );\n}\n\n/* Count number and sizes of all image objects.\n */\n\nstatic void *\nmainw_count_images( VipsObject *object, int *n )\n{\n\tif( VIPS_IS_IMAGE( object ) )\n\t\t*n += 1;\n\n\treturn( NULL ); \n}\n\nstatic void *\nmainw_size_images( VipsObject *object, size_t *size )\n{\n\tif( VIPS_IS_IMAGE( object ) )\n\t\t*size += VIPS_IMAGE_SIZEOF_IMAGE( VIPS_IMAGE( object ) ); \n\n\treturn( NULL ); \n}\n\nstatic void\nmainw_space_free_tooltip_generate( GtkWidget *widget, VipsBuf *buf, \n\tMainw *mainw )\n{\n\tHeap *heap = reduce_context->heap;\n\n\tsize_t size;\n\tint n;\n\n\tmainw_find_disc( buf );\n\t/* Expands to (eg.) \"14GB free in /pics/tmp\" */\n        vips_buf_appendf( buf, _( \" in \\\"%s\\\"\" ), PATH_TMP );\n        vips_buf_appends( buf, \", \" );\n\n        vips_buf_appendf( buf, \n\t\t_( \"%d cells in heap, %d cells free, %d cells maximum\" ),\n                heap->ncells, heap->nfree, heap->max_fn( heap ) );\n        vips_buf_appends( buf, \", \" );\n\n\tif( mainw->wsg ) {\n\t\tvips_buf_appendf( buf, _( \"%d objects in workspace\" ),\n\t\t\tworkspacegroup_get_n_objects( mainw->wsg ) );\n\t\tvips_buf_appends( buf, \", \" );\n\t}\n\n        vips_buf_appendf( buf, _( \"%d vips calls cached\" ), \n\t\tcache_history_size );\n        vips_buf_appends( buf, \", \" );\n\n        vips_buf_appendf( buf, _( \"using %d threads\" ), im_concurrency_get() );\n        vips_buf_appends( buf, \", \" );\n\n\tsize = 0;\n\tvips_object_map( (VipsSListMap2Fn) mainw_size_images, &size, NULL );\n\tn = 0;\n\tvips_object_map( (VipsSListMap2Fn) mainw_count_images, &n, NULL );\n\n\tvips_buf_append_size( buf, size );\n        vips_buf_appendf( buf, _( \" in %d images\" ), n );\n}\n\nstatic void\nmainw_free_changed_cb( gpointer *dummy, Mainw *mainw )\n{\n\tmainw_free_update( mainw );\n\tmainw_status_update( mainw );\n}\n\n/* Go to home page.\n */\nvoid\nmainw_homepage_action_cb( GtkAction *action, iWindow *iwnd )\n{\n\tbox_url( GTK_WIDGET( iwnd ), VIPS_HOMEPAGE );\n}\n\n/* About... box.\n */\nvoid\nmainw_about_action_cb( GtkAction *action, iWindow *iwnd )\n{\n\tbox_about( GTK_WIDGET( iwnd ) );\n}\n\n/* User's guide.\n */\nvoid\nmainw_guide_action_cb( GtkAction *action, iWindow *iwnd )\n{\n\tbox_url( GTK_WIDGET( iwnd ), \"file://\" NIP_DOCPATH \"/nipguide.html\" );\n}\n\nstatic void\nmainw_selected_duplicate_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tprogress_begin();\n\tif( (ws = mainw_get_workspace( mainw )) &&\n\t\t!workspace_selected_duplicate( ws ) )\n\t\tiwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );\n\tprogress_end();\n}\n\n/* Ungroup the selected object(s), or the bottom object.\n */\nstatic void\nmainw_ungroup_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tprogress_begin();\n\tif( (ws = mainw_get_workspace( mainw )) &&\n\t\t!workspace_selected_ungroup( ws ) )\n\t\tiwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );\n\tprogress_end();\n}\n\n/* Group the selected object(s).\n */\nvoid\nmainw_group_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( (ws = mainw_get_workspace( mainw )) )\n\t\tworkspace_selected_group( ws );\n}\n\n/* Select all objects.\n */\nstatic void\nmainw_select_all_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( (ws = mainw_get_workspace( mainw )) )\n\t\tworkspace_select_all( ws );\n}\n\nstatic void\nmainw_find_action_cb( GtkAction *action, Mainw *mainw )\n{\n\terror_top( _( \"Not implemented.\" ) );\n\terror_sub( _( \"Find in workspace not implemented yet.\" ) );\n\tiwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_INFO );\n}\n\nstatic void\nmainw_find_again_action_cb( GtkAction *action, Mainw *mainw )\n{\n\terror_top( _( \"Not implemented.\" ) );\n\terror_sub( _( \"Find again in workspace not implemented yet.\" ) );\n\tiwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_INFO );\n}\n\nvoid\nmainw_next_error_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tWorkspace *first_ws;\n\tWorkspace *ws;\n\n\tif( !(first_ws = mainw_get_workspace( mainw )) )\n\t\treturn;\n\n\tdo {\n\t\tws = mainw_get_workspace( mainw );\n\n\t\tif( workspace_next_error( ws ) ) \n\t\t\treturn;\n\n\t\tws = mainw_next_workspace( mainw ); \n\t} while( ws != first_ws ); \n\n\terror_top( _( \"No errors in workspace.\" ) );\n\terror_sub( \"%s\", _( \"There are no errors (that I can see) \"\n\t\t\"in this workspace.\" ) );\n\tiwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_INFO );\n}\n\nstatic void\nmainw_force_calc_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( (ws = mainw_get_workspace( mainw )) &&\n\t\tworkspace_selected_any( ws ) ) {\n\t\tif( !workspace_selected_recalc( ws ) ) \n\t\t\tiwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );\n\t}\n\telse \n\t\tsymbol_recalculate_all_force( TRUE );\n}\n\nWorkspacegroup *\nmainw_open_workspace( Workspaceroot *wsr, const char *filename )\n{\n\tWorkspacegroup *wsg;\n\tMainw *mainw;\n\n\tif( !(wsg = workspacegroup_new_from_file( wsr, filename, filename )) ) \n\t\treturn( NULL );\n\tmainw = mainw_new( wsg );\n\tgtk_widget_show( GTK_WIDGET( mainw ) );\n\n\treturn( wsg );\n}\n\n/* Track these during a load.\n */\ntypedef struct {\n\tMainw *mainw;\n\tVipsBuf *buf;\n\tint nitems;\n} MainwLoad;\n\n/* Try to open a file. Workspace files we load immediately, other ones we\n * add the load to a buffer.\n */\nstatic void *\nmainw_open_fn( Filesel *filesel, const char *filename, MainwLoad *load )\n{\n\tWorkspaceroot *wsr = load->mainw->wsg->wsr; \n\n\tif( is_file_type( &filesel_wfile_type, filename ) ) {\n\t\tif( !mainw_open_workspace( wsr, filename ) )\n\t\t\treturn( filesel );\n\t\tmainw_recent_add( &mainw_recent_workspace, filename );\n\t}\n\telse {\n\t\tif( load->nitems ) \n\t\t\tvips_buf_appends( load->buf, \", \" );\n\t\tif( !workspace_load_file_buf( load->buf, filename ) )\n\t\t\treturn( filesel );\n\t\tmainw_recent_add( &mainw_recent_image, filename );\n\t\tload->nitems += 1;\n\t}\n\n\treturn( NULL );\n}\n\n/* Callback from load browser.\n */\nstatic void\nmainw_open_done_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tMainw *mainw = MAINW( client );\n\tFilesel *filesel = FILESEL( iwnd );\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tMainwLoad load;\n\tWorkspace *ws;\n\n\tload.mainw = mainw;\n\tload.buf = &buf;\n\tload.nitems = 0;\n\n\tif( filesel_map_filename_multi( filesel,\n\t\t(FileselMapFn) mainw_open_fn, &load, NULL ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\t/* Some actual files (image, matrix) were selected. Load into\n\t * the current workspace.\n\t */\n\tif( load.nitems &&\n\t\t(ws = mainw_get_workspace( mainw )) ) { \n\t\tchar txt2[MAX_STRSIZE];\n\t\tVipsBuf buf2 = VIPS_BUF_STATIC( txt2 );\n\n\t\tif( load.nitems > 1 )\n\t\t\tvips_buf_appendf( &buf2, \"Group [%s]\", \n\t\t\t\tvips_buf_all( &buf ) );\n\t\telse\n\t\t\tvips_buf_appends( &buf2, vips_buf_all( &buf ) );\n\n\t\tif( !workspace_add_def_recalc( ws, vips_buf_all( &buf2 ) ) ) {\n\t\t\terror_top( _( \"Load failed.\" ) );\n\t\t\terror_sub( _( \"Unable to execute:\\n   %s\" ), \n\t\t\t\tvips_buf_all( &buf2 ) );\n\t\t\tnfn( sys, IWINDOW_ERROR );\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/* Wses will need a recalc.\n\t */\n\tsymbol_recalculate_all();\n\n\t/* If we had an empty wsg, perhaps we've just started up,\n\t * kill it. \n\t */\n\tif( workspacegroup_is_empty( mainw->wsg ) ) {\n\t\tfilemodel_set_modified( FILEMODEL( mainw->wsg ), FALSE );\n\t\tiwindow_kill( IWINDOW( mainw ) );\n\t}\n\n\tnfn( sys, IWINDOW_YES );\n}\n\n/* Show an open file dialog ... any type, but default to one of the image\n * ones.\n */\nstatic void\nmainw_open( Mainw *mainw )\n{\n\tGtkWidget *filesel = filesel_new();\n\n\tiwindow_set_title( IWINDOW( filesel ), _( \"Open File\" ) );\n\tfilesel_set_flags( FILESEL( filesel ), TRUE, FALSE );\n\tfilesel_set_filetype( FILESEL( filesel ), \n\t\tfilesel_type_mainw, IMAGE_FILE_TYPE );\n\tfilesel_set_filetype_pref( FILESEL( filesel ), \"IMAGE_FILE_TYPE\" );\n\tiwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( mainw ) );\n\tfilesel_set_done( FILESEL( filesel ), \n\t\tmainw_open_done_cb, mainw );\n\tfilesel_set_multi( FILESEL( filesel ), TRUE );\n\tiwindow_build( IWINDOW( filesel ) );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\nvoid\nmainw_open_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tmainw_open( mainw );\n}\n\n/* Open one of the example workspaces ... just a shortcut.\n */\nstatic void\nmainw_open_examples( Mainw *mainw )\n{\n\tGtkWidget *filesel = filesel_new();\n\n\tiwindow_set_title( IWINDOW( filesel ), _( \"Open File\" ) );\n\tfilesel_set_flags( FILESEL( filesel ), TRUE, FALSE );\n\tfilesel_set_filetype( FILESEL( filesel ), \n\t\tfilesel_type_workspace, 0 );\n\tiwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( mainw ) );\n\tfilesel_set_done( FILESEL( filesel ), \n\t\tmainw_open_done_cb, mainw );\n\tfilesel_set_multi( FILESEL( filesel ), TRUE );\n\tiwindow_build( IWINDOW( filesel ) );\n\tfilesel_set_filename( FILESEL( filesel ), \n\t\t\"$VIPSHOME\" G_DIR_SEPARATOR_S \"share\" G_DIR_SEPARATOR_S \n\t\tPACKAGE G_DIR_SEPARATOR_S \"data\" G_DIR_SEPARATOR_S \n\t\t\"examples\" G_DIR_SEPARATOR_S \"1_point_mosaic\" );\n\n\t/* Reset the filetype ... setting the filename will have changed it to\n\t * 'all', since there's no suffix.\n\t */\n\tfilesel_set_filetype( FILESEL( filesel ), \n\t\tfilesel_type_workspace, 0 );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\nstatic void\nmainw_open_examples_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tmainw_open_examples( mainw );\n}\n\nstatic gboolean\nmainw_recent_open( Mainw *mainw, const char *filename )\n{\n\tWorkspacegroup *wsg = mainw->wsg;\n\n\tif( is_file_type( &filesel_wfile_type, filename ) ) {\n\t\tif( !mainw_open_workspace( wsg->wsr, filename ) )\n\t\t\treturn( FALSE );\n\n\t\t/* If we had an empty wsg, perhaps we've just started up,\n\t\t * kill it. \n\t\t */\n\t\tif( workspacegroup_is_empty( wsg ) ) {\n\t\t\tfilemodel_set_modified( FILEMODEL( wsg ), FALSE );\n\t\t\tiwindow_kill( IWINDOW( mainw ) );\n\t\t}\n\t}\n\telse {\n\t\tWorkspace *ws;\n\n\t\tif( (ws = mainw_get_workspace( mainw )) &&\n\t\t\t!workspace_load_file( ws, filename ) )\n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic void\nmainw_recent_open_cb( GtkWidget *widget, const char *filename )\n{\n\tMainw *mainw = MAINW( iwindow_get_root( widget ) );\n\n\tprogress_begin();\n\tif( !mainw_recent_open( mainw, filename ) ) {\n\t\tiwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );\n\t\tprogress_end();\n\t\treturn;\n\t}\n\tprogress_end();\n\n\tsymbol_recalculate_all();\n}\n\nstatic void\nmainw_recent_build( GtkWidget *menu, GSList *recent )\n{\n\tGSList *p;\n\n\tfor( p = recent; p; p = p->next ) {\n\t\tconst char *filename = (const char *) p->data;\n\t\tGtkWidget *item;\n\t\tchar txt[80];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\t\tchar *utf8;\n\n\t\tvips_buf_appendf( &buf, \"    %s\", im_skip_dir( filename ) );\n\t\tutf8 = f2utf8( vips_buf_all( &buf ) );\n\t\titem = gtk_menu_item_new_with_label( utf8 );\n\t\tg_free( utf8 );\n\t\tutf8 = f2utf8( filename );\n\t\tset_tooltip( item, \"%s\", utf8 );\n\t\tg_free( utf8 );\n\t\tgtk_menu_append( GTK_MENU( menu ), item );\n\t\tgtk_widget_show( item );\n\t\tgtk_signal_connect( GTK_OBJECT( item ), \"activate\",\n\t\t\tGTK_SIGNAL_FUNC( mainw_recent_open_cb ), \n\t\t\t(char *) filename );\n\t}\n}\n\nstatic void\nmainw_recent_clear_cb( GtkWidget *widget, const char *filename )\n{\n\tIM_FREEF( recent_free, mainw_recent_workspace );\n\tIM_FREEF( recent_free, mainw_recent_image );\n\tIM_FREEF( recent_free, mainw_recent_matrix );\n\n\t/* Need to remove files too to prevent merge on quit.\n\t */\n\t(void) unlinkf( \"%s\" G_DIR_SEPARATOR_S \"%s\", \n\t\tget_savedir(), RECENT_WORKSPACE );\n\t(void) unlinkf( \"%s\" G_DIR_SEPARATOR_S \"%s\", \n\t\tget_savedir(), RECENT_IMAGE );\n\t(void) unlinkf( \"%s\" G_DIR_SEPARATOR_S \"%s\", \n\t\tget_savedir(), RECENT_MATRIX );\n}\n\nstatic void\nmainw_recent_map_cb( GtkWidget *widget, Mainw *mainw )\n{\n\tGtkWidget *menu = mainw->recent_menu;\n\tGtkWidget *item;\n\n\tgtk_container_foreach( GTK_CONTAINER( menu ),\n\t\t(GtkCallback) gtk_widget_destroy, NULL );\n\n\tif( mainw_recent_image ) {\n\t\titem = gtk_menu_item_new_with_label( _( \"Recent Images\" ) );\n\t\tgtk_menu_append( GTK_MENU( menu ), item );\n\t\tgtk_widget_show( item );\n\t\tgtk_widget_set_sensitive( item, FALSE );\n\t\tmainw_recent_build( menu, mainw_recent_image );\n\t}\n\n\tif( mainw_recent_workspace ) {\n\t\titem = gtk_menu_item_new_with_label( _( \"Recent Workspaces\" ) );\n\t\tgtk_menu_append( GTK_MENU( menu ), item );\n\t\tgtk_widget_show( item );\n\t\tgtk_widget_set_sensitive( item, FALSE );\n\t\tmainw_recent_build( menu, mainw_recent_workspace );\n\t}\n\n\tif( mainw_recent_matrix ) {\n\t\titem = gtk_menu_item_new_with_label( _( \"Recent Matricies\" ) );\n\t\tgtk_menu_append( GTK_MENU( menu ), item );\n\t\tgtk_widget_show( item );\n\t\tgtk_widget_set_sensitive( item, FALSE );\n\t\tmainw_recent_build( menu, mainw_recent_matrix );\n\t}\n\n\tif( !mainw_recent_workspace && !mainw_recent_image &&\n\t\t!mainw_recent_matrix ) {\n\t\titem = gtk_menu_item_new_with_label( _( \"No recent items\" ) );\n\t\tgtk_menu_append( GTK_MENU( menu ), item );\n\t\tgtk_widget_show( item );\n\t\tgtk_widget_set_sensitive( item, FALSE );\n\t}\n\telse {\n\t\titem = gtk_menu_item_new_with_label( _( \"Clear Recent Menu\" ) );\n\t\tgtk_menu_append( GTK_MENU( menu ), item );\n\t\tgtk_widget_show( item );\n\t\tgtk_signal_connect( GTK_OBJECT( item ), \"activate\",\n\t\t\tGTK_SIGNAL_FUNC( mainw_recent_clear_cb ), NULL );\n\t}\n}\n\n/* Merge a .ws into this wsg.\n */\nstatic void *\nmainw_workspace_merge_fn( Filesel *filesel,\n\tconst char *filename, void *a, void *b )\n{\n\tMainw *mainw = MAINW( a );\n\n\tif( !workspacegroup_merge_workspaces( mainw->wsg, filename ) )\n\t\treturn( filesel );\n\n\t/* Process some events to make sure we rethink the layout and\n\t * are able to get the append-at-RHS offsets.\n\t */\n\tprocess_events();\n\n\tsymbol_recalculate_all();\n\tmainw_recent_add( &mainw_recent_workspace, filename );\n\n\treturn( NULL );\n}\n\n/* Callback from load browser.\n */\nstatic void\nmainw_workspace_merge_done_cb( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( iwnd );\n\tMainw *mainw = MAINW( client );\n\n\tif( filesel_map_filename_multi( filesel,\n\t\tmainw_workspace_merge_fn, mainw, NULL ) ) {\n\t\tsymbol_recalculate_all();\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tsymbol_recalculate_all();\n\n\tnfn( sys, IWINDOW_YES );\n}\n\n/* Merge ws file into current ws.\n */\nvoid\nmainw_workspace_merge( Mainw *mainw )\n{\n\tGtkWidget *filesel = filesel_new();\n\n\tiwindow_set_title( IWINDOW( filesel ), \n\t\t_( \"Merge Workspace from File\" ) );\n\tfilesel_set_flags( FILESEL( filesel ), FALSE, FALSE );\n\tfilesel_set_filetype( FILESEL( filesel ), filesel_type_workspace, 0 ); \n\tiwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( mainw ) );\n\tfilesel_set_done( FILESEL( filesel ), \n\t\tmainw_workspace_merge_done_cb, mainw );\n\tfilesel_set_multi( FILESEL( filesel ), TRUE );\n\tiwindow_build( IWINDOW( filesel ) );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\nvoid\nmainw_workspace_merge_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tmainw_workspace_merge( mainw );\n}\n\n/* Load a workspace, called from a yesno dialog.\n */\nstatic void\nmainw_auto_recover_cb( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tchar *filename = (char *) client;\n\n\tWorkspacegroup *new_wsg;\n\tMainw *new_mainw;\n\n        progress_begin();\n\n\tif( !(new_wsg = workspacegroup_new_from_file( main_workspaceroot, \n\t\tfilename, filename )) ) {\n\t\tprogress_end();\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;  \n\t}\n\n\tfilemodel_set_filename( FILEMODEL( new_wsg ), NULL );\n\n\tnew_mainw = mainw_new( new_wsg );\n\tgtk_widget_show( GTK_WIDGET( new_mainw ) );\n\n\tsymbol_recalculate_all();\n\n\tprogress_end();\n\n\tnfn( sys, IWINDOW_YES );\n}\n\n/* Auto recover.\n */\nstatic void\nmainw_recover_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tchar *filename;\n\t\n\tif( !(filename = workspacegroup_autosave_recover()) ) { \n\t\tif( !AUTO_WS_SAVE ) {\n\t\t\terror_top( _( \"No backup workspaces found.\" ) );\n\t\t\terror_sub( \"%s\", \n\t\t\t\t_( \"You need to enable \\\"Auto workspace \"\n\t\t\t\t\"save\\\" in Preferences \"\n\t\t\t\t\"before automatic recovery works.\" ) );\n\t\t}\n\t\telse {\n\t\t\terror_top( _( \"No backup workspaces found.\" ) );\n\t\t\terror_sub( _( \"No suitable workspace save files found \"\n\t\t\t\t\"in \\\"%s\\\"\" ), PATH_TMP );\n\t\t}\n\n\t\tiwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_INFO );\n\t\treturn;\n\t}\n\n\t/* Tricksy ... free str with notify callack from yesno.\n\t */\n\n\tbox_yesno( GTK_WIDGET( mainw ), \n\t\tmainw_auto_recover_cb, iwindow_true_cb, filename, \n\t\t(iWindowNotifyFn) im_free, filename,\n\t\tGTK_STOCK_OPEN, \n\t\t_( \"Open workspace backup?\" ),\n\t\t_( \"Found workspace backup:\\n\\n\\t%s\\n\\n\"\n\t\t\"Do you want to recover this workspace?\" ),\n\t\tfilename ); \n}\n\n/* Callback from make new column.\n */\nvoid\nmainw_column_new_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( (ws = mainw_get_workspace( mainw )) )\n\t\t(void) workspace_column_new( ws );\n}\n\n/* Done button hit.\n */\nstatic void\nmainw_column_new_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tMainw *mainw = MAINW( client );\n\tStringset *ss = STRINGSET( iwnd );\n\tStringsetChild *name = stringset_child_get( ss, _( \"Name\" ) );\n\tStringsetChild *caption = stringset_child_get( ss, _( \"Caption\" ) );\n\n\tWorkspace *ws;\n\tColumn *col;\n\n\tchar name_text[1024];\n\tchar caption_text[1024];\n\n\tif( !(ws = mainw_get_workspace( mainw )) ) {\n\t\tnfn( sys, IWINDOW_YES );\n\t\treturn;\n\t}\n\n\tif( !get_geditable_name( name->entry, name_text, 1024 ) ||\n\t\t!get_geditable_string( caption->entry, caption_text, 1024 ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tif( !(col = column_new( ws, name_text )) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tif( strcmp( caption_text, \"\" ) != 0 )\n\t\tiobject_set( IOBJECT( col ), NULL, caption_text );\n\n\tworkspace_column_select( ws, col );\n\n\tcolumn_scrollto( col, MODEL_SCROLL_TOP );\n\n\tnfn( sys, IWINDOW_YES );\n}\n\n/* Make a new column with a specified name.\n */\nstatic void\nmainw_column_new_named_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tGtkWidget *ss = stringset_new();\n\tchar new_name[MAX_STRSIZE];\n\tWorkspace *ws;\n\n\tif( !(ws = mainw_get_workspace( mainw )) ) \n\t\treturn;\n\n\tworkspace_column_name_new( ws, new_name );\n\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Name\" ), new_name, _( \"Set column name here\" ) );\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Caption\" ), \"\", _( \"Set column caption here\" ) );\n\n\tiwindow_set_title( IWINDOW( ss ), _( \"New Column\" ) );\n\tidialog_set_callbacks( IDIALOG( ss ), \n\t\tiwindow_true_cb, NULL, NULL, mainw );\n\tidialog_add_ok( IDIALOG( ss ), \n\t\tmainw_column_new_cb, _( \"Create Column\" ) );\n\tiwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( mainw ) );\n\tiwindow_build( IWINDOW( ss ) );\n\n\tgtk_widget_show( ss );\n}\n\n/* Callback from program.\n */\nstatic void\nmainw_program_new_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( (ws = mainw_get_workspace( mainw )) ) {\n\t\tProgram *program;\n\n\t\tprogram = program_new( ws->kitg );\n\t\tgtk_widget_show( GTK_WIDGET( program ) ); \n\t}\n}\n\nstatic void\nmainw_workspace_new_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tworkspace_new_blank( mainw->wsg );\n}\n\n/* New workbook.\n */\nstatic void\nmainw_workbook_new_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tMainw *new_mainw;\n\tWorkspacegroup *new_wsg;\n\tchar name[256];\n\n\tworkspaceroot_name_new( mainw->wsg->wsr, name );\n\tnew_wsg = workspacegroup_new_blank( mainw->wsg->wsr, name );\n\tnew_mainw = mainw_new( new_wsg );\n\tgtk_widget_show( GTK_WIDGET( new_mainw ) );\n}\n\n/* Callback from auto-recalc toggle.\n */\nstatic void\nmainw_autorecalc_action_cb( GtkToggleAction *action, Mainw *mainw )\n{\n\tGSList *i;\n\n\tmainw_auto_recalc = gtk_toggle_action_get_active( action );\n\n\t/* Yuk! We have to ask all mainw to refresh by hand, since we're not \n\t * using the prefs system for auto_recalc for reasons noted at top.\n\t */\n\tfor( i = mainw_all; i; i = i->next ) \n\t\tmainw_refresh( MAINW( i->data ) );\n\n\tif( mainw_auto_recalc )\n\t\tsymbol_recalculate_all();\n}\n\n/* Callback from lock toggle.\n */\nstatic void\nmainw_lock_action_cb( GtkToggleAction *action, Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( (ws = mainw_get_workspace( mainw )) ) \n\t\tworkspace_set_locked( ws, \n\t\t\tgtk_toggle_action_get_active( action ) ); \n}\n\n/* Callback from show toolbar toggle.\n */\nstatic void\nmainw_toolbar_action_cb( GtkToggleAction *action, Mainw *mainw )\n{\n\tmainw->toolbar_visible = gtk_toggle_action_get_active( action );\n\tprefs_set( \"MAINW_TOOLBAR\", \n\t\t\"%s\", bool_to_char( mainw->toolbar_visible ) );\n\tmainw_refresh( mainw );\n}\n\n/* Callback from show statusbar toggle.\n */\nstatic void\nmainw_statusbar_action_cb( GtkToggleAction *action, Mainw *mainw )\n{\n\tmainw->statusbar_visible = gtk_toggle_action_get_active( action );\n\tprefs_set( \"MAINW_STATUSBAR\", \n\t\t\"%s\", bool_to_char( mainw->statusbar_visible ) );\n\tmainw_refresh( mainw );\n}\n\n/* Expose/hide the toolkit browser.\n */\nstatic void\nmainw_toolkitbrowser_action_cb( GtkToggleAction *action, Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( (ws = mainw_get_workspace( mainw )) ) {\n\t\tws->rpane_open = gtk_toggle_action_get_active( action );\n\t\tiobject_changed( IOBJECT( ws ) );\n\t}\n}\n\n/* Expose/hide the workspace defs.\n */\nstatic void\nmainw_tabdefs_action_cb( GtkToggleAction *action, Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( (ws = mainw_get_workspace( mainw )) ) {\n\t\tws->lpane_open = gtk_toggle_action_get_active( action );\n\t\tiobject_changed( IOBJECT( ws ) );\n\t}\n}\n\n/* Remove selected items.\n */\nstatic void\nmainw_selected_remove_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( (ws = mainw_get_workspace( mainw )) ) \n\t\tworkspace_selected_remove_yesno( ws, GTK_WIDGET( mainw ) );\n}\n\nvoid \nmainw_revert_ok_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys ) \n{\n\tPrefs *prefs = PREFS( client );\n\tWorkspacegroup *wsg = workspace_get_workspacegroup( prefs->ws );\n\n\tif( FILEMODEL( wsg )->filename ) {\n\t\t(void) unlinkf( \"%s\", FILEMODEL( wsg )->filename );\n\t\tmain_reload();\n\t\tsymbol_recalculate_all();\n\t}\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nvoid \nmainw_revert_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys ) \n{\n\tPrefs *prefs = PREFS( client );\n\n\tbox_yesno( GTK_WIDGET( iwnd ),\n\t\tmainw_revert_ok_cb, iwindow_true_cb, prefs,\n\t\tnfn, sys,\n\t\t_( \"Revert to Defaults\" ), \n\t\t_( \"Revert to installation defaults?\" ),\n\t\t_( \"Would you like to reset all preferences to their factory \"\n\t\t\"settings? This will delete any changes you have ever made \"\n\t\t\"to your preferences and may take a few seconds.\" ) );\n}\n\nstatic void\nmainw_preferences_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tPrefs *prefs;\n\n\t/* Can fail if there's no prefs ws, or an error on load.\n\t */\n\tif( !(prefs = prefs_new( NULL )) ) {\n\t\tiwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );\n\t\treturn;\n\t}\n\n\tiwindow_set_title( IWINDOW( prefs ), _( \"Preferences\" ) );\n\tiwindow_set_parent( IWINDOW( prefs ), GTK_WIDGET( mainw ) );\n\tidialog_set_callbacks( IDIALOG( prefs ), \n\t\tNULL, NULL, NULL, prefs );\n\tidialog_add_ok( IDIALOG( prefs ), \n\t\tmainw_revert_cb, _( \"Revert to Defaults ...\" ) );\n\tidialog_add_ok( IDIALOG( prefs ), iwindow_true_cb, GTK_STOCK_CLOSE );\n\tiwindow_build( IWINDOW( prefs ) );\n\n\t/* Just big enough to avoid a horizontal scrollbar on my machine. \n\n\t\tFIXME ... Yuk! There must be a better way to do this! \n\t\tMaybe a setting in prefs to suppress the h scrollbar?\n\n\t */\n\tgtk_window_set_default_size( GTK_WINDOW( prefs ), 780, 480 );\n\n\tgtk_widget_show( GTK_WIDGET( prefs ) );\n}\n\n/* Make a magic definition for the selected symbol.\n\n\tFIXME .. paste this back when magic is reinstated\n\nstatic void\nmainw_magic_cb( gpointer callback_data, guint callback_action,\n        GtkWidget *widget )\n{\n\tWorkspace *ws = main_workspaceroot->current;\n\tRow *row = workspace_selected_one( ws );\n\n\tif( !row )\n\t\tbox_alert( mainw,\n\t\t\t\"Select a single object with left-click, \"\n\t\t\t\"select Magic Definition.\" );\n\telse if( !magic_sym( row->sym ) )\n\t\tiwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );\n\telse\n\t\tworkspace_deselect_all( ws );\n}\n */\n\n#ifdef HAVE_LIBGVC\nstatic void\nmainw_graph_action_cb( GtkAction *action, Mainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( (ws = mainw_get_workspace( mainw )) ) { \n\t\tGraphwindow *graphwindow;\n\n\t\tgraphwindow = graphwindow_new( ws, GTK_WIDGET( mainw ) );\n\t\tgtk_widget_show( GTK_WIDGET( graphwindow ) );\n\t}\n}\n#endif /*HAVE_LIBGVC*/\n\n/* Set display mode.\n */\nstatic void\nmainw_mode_action_cb( GtkRadioAction *action, GtkRadioAction *current, \n\tMainw *mainw )\n{\n\tWorkspace *ws;\n\n\tif( (ws = mainw_get_workspace( mainw )) ) \n\t\tworkspace_set_mode( ws, \n\t\t\tgtk_radio_action_get_current_value( action ) );\n}\n\n/* Our actions.\n */\nstatic GtkActionEntry mainw_actions[] = {\n\t/* Menu items.\n\t */\n\t{ \"RecentMenu\", NULL, N_( \"Open _Recent\" ) },\n\t{ \"JumpToColumnMenu\", NULL, N_( \"Jump to _Column\" ) },\n\t{ \"ToolkitsMenu\", NULL, N_( \"_Toolkits\" ) },\n\n\t/* Dummy action ... replaced at runtime.\n\t */\n\t{ \"Stub\", \n\t\tNULL, \"\", NULL, \"\", NULL },\n\n\t/* Actions.\n\t */\n\t{ \"NewColumn\", \n\t\tGTK_STOCK_NEW, N_( \"C_olumn\" ), NULL, \n\t\tN_( \"Create a new column\" ), \n\t\tG_CALLBACK( mainw_column_new_action_cb ) },\n\n\t{ \"NewColumnName\", \n\t\tGTK_STOCK_NEW, N_( \"C_olumn\" ), NULL, \n\t\tN_( \"Create a new column with a specified name\" ), \n\t\tG_CALLBACK( mainw_column_new_named_action_cb ) },\n\n\t{ \"NewTab\", \n\t\tGTK_STOCK_NEW, N_( \"_Tab\" ), \"<control>T\", \n\t\tN_( \"Create a new tab\" ), \n\t\tG_CALLBACK( mainw_workspace_new_action_cb ) },\n\n\t{ \"NewWorkspace\", \n\t\tGTK_STOCK_NEW, N_( \"_Workspace\" ), NULL, \n\t\tN_( \"Create a new workspace\" ), \n\t\tG_CALLBACK( mainw_workbook_new_action_cb ) },\n\n\t{ \"Open\", \n\t\tGTK_STOCK_OPEN, N_( \"_Open\" ), NULL,\n\t\tN_( \"Open a file\" ), \n\t\tG_CALLBACK( mainw_open_action_cb ) },\n\n\t{ \"OpenExamples\", \n\t\tNULL, N_( \"Open _Examples\" ), NULL,\n\t\tN_( \"Open example workspaces\" ), \n\t\tG_CALLBACK( mainw_open_examples_action_cb ) },\n\n\t{ \"DuplicateWorkspace\", \n\t\tSTOCK_DUPLICATE, N_( \"_Duplicate Workspace\" ), NULL,\n\t\tN_( \"Duplicate workspace\" ), \n\t\tG_CALLBACK( mainw_duplicate_action_cb ) },\n\n\t{ \"Merge\", \n\t\tNULL, N_( \"_Merge Into Workspace\" ), NULL, \n\t\tN_( \"Merge workspace into this workspace\" ), \n\t\tG_CALLBACK( mainw_workspace_merge_action_cb ) },\n\n\t{ \"Save\", \n\t\tGTK_STOCK_SAVE, N_( \"_Save Workspace\" ), NULL,\n\t\tN_( \"Save workspace\" ), \n\t\tG_CALLBACK( mainw_save_action_cb ) },\n\n\t{ \"SaveAs\", \n\t\tGTK_STOCK_SAVE_AS, N_( \"_Save Workspace As\" ), NULL,\n\t\tN_( \"Save workspace as\" ), \n\t\tG_CALLBACK( mainw_save_as_action_cb ) },\n\n\t{ \"Recover\", \n\t\tNULL, N_( \"Search for Workspace _Backups\" ), NULL,\n\t\tN_( \"Load last automatically backed-up workspace\" ), \n\t\tG_CALLBACK( mainw_recover_action_cb ) },\n\n\t{ \"Delete\", \n\t\tGTK_STOCK_DELETE, N_( \"_Delete\" ), \"<control>BackSpace\",\n\t\tN_( \"Delete selected items\" ), \n\t\tG_CALLBACK( mainw_selected_remove_action_cb ) },\n\n\t{ \"SelectAll\", \n\t\tNULL, N_( \"Select _All\" ), \"<control>A\",\n\t\tN_( \"Select all items\" ), \n\t\tG_CALLBACK( mainw_select_all_action_cb ) },\n\n\t{ \"Duplicate\", \n\t\tSTOCK_DUPLICATE, N_( \"D_uplicate Selected\" ), \"<control>U\",\n\t\tN_( \"Duplicate selected items\" ), \n\t\tG_CALLBACK( mainw_selected_duplicate_action_cb ) },\n\n\t{ \"Recalculate\", \n\t\tNULL, N_( \"_Recalculate\" ), NULL,\n\t\tN_( \"Recalculate selected items\" ), \n\t\tG_CALLBACK( mainw_force_calc_action_cb ) },\n\n\t{ \"Find\", \n\t\tGTK_STOCK_FIND, N_( \"_Find\" ), NULL,\n\t\tN_( \"Find in workspace\" ), \n\t\tG_CALLBACK( mainw_find_action_cb ) },\n\n\t{ \"FindNext\", \n\t\tNULL, N_( \"Find _Next\" ), NULL,\n\t\tN_( \"Find again in workspace\" ), \n\t\tG_CALLBACK( mainw_find_again_action_cb ) },\n\n\t{ \"NextError\", \n\t\tSTOCK_NEXT_ERROR, NULL, NULL,\n\t\tN_( \"Jump to next error\" ), \n\t\tG_CALLBACK( mainw_next_error_action_cb ) },\n\n\t{ \"Group\", \n\t\tNULL, N_( \"_Group\" ), NULL,\n\t\tN_( \"Group selected items\" ), \n\t\tG_CALLBACK( mainw_group_action_cb ) },\n\n\t{ \"Ungroup\", \n\t\tNULL, N_( \"U_ngroup\" ), NULL,\n\t\tN_( \"Ungroup selected items\" ), \n\t\tG_CALLBACK( mainw_ungroup_action_cb ) },\n\n\t{ \"Preferences\", \n\t\tGTK_STOCK_PREFERENCES, N_( \"_Preferences\" ), NULL,\n\t\tN_( \"Edit preferences\" ), \n\t\tG_CALLBACK( mainw_preferences_action_cb ) },\n\n#ifdef HAVE_LIBGVC\n\t{ \"Graph\", \n\t\tNULL, N_( \"Workspace as Grap_h\" ), NULL,\n\t\tN_( \"Show a graph of workspace dependencies\" ), \n\t\tG_CALLBACK( mainw_graph_action_cb ) },\n#endif /*HAVE_LIBGVC*/\n\n\t{ \"EditToolkits\", \n\t\tNULL, N_( \"_Edit\" ), NULL,\n\t\tN_( \"Edit toolkits\" ), \n\t\tG_CALLBACK( mainw_program_new_action_cb ) }\n};\n\nstatic GtkToggleActionEntry mainw_toggle_actions[] = {\n\t{ \"AutoRecalculate\",\n\t\tNULL, N_( \"Au_to Recalculate\" ), NULL,\n\t\tN_( \"Recalculate automatically on change\" ),\n\t\tG_CALLBACK( mainw_autorecalc_action_cb ), TRUE },\n\n\t{ \"Lock\",\n\t\tNULL, N_( \"_Lock tab\" ), NULL,\n\t\tN_( \"Lock tab\" ),\n\t\tG_CALLBACK( mainw_lock_action_cb ), TRUE },\n\n\t{ \"Toolbar\",\n\t\tNULL, N_( \"_Toolbar\" ), NULL,\n\t\tN_( \"Show window toolbar\" ),\n\t\tG_CALLBACK( mainw_toolbar_action_cb ), TRUE },\n\n\t{ \"Statusbar\",\n\t\tNULL, N_( \"_Statusbar\" ), NULL,\n\t\tN_( \"Show window statusbar\" ),\n\t\tG_CALLBACK( mainw_statusbar_action_cb ), TRUE },\n\n\t{ \"ToolkitBrowser\",\n\t\tNULL, N_( \"Toolkit _Browser\" ), NULL,\n\t\tN_( \"Show toolkit browser\" ),\n\t\tG_CALLBACK( mainw_toolkitbrowser_action_cb ), FALSE },\n\n\t{ \"Tabdefs\",\n\t\tNULL, N_( \"Tab _Definitions\" ), NULL,\n\t\tN_( \"Show tab definitions\" ),\n\t\tG_CALLBACK( mainw_tabdefs_action_cb ), FALSE },\n};\n\nstatic GtkRadioActionEntry mainw_radio_actions[] = {\n\t{ \"Normal\",\n\t\tNULL, N_( \"_Normal\" ), NULL,\n\t\tN_( \"Normal view mode\" ),\n\t\tWORKSPACE_MODE_REGULAR },\n\n\t{ \"ShowFormula\",\n\t\tNULL, N_( \"Show _Formula\" ), NULL,\n\t\tN_( \"Show formula view mode\" ),\n\t\tWORKSPACE_MODE_FORMULA },\n\n\t{ \"NoEdit\",\n\t\tNULL, N_( \"No _Edits\" ), NULL,\n\t\tN_( \"No edits view mode\" ),\n\t\tWORKSPACE_MODE_NOEDIT },\n};\n\nstatic const char *mainw_menubar_ui_description =\n\"<ui>\"\n\"  <menubar name='MainwMenubar'>\"\n\"    <menu action='FileMenu'>\"\n\"      <menu action='NewMenu'>\"\n\"        <menuitem action='NewColumnName'/>\"\n\"        <menuitem action='NewTab'/>\"\n\"        <menuitem action='NewWorkspace'/>\"\n\"      </menu>\"\n\"      <menuitem action='Open'/>\"\n\"      <menu action='RecentMenu'>\"\n\"        <menuitem action='Stub'/>\"\t/* Dummy ... replaced on map */\n\"      </menu>\"\n\"      <menuitem action='OpenExamples'/>\"\n\"      <separator/>\"\n\"      <menuitem action='DuplicateWorkspace'/>\"\n\"      <menuitem action='Merge'/>\"\n\"      <menuitem action='Save'/>\"\n\"      <menuitem action='SaveAs'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Recover'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Close'/>\"\n\"      <menuitem action='Quit'/>\"\n\"    </menu>\"\n\"    <menu action='EditMenu'>\"\n\"      <menuitem action='Delete'/>\"\n\"      <menuitem action='SelectAll'/>\"\n\"      <menuitem action='Duplicate'/>\"\n\"      <menuitem action='Recalculate'/>\"\n\"      <menuitem action='AutoRecalculate'/>\"\n\"      <menuitem action='Lock'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Find'/>\"\n\"      <menuitem action='FindNext'/>\"\n\"      <menuitem action='NextError'/>\"\n\"      <menu action='JumpToColumnMenu'>\"\n\"        <menuitem action='Stub'/>\"\t/* Dummy ... replaced on map */\n\"      </menu>\"\n\"      <separator/>\"\n\"      <menuitem action='Group'/>\"\n\"      <menuitem action='Ungroup'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Preferences'/>\"\n\"    </menu>\"\n\"    <menu action='ViewMenu'>\"\n\"      <menuitem action='Toolbar'/>\"\n\"      <menuitem action='Statusbar'/>\"\n\"      <menuitem action='ToolkitBrowser'/>\"\n\"      <menuitem action='Tabdefs'/>\"\n\"      <separator/>\"\n#ifdef HAVE_LIBGVC\n\"      <menuitem action='Graph'/>\"\n\"      <separator/>\"\n#endif /*HAVE_LIBGVC*/\n\"      <menuitem action='Normal'/>\"\n\"      <menuitem action='ShowFormula'/>\"\n\"      <menuitem action='NoEdit'/>\"\n\"    </menu>\"\n\"    <menu action='ToolkitsMenu'>\"\n\"      <menuitem action='EditToolkits'/>\" \n\"      <separator/>\"\n\"      <menuitem action='Stub'/>\"\t/* Toolkits pasted here at runtime */\n\"    </menu>\"\n\"    <menu action='HelpMenu'>\"\n\"      <menuitem action='Guide'/>\"\n\"      <menuitem action='About'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Homepage'/>\"\n\"    </menu>\"\n\"  </menubar>\"\n\"</ui>\";\n\nstatic const char *mainw_toolbar_ui_description =\n\"<ui>\"\n\"  <toolbar name='MainwToolbar'>\"\n\"    <toolitem action='Open'/>\"\n\"    <toolitem action='SaveAs'/>\"\n\"    <toolitem action='NewWorkspace'/>\"\n\"    <toolitem action='DuplicateWorkspace'/>\"\n\"    <separator/>\"\n\"    <toolitem action='NewColumn'/>\"\n\"    <toolitem action='Duplicate'/>\"\n\"  </toolbar>\"\n\"</ui>\";\n\nstatic void\nmainw_watch_changed_cb( Watchgroup *watchgroup, Watch *watch, Mainw *mainw )\n{\n\tif( strcmp( IOBJECT( watch )->name, \"MAINW_TOOLBAR_STYLE\" ) == 0 )\n\t\tmainw->toolbar_visible = MAINW_TOOLBAR;\n\n\tmainw_refresh( mainw );\n}\n\n/* Make the insides of the panel.\n */\nstatic void\nmainw_build( iWindow *iwnd, GtkWidget *vbox )\n{\n\tMainw *mainw = MAINW( iwnd );\n\n        GtkWidget *mbar;\n\tGtkWidget *frame;\n\tGError *error;\n\tGtkWidget *cancel;\n\tGtkWidget *item;\n\n#ifdef DEBUG\n\tprintf( \"mainw_build: %p\\n\", mainw );\n#endif /*DEBUG*/\n\n        /* Make main menu bar\n         */\n\tgtk_action_group_add_actions( iwnd->action_group, \n\t\tmainw_actions, G_N_ELEMENTS( mainw_actions ), \n\t\tGTK_WINDOW( mainw ) );\n\tgtk_action_group_add_toggle_actions( iwnd->action_group, \n\t\tmainw_toggle_actions, G_N_ELEMENTS( mainw_toggle_actions ), \n\t\tGTK_WINDOW( mainw ) );\n\tgtk_action_group_add_radio_actions( iwnd->action_group,\n\t\tmainw_radio_actions, G_N_ELEMENTS( mainw_radio_actions ), \n\t\tWORKSPACE_MODE_REGULAR,\n\t\tG_CALLBACK( mainw_mode_action_cb ),\n\t\tGTK_WINDOW( mainw ) );\n\n\terror = NULL;\n\tif( !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager,\n\t\t\tmainw_menubar_ui_description, -1, &error ) ||\n\t\t!gtk_ui_manager_add_ui_from_string( iwnd->ui_manager,\n\t\t\tmainw_toolbar_ui_description, -1, &error ) ) {\n\t\tg_message( \"building menus failed: %s\", error->message );\n\t\tg_error_free( error );\n\t\texit( EXIT_FAILURE );\n\t}\n\n\tmbar = gtk_ui_manager_get_widget( iwnd->ui_manager, \"/MainwMenubar\" );\n\tgtk_box_pack_start( GTK_BOX( vbox ), mbar, FALSE, FALSE, 0 );\n        gtk_widget_show( mbar );\n\n\t/* Get the dummy item on the recent menu, then get the enclosing menu\n\t * for that dummy item.\n\t */\n        item = gtk_ui_manager_get_widget( iwnd->ui_manager,\n\t\t\"/MainwMenubar/FileMenu/RecentMenu/Stub\" );\n\tmainw->recent_menu = gtk_widget_get_parent( GTK_WIDGET( item ) );\n        gtk_signal_connect( GTK_OBJECT( mainw->recent_menu ), \"map\",\n                GTK_SIGNAL_FUNC( mainw_recent_map_cb ), mainw );\n\n\t/* Same for the column jump menu.\n\t */\n        item = gtk_ui_manager_get_widget( iwnd->ui_manager,\n\t\t\"/MainwMenubar/EditMenu/JumpToColumnMenu/Stub\" );\n\tmainw->jump_to_column_menu = \n\t\tgtk_widget_get_parent( GTK_WIDGET( item ) );\n\n\t/* Same for the tk menu. \n\t */\n        item = gtk_ui_manager_get_widget( iwnd->ui_manager,\n\t\t\"/MainwMenubar/ToolkitsMenu/Stub\" );\n        mainw->toolkit_menu = gtk_widget_get_parent( GTK_WIDGET( item ) );\n\tgtk_widget_destroy( item ); \n\n\t/* Attach toolbar.\n  \t */\n\tmainw->toolbar = gtk_ui_manager_get_widget( \n\t\tiwnd->ui_manager, \"/MainwToolbar\" );\n\tgtk_box_pack_start( GTK_BOX( vbox ), mainw->toolbar, FALSE, FALSE, 0 );\n        widget_visible( mainw->toolbar, MAINW_TOOLBAR );\n\n\t/* This will set to NULL if we don't have infobar support.\n\t */\n\tif( (IWINDOW( mainw )->infobar = infobar_new()) ) \n\t\tgtk_box_pack_start( GTK_BOX( vbox ), \n\t\t\tGTK_WIDGET( IWINDOW( mainw )->infobar ), \n\t\t\tFALSE, FALSE, 0 );\n\n\t/* hbox for status bar etc.\n\t */\n        mainw->statusbar_main = gtk_hbox_new( FALSE, 2 );\n        gtk_box_pack_end( GTK_BOX( vbox ), \n\t\tmainw->statusbar_main, FALSE, FALSE, 2 );\n        widget_visible( mainw->statusbar_main, MAINW_STATUSBAR );\n\n\t/* Make space free label.\n\t */\n\tmainw->space_free_eb = gtk_event_box_new();\n        gtk_box_pack_start( GTK_BOX( mainw->statusbar_main ), \n\t\tmainw->space_free_eb, FALSE, FALSE, 0 );\n\tgtk_widget_show( mainw->space_free_eb );\n\tframe = gtk_frame_new( NULL );\n\tgtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_IN );\n\tgtk_container_add( GTK_CONTAINER( mainw->space_free_eb ), frame );\n\tgtk_widget_show( frame );\n\tmainw->space_free = gtk_label_new( \"space_free\" );\n\tgtk_misc_set_padding( GTK_MISC( mainw->space_free ), 2, 2 );\n        gtk_container_add( GTK_CONTAINER( frame ), mainw->space_free );\n        gtk_signal_connect( GTK_OBJECT( mainw->space_free_eb ), \"event\",\n                GTK_SIGNAL_FUNC( mainw_space_free_event ), mainw );\n\tset_tooltip_generate( mainw->space_free_eb,\n\t\t(TooltipGenerateFn) mainw_space_free_tooltip_generate, \n\t\tmainw, NULL );\n        gtk_widget_show( mainw->space_free );\n\tmainw->imageinfo_changed_sid = g_signal_connect( main_imageinfogroup, \n\t\t\"changed\",\n\t\tG_CALLBACK( mainw_free_changed_cb ), mainw );\n\tmainw->heap_changed_sid = g_signal_connect( reduce_context->heap, \n\t\t\"changed\",\n\t\tG_CALLBACK( mainw_free_changed_cb ), mainw );\n\n\t/* Make message label.\n\t */\n\tmainw->statusbar = gtk_label_new( \"\" );\n\tgtk_label_set_ellipsize( GTK_LABEL( mainw->statusbar ), \n\t\tPANGO_ELLIPSIZE_MIDDLE );\n\t/* 6 is enough to stop the statusbar changing height when the progress\n\t * indicator changes visibility.\n\t */\n\tgtk_misc_set_padding( GTK_MISC( mainw->statusbar ), 2, 6 );\n\tgtk_misc_set_alignment( GTK_MISC( mainw->statusbar ), 0.0, 0.5 );\n        gtk_box_pack_start( GTK_BOX( mainw->statusbar_main ), \n\t\tmainw->statusbar, TRUE, TRUE, 0 );\n        gtk_widget_show( mainw->statusbar );\n\n        mainw->progress_box = gtk_hbox_new( FALSE, 2 );\n\n\tmainw->progress = gtk_progress_bar_new();\n\tgtk_widget_set_size_request( GTK_WIDGET( mainw->progress ), 200, -1 );\n        gtk_box_pack_end( GTK_BOX( mainw->progress_box ), mainw->progress, \n\t\tFALSE, TRUE, 0 );\n        gtk_widget_show( mainw->progress );\n\n        cancel = gtk_button_new_with_label( \"Cancel\" );\n        g_signal_connect( cancel, \"clicked\",\n                G_CALLBACK( mainw_cancel_cb ), mainw );\n        gtk_box_pack_end( GTK_BOX( mainw->progress_box ), cancel, \n\t\tFALSE, TRUE, 0 );\n        gtk_widget_show( cancel );\n\n        gtk_box_pack_end( GTK_BOX( mainw->statusbar_main ), \n\t\tmainw->progress_box, FALSE, TRUE, 0 );\n\n\tmainw->wsgview = WORKSPACEGROUPVIEW( workspacegroupview_new() );\n\tgtk_box_pack_start( GTK_BOX( vbox ), \n\t\tGTK_WIDGET( mainw->wsgview ), TRUE, TRUE, 0 );\n\tview_link( VIEW( mainw->wsgview ), MODEL( mainw->wsg ), NULL );\n\tgtk_widget_show( GTK_WIDGET( mainw->wsgview ) );\n\n\t/* Any changes to prefs, refresh (yuk!).\n\t */\n\tmainw->watch_changed_sid = g_signal_connect( main_watchgroup, \n\t\t\"watch_changed\",\n\t\tG_CALLBACK( mainw_watch_changed_cb ), mainw );\n}\n\nstatic void\nmainw_popdown( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys )\n{\n\tMainw *mainw = MAINW( iwnd );\n\n\t/* We can be destroyed in two ways: either our iwnd tells us to go, or\n\t * our model is destroyed under us. If the model has gone, we just go.\n\t * If the model is still there, we need to ask about saving and\n\t * quitting.\n\t */\n\n\tif( mainw->wsg )  \n\t\tfilemodel_inter_savenclose_cb( IWINDOW( mainw ), \n\t\t\tFILEMODEL( mainw->wsg ), nfn, sys );\n\telse\n\t\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nmainw_wsg_changed_cb( Workspacegroup *wsg, Mainw *mainw )\n{\n\tmainw_refresh( mainw );\n}\n\nstatic void\nmainw_wsg_destroy_cb( Workspacegroup *wsg, Mainw *mainw )\n{\n\tmainw->wsg = NULL;\n}\n\nstatic void\nmainw_link( Mainw *mainw, Workspacegroup *wsg )\n{\n\tWorkspace *ws = workspacegroup_get_workspace( wsg );\n\n\t/* Take ownership of the wsg.\n\t */\n\tmainw->wsg = wsg;\n\tg_object_ref( G_OBJECT( mainw->wsg ) );\n\tiobject_sink( IOBJECT( mainw->wsg ) );\n\n\twsg->iwnd = IWINDOW( mainw );\n\n\tiwindow_set_build( IWINDOW( mainw ), \n\t\t(iWindowBuildFn) mainw_build, wsg, NULL, NULL );\n\tiwindow_set_popdown( IWINDOW( mainw ), mainw_popdown, NULL );\n\tiwindow_set_size_prefs( IWINDOW( mainw ), \n\t\t\"MAINW_WINDOW_WIDTH\", \"MAINW_WINDOW_HEIGHT\" );\n\tiwindow_build( IWINDOW( mainw ) );\n\n\tif( ws &&\n\t\tMODEL( ws )->window_width != - 1 ) \n\t\tgtk_window_set_default_size( GTK_WINDOW( mainw ), \n\t\t\tMODEL( ws )->window_width, \n\t\t\tMODEL( ws )->window_height );  \n\n\t/* Set start state.\n\t */\n\t(void) mainw_refresh( mainw );\n\n\tmainw->changed_sid = g_signal_connect( mainw->wsg, \n\t\t\"changed\", \n\t\tG_CALLBACK( mainw_wsg_changed_cb ), mainw );\n\tmainw->destroy_sid = g_signal_connect( mainw->wsg, \n\t\t\"destroy\", \n\t\tG_CALLBACK( mainw_wsg_destroy_cb ), mainw );\n}\n\nMainw *\nmainw_new( Workspacegroup *wsg )\n{\n\tMainw *mainw;\n\n\tmainw = MAINW( g_object_new( TYPE_MAINW, NULL ) );\n\n\tmainw_link( mainw, wsg );\n\n\treturn( mainw );\n}\n\nstatic void *\nmainw_cull_sub( Mainw *mainw )\n{\n\tif( !ICONTAINER( mainw->wsg )->children ) {\n\t\tfilemodel_set_modified( FILEMODEL( mainw->wsg ), FALSE );\n\t\tiwindow_kill( IWINDOW( mainw ) );\n\t}\n\n\treturn( NULL );\n}\n\nvoid\nmainw_cull( void )\n{\n\tslist_map( mainw_all,\n\t\t(SListMapFn) mainw_cull_sub, NULL );\n}\n\nstatic void *\nmainw_layout_sub( Workspace *ws )\n{\n\tmodel_layout( MODEL( ws ) );\n\tworkspace_set_needs_layout( ws, FALSE );\n\n\treturn( NULL ); \n}\n\nstatic gboolean\nmainw_layout_timeout_cb( gpointer user_data )\n{\n\tmainw_layout_timeout = 0;\n\n\tslist_map( workspace_get_needs_layout(),\n\t\t(SListMapFn) mainw_layout_sub, NULL );\n\n\treturn( FALSE ); \n}\n\nvoid\nmainw_layout( void )\n{\n\tIM_FREEF( g_source_remove, mainw_layout_timeout );\n\tmainw_layout_timeout = g_timeout_add( 300, \n\t\t(GSourceFunc) mainw_layout_timeout_cb, NULL );\n}\n"
  },
  {
    "path": "src/mainw.h",
    "content": "/* A top level window holding some workspaces\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_MAINW (mainw_get_type())\n#define MAINW( obj ) (GTK_CHECK_CAST( (obj), TYPE_MAINW, Mainw ))\n#define MAINW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_MAINW, MainwClass ))\n#define IS_MAINW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_MAINW ))\n#define IS_MAINW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_MAINW ))\n\n/* Get a widget's enclosing Mainw.\n */\n#define GET_MAINW( W ) \\\n\tMAINW( idialog_get_root( GTK_WIDGET( W ) ) )\n\nstruct _Mainw {\n\tiWindow parent_object;\n\n\t/* Our model.\n\t */\n\tWorkspacegroup *wsg;\n\tguint changed_sid;\n\tguint destroy_sid;\n\n\t/* Watch for changed on heap and image, and prefs. Use to update\n\t * status bar and space free.\n\t */\n\tguint imageinfo_changed_sid;\n\tguint heap_changed_sid;\n\tguint watch_changed_sid;\n\n\t/* Link to progress system.\n\t */\n\tguint begin_sid;\t\n\tguint update_sid;\t\n\tguint end_sid;\t\n\tgboolean cancel;\n\n\t/* Batch refresh with this, it's slow.\n\t */\n\tguint refresh_timeout;\n\n\t/* Display MB free in tmp, or cells free in heap.\n\t */\n\tgboolean free_type;\n\n\t/* View menu show/hide toggle states. The pane states are in the ws as\n\t * we need to save them to the ws file.\n\t */\n\tgboolean toolbar_visible;\n\tgboolean statusbar_visible;\n\n\t/* The kitg the toolkit menu is currently displaying. Use this to\n\t * avoid rebuilding the toolkit menu on every tab switch.\n\t */\n\tToolkitgroup *kitg;\n\n\t/* Component widgets.\n\t */\n\tToolkitgroupview *kitgview;\n\tGtkWidget *toolbar;\n\tGtkWidget *recent_menu;\n\tGtkWidget *jump_to_column_menu;\n\tGtkWidget *toolkit_menu;\n\n\tWorkspacegroupview *wsgview;\n\n\tGtkWidget *statusbar_main;\n\tGtkWidget *statusbar;\n\tGtkWidget *space_free;\t\n\tGtkWidget *space_free_eb;\t\n\tGtkWidget *progress_box;\n\tGtkWidget *progress;\n};\n\ntypedef struct _MainwClass {\n\tiWindowClass parent_class;\n\n\t/* My methods.\n\t */\n} MainwClass;\n\nextern GSList *mainw_recent_workspace;\nextern GSList *mainw_recent_image;\nextern GSList *mainw_recent_matrix;\n\nextern gboolean mainw_auto_recalc;\n\nextern gboolean mainw_cancel;\n\nvoid mainw_startup( void );\nvoid mainw_shutdown( void );\nvoid mainw_recent_freeze( void );\nvoid mainw_recent_thaw( void );\nvoid mainw_recent_add( GSList **recent, const char *filename );\n\nMainw *mainw_pick_one( void );\nGType mainw_get_type( void );\n\nvoid mainw_find_disc( VipsBuf *buf );\nvoid mainw_find_heap( VipsBuf *buf, Heap *heap );\n\nWorkspace *mainw_get_workspace( Mainw *mainw );\n\nvoid mainw_homepage_action_cb( GtkAction *action, iWindow *iwnd );\nvoid mainw_about_action_cb( GtkAction *action, iWindow *iwnd );\nvoid mainw_guide_action_cb( GtkAction *action, iWindow *iwnd );\n\nvoid mainw_column_new_action_cb( GtkAction *action, Mainw *mainw );\nvoid mainw_workspace_merge( Mainw *mainw );\nvoid mainw_workspace_merge_action_cb( GtkAction *action, Mainw *mainw );\nvoid mainw_layout_action_cb( GtkAction *action, Mainw *mainw );\nvoid mainw_group_action_cb( GtkAction *action, Mainw *mainw );\nvoid mainw_next_error_action_cb( GtkAction *action, Mainw *mainw );\nvoid mainw_open_action_cb( GtkAction *action, Mainw *mainw );\n\nWorkspacegroup *mainw_open_workspace( Workspaceroot *wsr, \n\tconst char *filename );\n\nMainw *mainw_new( Workspacegroup *wsg );\n\nvoid mainw_cull( void );\n\nvoid mainw_layout( void );\n"
  },
  {
    "path": "src/makehelpindex.pl",
    "content": "#!/usr/bin/perl\n\n# html docs in $VIPSHOME/share/nip2/doc/html include extra anchor tags\n# generated from \\mylabel{} stuff in doc src (nip2-xx/doc/src/nipguide)\n#\n# latex source\n#\n#    \t\\section{Image view window}\n#    \t\\mylabel{sec:view}\n#\n# generates html which includes\n#\n#\t<a NAME=\"nip_label_sec:view\"> </a>\n#\n# scan all html files in $VIPSHOME/share/nip2/doc/html for patterns like this,\n# and generate C along the lines of:\n#\n#\t{ \"sec:view\", \"node4.html#nip_label_sec:view\" },\n#\n# this is includes in boxes.c ... then on \n#\n#\tbox_help( par, \"sec:view\" )\n# \n# we can pop up a web browser pointing at the right place in the docs\n\n$prefix = @ARGV[0];\n$docbase = \"$prefix/share/doc/nip2/html\";\n\nopendir( SDIR, \"$docbase\" );\n\nwhile( $filename = readdir SDIR ) {\n\tif( $filename =~ /.html$/ ) {\n\t\topen( HTMLFILE, \"$docbase/$filename\" );\n\n\t\twhile( <HTMLFILE> ) {\n\t\t\tif( /\"nip_label_([^\"]*)\"/ ) {\n\t\t\t\tprint \"{ \\\"$1\\\", \\\"$filename#nip_label_\" .\n\t\t\t\t\t\"$1\\\" },\\n\";\n\t\t\t}\n\t\t}\n\n\t\tclose( HTMLFILE );\n\t}\n}\n\nclosedir( SDIR );\n\n"
  },
  {
    "path": "src/managed.c",
    "content": "/* managed objects ... things like Imageinfo which are lifetime managed by\n * both the GC and by pointers from C: we need to both mark/sweep and refcount\n * \n * abstract class: Managedgvalue, Imageinfo, etc. build off this\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* get -DDEBUG_LEAK from the gcc command-line\n#define DEBUG\n */\n\nstatic iContainerClass *parent_class = NULL;\n\n#ifdef DEBUG_LEAK\nstatic GSList *managed_all = NULL;\n#endif /*DEBUG_LEAK*/\n\n#ifdef DEBUG_LEAK\nstatic void *\nmanaged_print_info( Managed *managed, VipsBuf *buf )\n{\n\tiobject_info( IOBJECT( managed ), buf );\n\tvips_buf_appends( buf, \"\\n\" );\n\n\treturn( NULL );\n}\n#endif /*DEBUG_LEAK*/\n\n/* Debugging ... check that all manageds have been closed, dump any which\n * haven't.\n */\nvoid\nmanaged_check_all_destroyed( void )\n{\n#ifdef DEBUG_LEAK\n\tif( managed_all ) {\n\t\tchar txt[1000];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\tprintf( \"managed_check_all_destroyed:\\n\" );\n\t\tslist_map( managed_all, (SListMapFn) managed_print_info, &buf );\n\t\tprintf( \"%s\", vips_buf_all( &buf ) );\n\t}\n#endif /*DEBUG_LEAK*/\n}\n\nvoid \nmanaged_link_heap( Managed *managed, Heap *heap )\n{\n\tg_assert( !managed->heap );\n\n\tif( heap == NULL )\n\t\theap = reduce_context->heap;\n\tmanaged->heap = heap;\n\tg_hash_table_insert( heap->mtable, managed, managed );\n\tmanaged->attached = TRUE;\n\n\t/* The mtable owns our ref.\n\t */\n\tg_object_ref( G_OBJECT( managed ) );\n\tiobject_sink( IOBJECT( managed ) );\n}\n\nstatic void \nmanaged_unlink_heap( Managed *managed )\n{\n\tif( managed->attached && managed->heap ) {\n\t\tg_hash_table_remove( managed->heap->mtable, managed );\n\t\tmanaged->attached = FALSE;\n\t\tg_object_unref( G_OBJECT( managed ) );\n\t}\n}\n\n/* managed no longer depends upon in.\n */\nvoid *\nmanaged_sub_remove( Managed *in, Managed *managed )\n{\n\tg_assert( g_slist_find( managed->sub, in ) );\n\n\tmanaged->sub = g_slist_remove( managed->sub, in );\n\tmanaged_destroy_nonheap( in );\n\n\treturn( NULL );\n}\n\nstatic void\nmanaged_dispose( GObject *gobject )\n{\n\tManaged *managed = MANAGED( gobject );\n\n#ifdef DEBUG\n\tprintf( \"managed_dispose: \" );\n\tiobject_print( IOBJECT( managed ) );\n#endif /*DEBUG*/\n\n\tg_assert( managed->count == 0 );\n\n\tmanaged_unlink_heap( managed );\n\tslist_map( managed->sub, \n\t\t(SListMapFn) managed_sub_remove, managed );\n\tg_assert( !managed->sub );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\n/* Final death!\n */\nstatic void \nmanaged_finalize( GObject *gobject )\n{\n#ifdef DEBUG\n\tManaged *managed = MANAGED( gobject );\n\n\tprintf( \"managed_finalize:\" ); \n\tiobject_print( IOBJECT( managed ) );\n#endif /*DEBUG*/\n\n#ifdef DEBUG_LEAK\n\tmanaged_all = g_slist_remove( managed_all, gobject );\n#endif /*DEBUG_LEAK*/\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\n/* _info() is used by itext.c to display managed objects. Don't chain\n * up, don't print more than one line.\n */\nstatic void\nmanaged_info( iObject *iobject, VipsBuf *buf )\n{\n#ifdef DEBUG\n\tManaged *managed = MANAGED( iobject );\n\n\tvips_buf_appendf( buf, \"managed-object %p\\n\", managed );\n\tvips_buf_appendf( buf, \"managed->count = %d\\n\", managed->count );\n\tvips_buf_appendf( buf, \"managed->marked = %d\\n\", managed->marked );\n#endif /*DEBUG*/\n\n\tvips_buf_appendf( buf, \"%s %p\", G_OBJECT_TYPE_NAME( iobject ), iobject );\n}\n\nstatic void\nmanaged_class_init( ManagedClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tiObjectClass *iobject_class = IOBJECT_CLASS( class );\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = managed_dispose;\n\tgobject_class->finalize = managed_finalize;\n\n\tiobject_class->info = managed_info;\n\n\tclass->keepalive = 0;\n}\n\nstatic void\nmanaged_init( Managed *managed )\n{\n#ifdef DEBUG\n\tprintf( \"managed_init: %p\\n\", managed );\n#endif /*DEBUG*/\n\n\tmanaged->heap = NULL;\n\tmanaged->attached = FALSE;\n\n\t/* Init to TRUE, so we won't close until (at least) the next GC.\n\t */\n\tmanaged->marked = TRUE;\n\n\t/* Start with a count of zero (unlike gobject!). We will be deleted\n\t * on the next GC unless our caller refs us.\n\t */\n\tmanaged->count = 0;\n\n\t/* When we're unreffed, become a zombie first, then destroy after a\n\t * (possibly zero) interval.\n\t */\n\tmanaged->zombie = FALSE;\n\tmanaged->time = 0;\n\n\tmanaged->sub = NULL;\n\n#ifdef DEBUG_LEAK\n\tmanaged_all = g_slist_prepend( managed_all, managed );\n#endif /*DEBUG_LEAK*/\n}\n\nGType\nmanaged_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ManagedClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) managed_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Managed ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) managed_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_ICONTAINER, \n\t\t\t\"Managed\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\n/* From heap_gc() ... no heap pointers left, delete if there are no\n * non-heap pointers either.\n */\nvoid\nmanaged_destroy_heap( Managed *managed )\n{\n#ifdef DEBUG\n\tprintf( \"managed_destroy_heap: \" );\n\tiobject_print( IOBJECT( managed ) );\n#endif /*DEBUG*/\n\n\t/* All non-heaps gone too?\n\t */\n\tif( !managed->count ) \n\t\tIDESTROY( managed );\n}\n\n/* destroy() for non-heap pointers.\n */\nvoid *\nmanaged_destroy_nonheap( Managed *managed )\n{\n\tg_assert( managed->count > 0 );\n\n#ifdef DEBUG\n\tprintf( \"managed_destroy_nonheap: count = %d \", managed->count );\n\tiobject_print( IOBJECT( managed ) );\n#endif /*DEBUG*/\n\n\tmanaged->count--;\n\n\t/* We can't destroy the managed if count == 0 && it's not marked,\n\t * since a heap pointer might have been created to it since the last\n\t * GC. Queue a GC to clean off stray manageds.\n\t */\n\theap_gc_request( managed->heap );\n\n\treturn( NULL );\n}\n\n/* Create a new non-heap pointer.\n */\nvoid\nmanaged_dup_nonheap( Managed *managed )\n{\n\tg_assert( managed->count >= 0 );\n\n\tmanaged->count++;\n\n#ifdef DEBUG\n\tprintf( \"managed_dup_nonheap: count = %d \", managed->count );\n\tiobject_print( IOBJECT( managed ) );\n#endif /*DEBUG*/\n}\n\n/* managed depends on in ... add a dependency.\n */\nvoid \nmanaged_sub_add( Managed *managed, Managed *in )\n{\n\tg_assert( managed && in );\n\n\tmanaged->sub = g_slist_prepend( managed->sub, in );\n\tmanaged_dup_nonheap( in );\n}\n\n/* out needs all of in[], add to sub-mark-list.\n */\nvoid \nmanaged_sub_add_all( Managed *out, int nin, Managed **in )\n{\n\tint i;\n\n\tif( out )\n\t\tfor( i = 0; i < nin; i++ )\n\t\t\tmanaged_sub_add( out, in[i] );\n}\n\n\nstatic void \nmanaged_clear_sub( void *key, Managed *managed )\n{\n\tmanaged->marked = FALSE;\n}\n\nvoid \nmanaged_clear( Heap *heap )\n{\n\tg_hash_table_foreach( heap->mtable, \n\t\t(GHFunc) managed_clear_sub, NULL );\n}\n\n/* Mark as being used ... also mark all sub-objects.\n */\nvoid \nmanaged_mark( Managed *managed )\n{\n\tif( !managed->marked ) {\n\t\tmanaged->marked = TRUE;\n\t\t(void) slist_map( managed->sub, \n\t\t\t(SListMapFn) managed_mark, NULL );\n\t}\n}\n\n/* Use a timer to remove unreffed keepalive objects after some\n * interval.\n */\nstatic GTimer *zombie_timer = NULL;\nstatic double zombie_elapsed;\n\nstatic gboolean \nmanaged_free_unused_sub( void *key, Managed *managed, gboolean *changed )\n{ \n\tManagedClass *managed_class = MANAGED_GET_CLASS( managed );\n\tHeap *heap = managed->heap;\n\tgboolean remove = FALSE;\n\n\tif( !managed->marked && !managed->count ) {\n\t\tif( !managed->zombie ) {\n\t\t\t/* Unreffed, but not marked as a zombie.\n\t\t\t */\n#ifdef DEBUG\n\t\t\tprintf( \"managed_free: zombiefying: \" );\n\t\t\tiobject_print( IOBJECT( managed ) );\n#endif /*DEBUG*/\n\n\t\t\tmanaged->zombie = TRUE;\n\t\t\tmanaged->time = zombie_elapsed;\n\t\t}\n\t}\n\telse {\n\t\tif( managed->zombie ) {\n\t\t\t/* Reffed, but marked as a zombie. Back to life again.\n\t\t\t */\n#ifdef DEBUG\n\t\t\tprintf( \"managed_free: resuscitating: \" );\n\t\t\tiobject_print( IOBJECT( managed ) );\n#endif /*DEBUG*/\n\t\t\t\n\t\t\tmanaged->zombie = FALSE;\n\t\t\tmanaged->time = 0;\n\t\t}\n\t}\n\n\t/* Is this an old zombie? Or a not-so-old one and we're flushing?\n\t * Junk.\n\t */\n\tif( managed->zombie && \n\t\tzombie_elapsed - managed->time >= managed_class->keepalive ) \n\t\tremove = TRUE;\n\tif( managed->zombie && heap->flush )\n\t\tremove = TRUE;\n\n\tif( remove ) {\n#ifdef DEBUG\n\t\tprintf( \"managed_free: closing unreferenced object: \" );\n\t\tiobject_print( IOBJECT( managed ) );\n\t\tprintf( \"managed_free: after %g s as a zombie\\n\", \n\t\t\tzombie_elapsed - managed->time );\n#endif /*DEBUG*/\n\n\t\t/* We will return TRUE to unlink us from the hash table. Stop \n\t\t * managed_dispose unlinking for us, and drop the hash table's\n\t\t * reference.\n\t\t */\n\t\tmanaged->attached = FALSE;\n\t\tmanaged_destroy_heap( managed );\n\t\tg_object_unref( G_OBJECT( managed ) );\n\n\t\t*changed = TRUE;\n\t}\n\n\treturn( remove );\n}\n\n/* Make one sweep and destroy all unused managed objects. Return TRUE if we \n * removed any.\n */\ngboolean\nmanaged_free_unused( Heap *heap ) \n{\n\tgboolean changed;\n\n\tif( !zombie_timer )\n\t\tzombie_timer = g_timer_new();\n\tzombie_elapsed = g_timer_elapsed( zombie_timer, NULL );\n\n\tchanged = FALSE;\n\tg_hash_table_foreach_remove( heap->mtable, \n\t\t(GHRFunc) managed_free_unused_sub, &changed );\n\n\treturn( changed );\n}\n"
  },
  {
    "path": "src/managed.h",
    "content": "/* managed objects ... things like Imageinfo which are lifetime managed by\n * both the GC and by pointers from C: we need to both mark/sweep and refcount\n * \n * abstract class: Managedgvalue, Imageinfo, etc. build off this\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_MANAGED (managed_get_type())\n#define MANAGED( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MANAGED, Managed ))\n#define MANAGED_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_MANAGED, ManagedClass))\n#define IS_MANAGED( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MANAGED ))\n#define IS_MANAGED_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MANAGED ))\n#define MANAGED_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_MANAGED, ManagedClass ))\n\n#define MANAGED_UNREF( X ) { \\\n\tif( X ) { \\\n\t\tmanaged_destroy_nonheap( MANAGED( X ) ); \\\n\t\tX = NULL; \\\n\t} \\\n}\n#define MANAGED_REF( X ) managed_dup_nonheap( MANAGED( X ) )\n\nstruct _Managed {\n\tiContainer parent_object;\n\n\t/* Can't just set ->heap = NULL to mean unattached, our subclasses\n\t * rely on ->heap being valid even during dispose.\n\t */\n\n\tHeap *heap;\t\t/* Heap we are attached to */\n\tgboolean attached;\t/* If we are attached to the heap */\n\n\tgboolean marked;\t/* For mark-sweep */\n\tint count;\t\t/* Number of non-heap pointers to us */\n\tgboolean zombie;\t/* Unreffed, but being kept alive */\n\tdouble time;\t\t/* When we became a zombie */\n\n\t/* \n\n\t   \tFIXME ... This should go with vips8: it does dependency \n\t\ttracking for us.\n\n\t */\n\tGSList *sub;\t\t/* Sub-objects ... mark these if we mark this */\n\n\t/* Set by subclasses as part of construction.\n\t */\n\tguint hash;\n};\n\ntypedef struct _ManagedClass {\n\tiContainerClass parent_class;\n\n\t/* How long after zombiefying before we unref.\n\t */\n\tdouble keepalive;\n} ManagedClass;\n\nvoid managed_check_all_destroyed( void );\n\nvoid managed_link_heap( Managed *managed, Heap *heap );\n\nvoid managed_destroy_heap( Managed *managed );\nvoid *managed_destroy_nonheap( Managed *managed );\nvoid managed_dup_nonheap( Managed *managed );\n\nvoid *managed_sub_remove( Managed *in, Managed *managed );\nvoid managed_sub_add( Managed *managed, Managed *in );\nvoid managed_sub_add_all( Managed *out, int nin, Managed **in );\n\nGType managed_get_type( void );\n\nvoid managed_clear( Heap *heap );\nvoid managed_mark( Managed *managed );\ngboolean managed_free_unused( Heap *heap );\n"
  },
  {
    "path": "src/managedfile.c",
    "content": "/* a managed FILE* ... for lazy file read\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* \n#define DEBUG\n */\n\nstatic ManagedClass *parent_class = NULL;\n\nstatic void\nmanagedfile_dispose( GObject *gobject )\n{\n\tManagedfile *managedfile = MANAGEDFILE( gobject );\n\n#ifdef DEBUG\n\tprintf( \"managedfile_dispose: \" );\n\tiobject_print( IOBJECT( managedfile ) );\n#endif /*DEBUG*/\n\n\tIM_FREEF( ifile_close, managedfile->file );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\nmanagedfile_info( iObject *iobject, VipsBuf *buf )\n{\n\tManagedfile *managedfile = MANAGEDFILE( iobject );\n\n\tvips_buf_appendf( buf, \"managedfile->fp = %p\\n\", managedfile->file->fp );\n\tvips_buf_appendf( buf, \"managedfile->file->filename = %s\\n\", \n\t\tmanagedfile->file->fname );\n\tvips_buf_appendf( buf, \"managedfile->file->last_errno = %d\\n\", \n\t\tmanagedfile->file->last_errno );\n\n\tIOBJECT_CLASS( parent_class )->info( iobject, buf );\n}\n\nstatic void\nmanagedfile_class_init( ManagedfileClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tiObjectClass *iobject_class = IOBJECT_CLASS( class );\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = managedfile_dispose;\n\n\tiobject_class->info = managedfile_info;\n}\n\nstatic void\nmanagedfile_init( Managedfile *managedfile )\n{\n#ifdef DEBUG\n\tprintf( \"managedfile_init: %p\\n\", managedfile );\n#endif /*DEBUG*/\n\n\tmanagedfile->file = NULL;\n}\n\nGType\nmanagedfile_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ManagedfileClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) managedfile_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Managedfile ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) managedfile_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_MANAGED, \n\t\t\t\"Managedfile\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nManagedfile *\nmanagedfile_new( Heap *heap, const char *filename )\n{\n\tManagedfile *managedfile;\n\tiOpenFile *file;\n\n#ifdef DEBUG\n\tprintf( \"managedfile_new: %p: %s\\n\", managedfile, filename );\n#endif /*DEBUG*/\n\n\tif( !(file = ifile_open_read( \"%s\", filename )) )\n\t\treturn( NULL );\n\n\tmanagedfile = g_object_new( TYPE_MANAGEDFILE, NULL );\n\tmanaged_link_heap( MANAGED( managedfile ), heap );\n\tmanagedfile->file = file;\n\n\tMANAGED( managedfile )->hash = g_str_hash( filename );\n\n\treturn( managedfile );\n}\n\nint\nmanagedfile_getc( Managedfile *managedfile )\n{\n\tint ch = ifile_getc( managedfile->file );\n\n#ifdef DEBUG\n{\n\tchar in[2];\n\tchar out[3];\n\n\tin[0] = ch;\n\tin[1] = '\\0';\n\tmy_strecpy( out, in, FALSE );\n\tprintf( \"managedfile_getc: '%s' (%d)\\n\", out, ch );\n}\n#endif /*DEBUG*/\n\n\treturn( ch );\n}\n"
  },
  {
    "path": "src/managedfile.h",
    "content": "/* a managed FILE* ... for lazy file read\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_MANAGEDFILE (managedfile_get_type())\n#define MANAGEDFILE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MANAGEDFILE, Managedfile ))\n#define MANAGEDFILE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_MANAGEDFILE, ManagedfileClass))\n#define IS_MANAGEDFILE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MANAGEDFILE ))\n#define IS_MANAGEDFILE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MANAGEDFILE ))\n#define MANAGEDFILE_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), \\\n\t\tTYPE_MANAGEDFILE, ManagedfileClass ))\n\nstruct _Managedfile {\n\tManaged parent_object;\n\n\tiOpenFile *file;\n};\n\ntypedef struct _ManagedfileClass {\n\tManagedClass parent_class;\n\n} ManagedfileClass;\n\nGType managedfile_get_type( void );\n\nManagedfile *managedfile_new( Heap *heap, const char *filename );\nint managedfile_getc( Managedfile *managedfile );\n"
  },
  {
    "path": "src/managedgobject.c",
    "content": "/* a managed gobject \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* \n#define DEBUG\n */\n\nstatic ManagedClass *parent_class = NULL;\n\nstatic void\nmanagedgobject_dispose( GObject *gobject )\n{\n\tManagedgobject *managedgobject = MANAGEDGOBJECT( gobject );\n\n#ifdef DEBUG\n\tprintf( \"managedgobject_dispose: \" );\n\tiobject_print( IOBJECT( managedgobject ) );\n#endif /*DEBUG*/\n\n\tIM_FREEF( g_object_unref, managedgobject->object );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\nmanagedgobject_info( iObject *iobject, VipsBuf *buf )\n{\n\tManagedgobject *managedgobject = MANAGEDGOBJECT( iobject );\n\n\tif( VIPS_IS_OBJECT( managedgobject->object ) )\n\t\tvips_object_summary( VIPS_OBJECT( managedgobject->object ), \n\t\t\tbuf ); \n\telse\n\t\tIOBJECT_CLASS( parent_class )->info( iobject, buf );\n}\n\n\nstatic void\nmanagedgobject_class_init( ManagedgobjectClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tiObjectClass *iobject_class = IOBJECT_CLASS( class );\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = managedgobject_dispose;\n\n\tiobject_class->info = managedgobject_info;\n}\n\nstatic void\nmanagedgobject_init( Managedgobject *managedgobject )\n{\n#ifdef DEBUG\n\tprintf( \"managedgobject_init: %p\\n\", managedgobject );\n#endif /*DEBUG*/\n\n\tmanagedgobject->object = NULL;\n}\n\nGType\nmanagedgobject_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ManagedgobjectClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) managedgobject_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Managedgobject ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) managedgobject_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_MANAGED, \n\t\t\t\"Managedgobject\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nManagedgobject *\nmanagedgobject_new( Heap *heap, GObject *object )\n{\n\tManagedgobject *managedgobject = \n\t\tg_object_new( TYPE_MANAGEDGOBJECT, NULL );\n\n\tmanaged_link_heap( MANAGED( managedgobject ), heap );\n\tmanagedgobject->object = object;\n\tg_object_ref( object );\n\n\tMANAGED( managedgobject )->hash = GPOINTER_TO_UINT( object ); \n\n\treturn( managedgobject );\n}\n"
  },
  {
    "path": "src/managedgobject.h",
    "content": "/* a managed gobject \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_MANAGEDGOBJECT (managedgobject_get_type())\n#define MANAGEDGOBJECT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MANAGEDGOBJECT, Managedgobject ))\n#define MANAGEDGOBJECT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_MANAGEDGOBJECT, ManagedgobjectClass))\n#define IS_MANAGEDGOBJECT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MANAGEDGOBJECT ))\n#define IS_MANAGEDGOBJECT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MANAGEDGOBJECT ))\n#define MANAGEDGOBJECT_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), \\\n\t\tTYPE_MANAGEDGOBJECT, ManagedgobjectClass ))\n\nstruct _Managedgobject {\n\tManaged parent_object;\n\n\tGObject *object;\n};\n\ntypedef struct _ManagedgobjectClass {\n\tManagedClass parent_class;\n\n} ManagedgobjectClass;\n\nGType managedgobject_get_type( void );\n\nManagedgobject *managedgobject_new( Heap *heap, GObject *value );\n"
  },
  {
    "path": "src/managedgvalue.c",
    "content": "/* a managedgvalue gvalue \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* \n#define DEBUG\n */\n\nstatic ManagedClass *parent_class = NULL;\n\nstatic void\nmanagedgvalue_dispose( GObject *gobject )\n{\n\tManagedgvalue *managedgvalue = MANAGEDGVALUE( gobject );\n\n#ifdef DEBUG\n\tprintf( \"managedgvalue_dispose: \" );\n\tiobject_print( IOBJECT( managedgvalue ) );\n#endif /*DEBUG*/\n\n\tg_value_unset( &managedgvalue->value );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\nmanagedgvalue_info( iObject *iobject, VipsBuf *buf )\n{\n\tManagedgvalue *managedgvalue = MANAGEDGVALUE( iobject );\n\tchar *value_str;\n\n\tvalue_str = g_strdup_value_contents( &managedgvalue->value );\n\tvips_buf_appendf( buf, \"managedgvalue->value = %s\\n\", value_str );\n\tg_free( value_str );\n\n\tIOBJECT_CLASS( parent_class )->info( iobject, buf );\n}\n\nstatic void\nmanagedgvalue_class_init( ManagedgvalueClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tiObjectClass *iobject_class = IOBJECT_CLASS( class );\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = managedgvalue_dispose;\n\n\tiobject_class->info = managedgvalue_info;\n}\n\nstatic void\nmanagedgvalue_init( Managedgvalue *managedgvalue )\n{\n#ifdef DEBUG\n\tprintf( \"managedgvalue_init: %p\\n\", managedgvalue );\n#endif /*DEBUG*/\n\n\tmemset( &managedgvalue->value, 0, sizeof( GValue ) );\n}\n\nGType\nmanagedgvalue_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ManagedgvalueClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) managedgvalue_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Managedgvalue ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) managedgvalue_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_MANAGED, \n\t\t\t\"Managedgvalue\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nvoid \nmanagedgvalue_set_value( Managedgvalue *managedgvalue, GValue *value )\n{\n\tg_value_unset( &managedgvalue->value );\n\tg_value_init( &managedgvalue->value, G_VALUE_TYPE( value ) );\n\tg_value_copy( &managedgvalue->value, value );\n}\n\nManagedgvalue *\nmanagedgvalue_new( Heap *heap, GValue *value )\n{\n\tManagedgvalue *managedgvalue = g_object_new( TYPE_MANAGEDGVALUE, NULL );\n\n\tmanaged_link_heap( MANAGED( managedgvalue ), heap );\n\tmanagedgvalue_set_value( managedgvalue, value );\n\n\t/* Not a very good hash.\n\t */\n\tMANAGED( managedgvalue )->hash = (guint) G_VALUE_TYPE( value );\n\n\treturn( managedgvalue );\n}\n"
  },
  {
    "path": "src/managedgvalue.h",
    "content": "/* a managed gvalue \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_MANAGEDGVALUE (managedgvalue_get_type())\n#define MANAGEDGVALUE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MANAGEDGVALUE, Managedgvalue ))\n#define MANAGEDGVALUE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_MANAGEDGVALUE, ManagedgvalueClass))\n#define IS_MANAGEDGVALUE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MANAGEDGVALUE ))\n#define IS_MANAGEDGVALUE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MANAGEDGVALUE ))\n#define MANAGEDGVALUE_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), \\\n\t\tTYPE_MANAGEDGVALUE, ManagedgvalueClass ))\n\nstruct _Managedgvalue {\n\tManaged parent_object;\n\n\tGValue value;\n};\n\ntypedef struct _ManagedgvalueClass {\n\tManagedClass parent_class;\n\n} ManagedgvalueClass;\n\nGType managedgvalue_get_type( void );\n\nvoid managedgvalue_set_value( Managedgvalue *managedgvalue, GValue *value );\nManagedgvalue *managedgvalue_new( Heap *heap, GValue *value );\n"
  },
  {
    "path": "src/managedstring.c",
    "content": "/* a managed FILE* ... for lazy file read\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* \n#define DEBUG\n */\n\nstatic ManagedClass *parent_class = NULL;\n\n/* Track all instances here. \n */\nstatic GHashTable *managedstring_all = NULL;\n\n#ifdef DEBUG\n/* Number of managed strings, number we have expanded to the heap.\n */\nint managed_total = 0;\nint managed_expanded = 0;\n#endif /*DEBUG*/\n\nstatic void\nmanagedstring_finalize( GObject *gobject )\n{\n\tManagedstring *managedstring = MANAGEDSTRING( gobject );\n\n#ifdef DEBUG\n\tprintf( \"managedstring_finalize: \\\"%s\\\", \", managedstring->string );\n\tiobject_print( IOBJECT( managedstring ) );\n#endif /*DEBUG*/\n\n#ifdef DEBUG\n{\n\tPElement pe;\n\n\tPEPOINTE( &pe, &managedstring->e );\n\tif( !PEISNOVAL( &pe ) ) \n\t\tmanaged_expanded -= 1;\n\tmanaged_total -= 1;\n}\n#endif /*DEBUG*/\n\n\theap_unregister_element( MANAGED( managedstring )->heap, \n\t\t&managedstring->e );\n\tg_hash_table_remove( managedstring_all, managedstring );\n\tIM_FREE( managedstring->string );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\nmanagedstring_info( iObject *iobject, VipsBuf *buf )\n{\n\tManagedstring *managedstring = MANAGEDSTRING( iobject );\n\n\tvips_buf_appendf( buf, \"managedstring->string = \\\"%s\\\"\\n\", \n\t\tmanagedstring->string );\n\n\tIOBJECT_CLASS( parent_class )->info( iobject, buf );\n}\n\n/* Hash and equality for a managed string: we need the string and the heap to\n * match.\n */\nstatic unsigned int\nmanagedstring_hash( Managedstring *managedstring )\n{\n\treturn( g_str_hash( managedstring->string ) | \n\t\tGPOINTER_TO_UINT( ((Managed *) managedstring)->heap ) );\n}\n\nstatic gboolean\nmanagedstring_equal( Managedstring *a, Managedstring *b ) \n{\n\treturn( ((Managed *) a)->heap == ((Managed *) b)->heap &&\n\t\tg_str_equal( a->string, b->string ) );\n}\n\nstatic void\nmanagedstring_all_init( void )\n{\n\tif( !managedstring_all )\n\t\tmanagedstring_all = g_hash_table_new( \n\t\t\t(GHashFunc) managedstring_hash, \n\t\t\t(GEqualFunc) managedstring_equal );\n}\n\nstatic void\nmanagedstring_class_init( ManagedstringClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tiObjectClass *iobject_class = IOBJECT_CLASS( class );\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = managedstring_finalize;\n\n\tiobject_class->info = managedstring_info;\n\n\tmanagedstring_all_init();\n}\n\nstatic void\nmanagedstring_init( Managedstring *managedstring )\n{\n#ifdef DEBUG\n\tprintf( \"managedstring_init: %p\\n\", managedstring );\n#endif /*DEBUG*/\n\n#ifdef DEBUG\n\tmanaged_total += 1;\n#endif /*DEBUG*/\n\n\tmanagedstring->string = NULL;\n\tmanagedstring->e.type = ELEMENT_NOVAL;\n\tmanagedstring->e.ele = NULL;\n}\n\nGType\nmanagedstring_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ManagedstringClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) managedstring_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Managedstring ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) managedstring_init,\n\t\t}; \n\t\ttype = g_type_register_static( TYPE_MANAGED, \n\t\t\t\"Managedstring\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic Managedstring *\nmanagedstring_new( Heap *heap, const char *string )\n{\n\tManagedstring *managedstring;\n\n#ifdef DEBUG\n\tprintf( \"managedstring_new: %p, %s\\n\", heap, string );\n#endif /*DEBUG*/\n\n\t/* Disallow \"\" as string, we want to represent that as [].\n\t */\n\tg_assert( strcmp( string, \"\" ) != 0 );\n\n\tmanagedstring = g_object_new( TYPE_MANAGEDSTRING, NULL );\n\tmanaged_link_heap( MANAGED( managedstring ), heap );\n\theap_register_element( heap, &managedstring->e );\n\tif( !(managedstring->string = im_strdup( NULL, string )) ) \n\t\treturn( NULL );\n\n\tg_assert( !g_hash_table_lookup( managedstring_all, managedstring ) );\n\tg_hash_table_insert( managedstring_all, managedstring, managedstring );\n\n\tMANAGED( managedstring )->hash = managedstring_hash( managedstring ); \n\n\treturn( managedstring );\n}\n\nManagedstring *\nmanagedstring_lookup( Heap *heap, const char *string )\n{\n\tManagedstring managedstring;\n\n\t((Managed *) &managedstring)->heap = heap;\n\tmanagedstring.string = string;\n\tmanagedstring_all_init();\n\n\treturn( g_hash_table_lookup( managedstring_all, &managedstring ) );\n}\n\nManagedstring *\nmanagedstring_find( Heap *heap, const char *string )\n{\n\tManagedstring *managedstring;\n\n\tif( !(managedstring = managedstring_lookup( heap, string )) )\n\t\tif( !(managedstring = managedstring_new( heap, string )) )\n\t\t\treturn( NULL );\n\n\treturn( managedstring );\n}\n\ngboolean\nmanagedstring_get( Managedstring *managedstring, PElement *out )\n{\n\tPElement pe;\n\n\tPEPOINTE( &pe, &managedstring->e );\n\tif( PEISNOVAL( &pe ) ) {\n\t\tif( !heap_string_new( MANAGED( managedstring )->heap, \n\t\t\tmanagedstring->string, &pe ) ) \n\t\t\treturn( FALSE );\n\n#ifdef DEBUG\n\t\tmanaged_expanded += 1;\n\t\tprintf( \"expanding %s to the heap\\n\", managedstring->string );\n\t\tprintf( \"\\t(%d of %d now expanded)\\n\", \n\t\t\tmanaged_expanded, managed_total );\n#endif /*DEBUG*/\n\t}\n\n\tPEPUTE( out, &managedstring->e );\n\n\treturn( TRUE );\n}\n"
  },
  {
    "path": "src/managedstring.h",
    "content": "/* a managed STRING* ... for lazy string read\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These strings are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_MANAGEDSTRING (managedstring_get_type())\n#define MANAGEDSTRING( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MANAGEDSTRING, Managedstring ))\n#define MANAGEDSTRING_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_MANAGEDSTRING, ManagedstringClass))\n#define IS_MANAGEDSTRING( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MANAGEDSTRING ))\n#define IS_MANAGEDSTRING_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MANAGEDSTRING ))\n#define MANAGEDSTRING_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), \\\n\t\tTYPE_MANAGEDSTRING, ManagedstringClass ))\n\nstruct _Managedstring {\n\tManaged parent_object;\n\n\tconst char *string;\n\tElement e;\t\t/* Points to compiled string */\n};\n\ntypedef struct _ManagedstringClass {\n\tManagedClass parent_class;\n\n} ManagedstringClass;\n\nGType managedstring_get_type( void );\n\nManagedstring *managedstring_find( Heap *heap, const char *string );\ngboolean managedstring_get( Managedstring *managedstring, PElement *out );\n"
  },
  {
    "path": "src/matrix.c",
    "content": "/* an input matrix \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic void\nmatrix_finalize( GObject *gobject )\n{\n\tMatrix *matrix;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_MATRIX( gobject ) );\n\n\tmatrix = MATRIX( gobject );\n\n#ifdef DEBUG\n\tprintf( \"matrix_finalize\\n\" );\n#endif /*DEBUG*/\n\n\t/* My instance finalize stuff.\n\t */\n\tIM_FREE( matrix->value.coeff );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\n/* Rearrange our model for a new width/height.\n */\ngboolean\nmatrix_value_resize( MatrixValue *value, int width, int height )\n{\n\tdouble *coeff;\n\tint x, y, i;\n\n\tif( width == value->width && height == value->height )\n\t\treturn( TRUE );\n\n\tif( !(coeff = IARRAY( NULL, width * height, double )) )\n\t\treturn( FALSE );\n\n\t/* Set what we can with values from the old matrix.\n\t */\n\tfor( i = 0, y = 0; y < height; y++ )\n\t\tfor( x = 0; x < width; x++, i++ ) \n\t\t\tif( y < value->height && x < value->width ) \n\t\t\t\tcoeff[i] = value->coeff[x + \n\t\t\t\t\ty * value->width];\n\t\t\telse \n\t\t\t\tcoeff[i] = 0.0;\n\n\t/* Install new values.\n\t */\n\tIM_FREE( value->coeff );\n\tvalue->coeff = coeff;\n\tvalue->width = width;\n\tvalue->height = height;\n\n\treturn( TRUE );\n}\n\n/* Widgets for matrix edit.\n */\ntypedef struct _MatrixEdit {\n\tiDialog *idlg;\n\n\tMatrix *matrix;\n\n\tGtkWidget *width;\n\tGtkWidget *height;\n\tGtkWidget *display;\n} MatrixEdit;\n\n/* Done button hit.\n */\n/*ARGSUSED*/\nstatic void\nmatrix_done_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tMatrixEdit *eds = (MatrixEdit *) client;\n\n\tint width, height;\n\n\t/* Parse values. We have to scan before we resize in case we are\n\t * sizing smaller and we have unscanned changes at the edges.\n\t */\n\tview_scan_all();\n\teds->matrix->display = (MatrixDisplayType)\n\t\tgtk_combo_box_get_active( GTK_COMBO_BOX( eds->display ) );\n\tif( !get_geditable_pint( eds->width, &width ) ||\n\t\t!get_geditable_pint( eds->height, &height ) ||\n\t\t!matrix_value_resize( &eds->matrix->value, width, height ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\t/* Rebuild object.\n\t */\n\tclassmodel_update( CLASSMODEL( eds->matrix ) );\n\tsymbol_recalculate_all();\n\n\tnfn( sys, IWINDOW_YES );\n}\n\n/* Build the insides of matrix edit.\n */\nstatic void\nmatrix_buildedit( iDialog *idlg, GtkWidget *work, MatrixEdit *eds )\n{\n\tMatrix *matrix = eds->matrix;\n\n\tGtkSizeGroup *group;\n\n        /* Index with MatrixType.\n         */\n        static const char *display_names[] = {\n                N_( \"Text\" ),\n                N_( \"Sliders\" ),\n                N_( \"Toggle buttons\" ),\n                N_( \"Text, plus scale and offset\" )\n        };\n\n\tgroup = gtk_size_group_new( GTK_SIZE_GROUP_HORIZONTAL );\n\n        eds->width = build_glabeltext4( work, group, \"Width\" );\n\tidialog_init_entry( idlg, eds->width, \n\t\t\"Width of matrix\", \"%d\", matrix->value.width );\n        eds->height = build_glabeltext4( work, group, \"Height\" );\n\tidialog_init_entry( idlg, eds->height, \n\t\t\"Height of matrix\", \"%d\", matrix->value.height );\n        eds->display = build_goption( work, group, _( \"Display as\" ),\n                display_names, IM_NUMBER( display_names ), NULL, NULL );\n\tgtk_combo_box_set_active( GTK_COMBO_BOX( eds->display ), \n\t\tmatrix->display );\n\n\tUNREF( group );\n\n        gtk_widget_show_all( work );\n}\n\nstatic View *\nmatrix_view_new( Model *model, View *parent )\n{\n\treturn( matrixview_new() );\n}\n\n/* Pop up a matrix edit box.\n */\nstatic void \nmatrix_edit( GtkWidget *parent, Model *model )\n{\n\tMatrix *matrix = MATRIX( model );\n\tMatrixEdit *eds = INEW( NULL, MatrixEdit );\n\tGtkWidget *idlg;\n\n\teds->matrix = matrix;\n\n\tidlg = idialog_new();\n\tiwindow_set_title( IWINDOW( idlg ), _( \"Edit %s %s\" ),\n\t\tIOBJECT_GET_CLASS_NAME( model ),\n\t\tIOBJECT( HEAPMODEL( model )->row )->name );\n\tidialog_set_build( IDIALOG( idlg ), \n\t\t(iWindowBuildFn) matrix_buildedit, eds, NULL, NULL );\n\tidialog_set_callbacks( IDIALOG( idlg ), \n\t\tiwindow_true_cb, NULL, idialog_free_client, eds );\n\tidialog_add_ok( IDIALOG( idlg ), \n\t\tmatrix_done_cb, _( \"Set %s\" ), \n\t\tIOBJECT_GET_CLASS_NAME( model ) );\n\tiwindow_set_parent( IWINDOW( idlg ), parent );\n\tidialog_set_iobject( IDIALOG( idlg ), IOBJECT( model ) );\n\tiwindow_build( IWINDOW( idlg ) );\n\n\tgtk_widget_show( GTK_WIDGET( idlg ) );\n}\n\nstatic gboolean\nmatrix_graphic_save( Classmodel *classmodel, \n\tGtkWidget *parent, const char *filename )\n{\n\tMatrix *matrix = MATRIX( classmodel );\n\tDOUBLEMASK *dmask;\n\tchar buf[FILENAME_MAX];\n\n\tif( !(dmask = matrix_model_to_dmask( matrix )) ) \n\t\treturn( FALSE );\n\n\t/* We don't want $VAR etc. in the filename we pass down to the file\n\t * ops.\n\t */\n\tim_strncpy( buf, filename, FILENAME_MAX );\n\tpath_expand( buf );\n\n\tif( im_write_dmask_name( dmask, buf ) ) {\n\t\terror_vips_all();\n\t\tIM_FREEF( im_free_dmask, dmask );\n\t\treturn( FALSE );\n\t}\n\tIM_FREEF( im_free_dmask, dmask );\n\n\tmainw_recent_add( &mainw_recent_matrix, filename );\n\n\treturn( TRUE );\n}\n\nstatic gboolean\nmatrix_graphic_replace( Classmodel *classmodel, \n\tGtkWidget *parent, const char *filename )\n{\n\tMatrix *matrix = MATRIX( classmodel );\n\tRow *row = HEAPMODEL( matrix )->row;\n\tiText *itext = ITEXT( HEAPMODEL( matrix )->rhs->itext );\n\tDOUBLEMASK *dmask;\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t/* We don't want $VAR etc. in the filename we pass down to the file\n\t * ops.\n\t */\n\tim_strncpy( txt, filename, FILENAME_MAX );\n\tpath_expand( txt );\n\n\tif( !(dmask = im_read_dmask( txt )) ) {\n\t\terror_vips_all();\n\t\treturn( FALSE );\n\t}\n\n\tmatrix_dmask_to_ip( dmask, &buf );\n\tim_free_dmask( dmask );\n\n\tif( itext_set_formula( itext, vips_buf_all( &buf ) ) ) {\n\t\titext_set_edited( itext, TRUE );\n\t\t(void) expr_dirty( row->expr, link_serial_new() );\n\t}\n\n\tmainw_recent_add( &mainw_recent_matrix, filename );\n\n\treturn( TRUE );\n}\n\n/* Members of matrix we automate.\n */\nstatic ClassmodelMember matrix_members[] = {\n\t{ CLASSMODEL_MEMBER_MATRIX, NULL, 0, \n\t\tMEMBER_VALUE, NULL, N_( \"Value\" ),\n\t\tG_STRUCT_OFFSET( Matrix, value ) },\n\t{ CLASSMODEL_MEMBER_DOUBLE, NULL, 0,\n\t\tMEMBER_SCALE, \"scale\", N_( \"Scale\" ),\n\t\tG_STRUCT_OFFSET( Matrix, scale ) },\n\t{ CLASSMODEL_MEMBER_DOUBLE, NULL, 0,\n\t\tMEMBER_OFFSET, \"offset\", N_( \"Offset\" ),\n\t\tG_STRUCT_OFFSET( Matrix, offset ) },\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_FILENAME, \"filename\", N_( \"Filename\" ),\n\t\tG_STRUCT_OFFSET( Classmodel, filename ) },\n\t{ CLASSMODEL_MEMBER_ENUM, NULL, MATRIX_DISPLAY_LAST - 1,\n\t\tMEMBER_DISPLAY, \"display\", N_( \"Display\" ),\n\t\tG_STRUCT_OFFSET( Matrix, display ) }\n};\n\nstatic void\nmatrix_class_init( MatrixClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->finalize = matrix_finalize;\n\n\tiobject_class->user_name = _( \"Matrix\" );\n\n\tmodel_class->view_new = matrix_view_new;\n\tmodel_class->edit = matrix_edit;\n\n\tclassmodel_class->graphic_save = matrix_graphic_save;\n\tclassmodel_class->graphic_replace = matrix_graphic_replace;\n\n\tclassmodel_class->filetype = filesel_type_matrix;\n\tclassmodel_class->filetype_pref = \"MATRIX_FILE_TYPE\";\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n\n\tclassmodel_class->members = matrix_members;\n\tclassmodel_class->n_members = IM_NUMBER( matrix_members );\n}\n\nstatic void\nmatrix_init( Matrix *matrix )\n{\n#ifdef DEBUG\n\tprintf( \"matrix_init\\n\" );\n#endif /*DEBUG*/\n\n\tmatrix->value.coeff = NULL;\n        matrix->value.width = 0;\n\tmatrix->value.height = 0;\n\tmatrix->display = MATRIX_DISPLAY_TEXT;\n\tmatrix->scale = 1.0;\n\tmatrix->offset = 0.0;\n\tmatrix->selected = FALSE;\n\n\tiobject_set( IOBJECT( matrix ), CLASS_MATRIX, NULL );\n}\n\nGtkType\nmatrix_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( MatrixClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) matrix_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Matrix ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) matrix_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"Matrix\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nvoid\nmatrix_select( Matrix *matrix, int left, int top, int width, int height )\n{\n\tif( !matrix->selected ||\n\t\tmatrix->range.left != left ||\n\t\tmatrix->range.top != top ||\n\t\tmatrix->range.width != width ||\n\t\tmatrix->range.height != height ) {\n\t\tRow *row = HEAPMODEL( matrix )->row;\n\n#ifdef DEBUG\n\t\tprintf( \"matrix_select: \"\n\t\t\t\"left=%d, top = %d, width = %d, height = %d\\n\",\n\t\t\tleft, top, width, height );\n#endif /*DEBUG*/\n\n\t\tmatrix->selected = TRUE;\n\t\tmatrix->range.left = left;\n\t\tmatrix->range.top = top;\n\t\tmatrix->range.width = width;\n\t\tmatrix->range.height = height;\n\t\tiobject_changed( IOBJECT( matrix ) );\n\n\t\t/* Also make sure this row is selected.\n\t\t */\n\t\trow_select_ensure( row );\n\n\t\t/* The range of cells selected has changed, so the workspace\n\t\t * must update the status line too. row_select_ensure() only\n\t\t * spots row on/off selects. Yuk!\n\t\t */\n\t\tiobject_changed( IOBJECT( row->ws ) );\n\t}\n}\n\nvoid \nmatrix_deselect( Matrix *matrix )\n{\n\tif( matrix->selected ) {\n\t\tRow *row = HEAPMODEL( matrix )->row;\n\n#ifdef DEBUG\n\t\tprintf( \"matrix_deselect\\n\" );\n#endif /*DEBUG*/\n\n\t\tmatrix->selected = FALSE;\n\t\tiobject_changed( IOBJECT( matrix ) );\n\n\t\t/* Also make sure this row is not selected.\n\t\t */\n\t\trow_deselect( row );\n\t}\n}\n\n/* Guess a display type from a filename.\n */\nstatic int\nmatrix_guess_display( const char *fname )\n{\n\t/* Choose display type based on filename suffix ... rec \n\t * displays as 1, mor displays as 2, .con displays as 3, all others \n\t * display as 0. Keep in sync with MatrixDisplayType.\n\t */\n\tstatic const FileselFileType *types[] = {\n\t\t&filesel_xfile_type,\t// matrix\n\t\t&filesel_rfile_type,\t// recombination\n\t\t&filesel_mfile_type,\t// morphology\n\t\t&filesel_cfile_type\t// convolution\n\t};\n\n\tint i;\n\n\tif( !fname )\n\t\treturn( 0 );\n\n\tfor( i = 0; i < IM_NUMBER( types ); i++ )\n\t\tif( is_file_type( types[i], fname ) )\n\t\t\treturn( i );\n\n\treturn( 0 );\n}\n\n/* Make an ip definition out of a DOUBLEMASK.\n */\nvoid\nmatrix_dmask_to_ip( DOUBLEMASK *dmask, VipsBuf *buf )\n{\n\tint x, y;\n\n\t/* Build matrix expression.\n\t */\n\tvips_buf_appends( buf, CLASS_MATRIX \" \" );\n\n\tvips_buf_appends( buf, \"[\" );\n\tfor( y = 0; y < dmask->ysize; y++ ) {\n\t\tvips_buf_appends( buf, \"[\" );\n\t\tfor( x = 0; x < dmask->xsize; x++ ) {\n\t\t\tvips_buf_appendf( buf, \"%g\", \n\t\t\t\tdmask->coeff[x + y*dmask->xsize] );\n\t\t\tif( x != dmask->xsize - 1 )\n\t\t\t\tvips_buf_appends( buf, \",\" );\n\t\t}\n\t\tvips_buf_appends( buf, \"]\" );\n\t\tif( y != dmask->ysize - 1 )\n\t\t\tvips_buf_appends( buf, \",\" );\n\t}\n\tvips_buf_appends( buf, \"]\" );\n\n\tvips_buf_appendf( buf, \"(%g) (%g) \\\"%s\\\" %d\", \n\t\tdmask->scale, dmask->offset, dmask->filename,\n\t\tmatrix_guess_display( dmask->filename ) );\n}\n\n/* Make a heap object out of a DOUBLEMASK.\n */\ngboolean\nmatrix_dmask_to_heap( Heap *heap, DOUBLEMASK *dmask, PElement *out )\n{\n\tSymbol *sym = compile_lookup( symbol_root->expr->compile, \n\t\tCLASS_MATRIX );\n\n\tPElement rhs;\n\n\tif( !sym || !sym->expr || !sym->expr->compile ||\n\t\t!heap_copy( heap, sym->expr->compile, out ) )\n\t\treturn( FALSE );\n\n\tif( !heap_appl_add( heap, out, &rhs ) || \n\t\t!heap_matrix_new( heap, \n\t\t\tdmask->xsize, dmask->ysize, dmask->coeff, &rhs ) ||\n\t\t!heap_appl_add( heap, out, &rhs ) ||\n\t\t!heap_real_new( heap, dmask->scale, &rhs ) ||\n\t\t!heap_appl_add( heap, out, &rhs ) ||\n\t\t!heap_real_new( heap, dmask->offset, &rhs ) ||\n\t\t!heap_appl_add( heap, out, &rhs ) ||\n\t\t!heap_managedstring_new( heap, dmask->filename, &rhs ) ||\n\t\t!heap_appl_add( heap, out, &rhs ) ||\n\t\t!heap_real_new( heap, \n\t\t\tmatrix_guess_display( dmask->filename ), &rhs ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Cast an IMASK to a DMASK.\n */\nDOUBLEMASK *\nmatrix_imask_to_dmask( INTMASK *imask )\n{\n\tDOUBLEMASK *dmask;\n\tint i;\n\n\tif( !(dmask = im_create_dmask( imask->filename, \n\t\timask->xsize, imask->ysize )) ) {\n\t\terror_vips_all();\n\t\treturn( NULL );\n\t}\n\n\tdmask->scale = imask->scale;\n\tdmask->offset = imask->offset;\n\tfor( i = 0; i < imask->xsize * imask->ysize; i++ )\n\t\tdmask->coeff[i] = imask->coeff[i];\n\n\treturn( dmask );\n}\n\n/* Cast a DMASK to an IMASK.\n */\nINTMASK *\nmatrix_dmask_to_imask( DOUBLEMASK *dmask )\n{\n\tINTMASK *imask;\n\tint i;\n\n\tif( !(imask = im_create_imask( dmask->filename, \n\t\tdmask->xsize, dmask->ysize )) ) {\n\t\terror_vips_all();\n\t\treturn( NULL );\n\t}\n\n\timask->scale = dmask->scale;\n\timask->offset = dmask->offset;\n\tfor( i = 0; i < dmask->xsize * dmask->ysize; i++ )\n\t\timask->coeff[i] = dmask->coeff[i];\n\n\treturn( imask );\n}\n\n/* Make a heap object out of an INTMASK.\n */\ngboolean\nmatrix_imask_to_heap( Heap *heap, INTMASK *imask, PElement *out )\n{\n\tDOUBLEMASK *dmask;\n\n\tif( !(dmask = matrix_imask_to_dmask( imask )) )\n\t\treturn( FALSE );\n\tif( !matrix_dmask_to_heap( heap, dmask, out ) ) {\n\t\tim_free_dmask( dmask );\n\t\treturn( FALSE );\n\t}\n\tim_free_dmask( dmask );\n\n\treturn( TRUE );\n}\n\n/* Make a DOUBLEMASK out of an ip value.\n */\nDOUBLEMASK *\nmatrix_ip_to_dmask( PElement *root )\n{\n\tchar buf[MAX_STRSIZE];\n\tchar name[FILENAME_MAX];\n\tDOUBLEMASK *dmask;\n\tdouble scale, offset;\n\tchar *filename;\n\tint width, height;\n\n\tif( !class_get_member_matrix_size( root, \n\t\tMEMBER_VALUE, &width, &height ) )\n\t\treturn( NULL );\n\n\tif( class_get_member_string( root, MEMBER_FILENAME, buf, MAX_STRSIZE ) )\n\t\tfilename = buf;\n\telse {\n\t\tif( !temp_name( name, \"mat\" ) )\n\t\t\treturn( NULL );\n\n\t\tfilename = name;\n\t}\n\n\tif( !(dmask = im_create_dmask( filename, width, height )) ) {\n\t\terror_vips_all();\n\t\treturn( NULL );\n\t}\n\n\tif( !class_get_member_matrix( root, MEMBER_VALUE, \n\t\tdmask->coeff, width * height, &width, &height ) ) {\n\t\tIM_FREEF( im_free_dmask, dmask );\n\t\treturn( FALSE );\n\t}\n\n\tif( !class_get_member_real( root, MEMBER_SCALE, &scale ) )\n\t\tscale = 1.0;\n\tif( !class_get_member_real( root, MEMBER_OFFSET, &offset ) )\n\t\toffset = 0.0;\n\tdmask->scale = scale;\n\tdmask->offset = offset;\n\n\treturn( dmask );\n}\n\n/* Make an INTMASK out of an ip value.\n */\nINTMASK *\nmatrix_ip_to_imask( PElement *root )\n{\n\tDOUBLEMASK *dmask;\n\tINTMASK *imask;\n\n\tif( !(dmask = matrix_ip_to_dmask( root )) )\n\t\treturn( NULL );\n\n\tif( !(imask = matrix_dmask_to_imask( dmask )) ) {\n\t\tIM_FREEF( im_free_dmask, dmask );\n\t\treturn( NULL );\n\t}\n\n\treturn( imask );\n}\n\nDOUBLEMASK *\nmatrix_model_to_dmask( Matrix *matrix )\n{\n\tDOUBLEMASK *dmask;\n\tint i;\n\n\tif( !(dmask = im_create_dmask( CLASSMODEL( matrix )->filename, \n\t\tmatrix->value.width, matrix->value.height )) ) {\n\t\terror_vips_all();\n\t\treturn( NULL );\n\t}\n\n\tdmask->scale = matrix->scale;\n\tdmask->offset = matrix->offset;\n\tfor( i = 0; i < matrix->value.width * matrix->value.height; i++ )\n\t\tdmask->coeff[i] = matrix->value.coeff[i];\n\n\treturn( dmask );\n}\n\ngboolean\nmatrix_dmask_to_model( Matrix *matrix, DOUBLEMASK *dmask )\n{\n\tint i;\n\n\tif( !matrix_value_resize( &matrix->value, \n\t\tdmask->xsize, dmask->ysize ) ) \n\t\treturn( FALSE );\n\n\tmatrix->scale = dmask->scale;\n\tmatrix->offset = dmask->offset;\n\tfor( i = 0; i < matrix->value.width * matrix->value.height; i++ )\n\t\tmatrix->value.coeff[i] = dmask->coeff[i];\n\tmatrix->display = \n\t\t(MatrixDisplayType) matrix_guess_display( dmask->filename );\n\tIM_SETSTR( CLASSMODEL( matrix )->filename, dmask->filename );\n\n\treturn( TRUE );\n}\n\n"
  },
  {
    "path": "src/matrix.h",
    "content": "/* a matrix in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_MATRIX (matrix_get_type())\n#define MATRIX( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MATRIX, Matrix ))\n#define MATRIX_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_MATRIX, MatrixClass))\n#define IS_MATRIX( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MATRIX ))\n#define IS_MATRIX_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MATRIX ))\n#define MATRIX_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_MATRIX, MatrixClass ))\n\n/* What kind of ui bits have we asked for for this matrix?\n */\ntypedef enum {\n\tMATRIX_DISPLAY_TEXT = 0,\t/* Set of text widgets */\n\tMATRIX_DISPLAY_SLIDER,\t\t/* Set of sliders */\n\tMATRIX_DISPLAY_TOGGLE,\t\t/* Set of 3 value toggles */\n\tMATRIX_DISPLAY_TEXT_SCALE_OFFSET,/* Text, with scale/offset widgets */\n\tMATRIX_DISPLAY_LAST\n} MatrixDisplayType;\n\ntypedef struct _Matrix {\n\tClassmodel model;\n\n\t/* Base class fields.\n\t */\n\tMatrixValue value;\n\n\t/* Other class fields.\n\t */\n\tMatrixDisplayType display;\t/* Display as */\n\tdouble scale;\n\tdouble offset;\n\n\t/* Is there a current selection on the matrixview? And if there is,\n\t * the cells it covers.\n\t */\n\tgboolean selected;\n\tRect range;\n} Matrix;\n\ntypedef struct _MatrixClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} MatrixClass;\n\ngboolean matrix_value_resize( MatrixValue *value, int width, int height );\n\nGType matrix_get_type( void );\n\n/* Select rectangular areas of matricies.\n */\nvoid matrix_select( Matrix *matrix, int left, int top, int width, int height );\nvoid matrix_deselect( Matrix *matrix );\n\nvoid matrix_dmask_to_ip( DOUBLEMASK *dmask, VipsBuf *buf );\ngboolean matrix_dmask_to_heap( Heap *heap, DOUBLEMASK *dmask, PElement *out );\nDOUBLEMASK *matrix_imask_to_dmask( INTMASK *imask );\nINTMASK *matrix_dmask_to_imask( DOUBLEMASK *dmask );\ngboolean matrix_imask_to_heap( Heap *heap, INTMASK *imask, PElement *out );\nDOUBLEMASK *matrix_ip_to_dmask( PElement *root );\nINTMASK *matrix_ip_to_imask( PElement *root );\nDOUBLEMASK *matrix_model_to_dmask( Matrix *matrix );\ngboolean matrix_dmask_to_model( Matrix *matrix, DOUBLEMASK *dmask );\n"
  },
  {
    "path": "src/matrixview.c",
    "content": "/* run the display for an input matrixview in a workspace \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* Round N down to P boundary.\n */\n#define ROUND_DOWN(N,P) ((N) - ((N) % P))\n\n/* Round N up to P boundary.\n */\n#define ROUND_UP(N,P) (ROUND_DOWN( (N) + (P) - 1, (P) ))\n\n/* The size in cells at which we switch from displaying the whole matrix to\n * displaying part of it in a scrolled window.\n */\nstatic const int matrixview_max_width = 7;\nstatic const int matrixview_max_height = 10;\n\n/* Show a matrix with fixed-width columns.\n */\nstatic const int matrixview_column_width = 70;\n\n/* Limit number of sub-widgets with this ... could be prefs?\n */\nstatic const int matrixview_max_cells = 100;\n\nstatic GraphicviewClass *parent_class = NULL;\n\nstatic void\nmatrixview_destroy( GtkObject *object )\n{\n    \tMatrixview *matrixview;\n\n    \tg_return_if_fail( object != NULL );\n    \tg_return_if_fail( IS_MATRIXVIEW( object ) );\n\n#ifdef DEBUG\n    \tprintf( \"matrixview_destroy\\n\" );\n#endif /*DEBUG*/\n\n    \tmatrixview = MATRIXVIEW( object );\n\n    \t/* My instance destroy stuff.\n    \t */\n    \tIM_FREEF( g_slist_free, matrixview->items );\n\n    \tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic gboolean\nmatrixview_scan_text( Matrixview *matrixview, GtkWidget *txt, \n    \tdouble *out, gboolean *changed )\n{\n    \tdouble v;\n\n    \tif( !get_geditable_double( txt, &v ) ) \n    \t\treturn( FALSE );\n\n    \tif( *out != v ) {\n    \t\t*out = v;\n    \t\t*changed = TRUE;\n    \t}\n\n    \treturn( TRUE );\n}\n\n/* Search and read all text widgets and refill matrix. set_dirty this symbol\n * if there was a change. Return non-NULL if we found an error.\n */\nstatic void *\nmatrixview_scan( View *view )\n{\n    \tMatrixview *matrixview = MATRIXVIEW( view );\n    \tMatrix *matrix = MATRIX( VOBJECT( matrixview )->iobject );\n\tint width = matrix->value.width;\n\tint height = matrix->value.height;\n    \tExpr *expr = HEAPMODEL( matrix )->row->expr;\n\n    \tgboolean changed;\n    \tint x, y;\n    \tGSList *p;\n\n#ifdef DEBUG\n    \tprintf( \"matrixview_scan\\n\" );\n#endif /*DEBUG*/\n\n    \t/* Should be text widgets there ... either text or tslider.\n    \t */\n    \tif( matrixview->display != MATRIX_DISPLAY_TEXT && \n    \t\tmatrixview->display != MATRIX_DISPLAY_TEXT_SCALE_OFFSET && \n    \t\tmatrixview->display != MATRIX_DISPLAY_SLIDER )\n    \t\treturn( NULL );\n\n    \texpr_error_clear( expr );\n    \tchanged = FALSE;\n\n    \t/* Check for scale and offset, if present.\n    \t */\n    \tif( matrixview->scale && \n\t\t!matrixview_scan_text( matrixview,\n\t\t\tmatrixview->scale, &matrix->scale, &changed ) ) {\n\t\texpr_error_set( expr );\n    \t\treturn( view );\n\t}\n    \tif( matrixview->offset && \n\t\t!matrixview_scan_text( matrixview, \n\t\t\tmatrixview->offset, &matrix->offset, &changed ) ) {\n\t\texpr_error_set( expr );\n    \t\treturn( view );\n    \t}\n\n    \t/* Loop thru' all matrix widgets. tsliders have text fields we must\n\t * scan too.\n    \t */\n    \tif( matrixview->items ) \n    \t\tfor( p = matrixview->items, y = 0; y < height; y++ )\n    \t\t\tfor( x = 0; x < width; x++, p = p->next ) {\n    \t\t\t\tGtkWidget *item = GTK_WIDGET( p->data );\n    \t\t\t\tGtkWidget *entry = TSLIDER( item )->entry;\n\t\t\t\tint i = x + y * width;\n\n    \t\t\t\tif( !matrixview_scan_text( matrixview, entry,\n    \t\t\t\t\t&matrix->value.coeff[i], &changed ) ) {\n\t\t\t\t\terror_top( _( \"Bad value.\" ) );\n\t\t\t\t\terror_sub( _( \"Cell (%d, %d):\\n%s\" ), \n    \t\t\t\t\t\tx, y, error_get_sub() );\n\t\t\t\t\texpr_error_set( expr );\n\n    \t\t\t\t\treturn( view );\n    \t\t\t\t}\n    \t\t\t}\n\n\tif( matrixview->store ) {\n\t\tGtkTreeModel *tree = GTK_TREE_MODEL( matrixview->store );\n\n\t\tGtkTreeIter iter;\n\n\t\tgtk_tree_model_get_iter_first( tree, &iter );\n\n\t\tfor( y = 0; y < height; y++ ) {\n\t\t\tfor( x = 0; x < width; x++ ) {\n\t\t\t\tdouble *out = \n\t\t\t\t\t&matrix->value.coeff[x + y * width];\n\n\t\t\t\tdouble d;\n\n\t\t\t\tgtk_tree_model_get( tree, &iter, x, &d, -1 );\n\n\t\t\t\tif( *out != d ) {\n\t\t\t\t\t*out = d;\n\t\t\t\t\tchanged = TRUE;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tgtk_tree_model_iter_next( tree, &iter );\n\t\t}\n\t}\n\n    \tif( changed ) \n    \t\tclassmodel_update( CLASSMODEL( matrix ) ) ;\n\n    \treturn( VIEW_CLASS( parent_class )->scan( view ) );\n}\n\n/* Change to a toggle widget. \n */\n/*ARGSUSED*/\nstatic void\nmatrixview_toggle_change_cb( GtkWidget *widget, Matrixview *matrixview )\n{\n    \tMatrix *matrix = MATRIX( VOBJECT( matrixview )->iobject );\n    \tint pos = g_slist_index( matrixview->items, widget );\n\tint x = pos % matrixview->width;\n\tint y = pos / matrixview->width;\n\tint i = x + y * matrix->value.width;\n\n#ifdef DEBUG\n    \tprintf( \"matrixview_toggle_change_cb\\n\" );\n#endif /*DEBUG*/\n\n    \t/* Cycle value.\n    \t */\n    \tswitch( (int) matrix->value.coeff[i] ) {\n    \tcase 0:\n    \t\tmatrix->value.coeff[i] = 128.0;\n    \t\tbreak;\n\n    \tcase 255:\n    \t\tmatrix->value.coeff[i] = 0.0;\n    \t\tbreak;\n\n    \tdefault:\n    \t\tmatrix->value.coeff[i] = 255.0;\n    \t\tbreak;\n    \t}\n\n    \tclassmodel_update( CLASSMODEL( matrix ) );\n    \tsymbol_recalculate_all();\n}\n\n/* Build a set of toggle items for a matrix. \n */\nstatic void\nmatrixview_toggle_build( Matrixview *matrixview )\n{\n    \tMatrix *matrix = MATRIX( VOBJECT( matrixview )->iobject );\n\n    \tint x, y;\n    \tint cx, cy;\n\n    \tmatrixview->table = gtk_table_new( \n\t\tmatrixview->height, matrixview->width, TRUE );\n    \tgtk_box_pack_start( GTK_BOX( matrixview->box ), \n    \t\tmatrixview->table, FALSE, FALSE, 0 );\n\n    \t/* Find the centre position, if there is one. We give this a special\n    \t * name; it is highlit by our resource file.\n    \t */\n    \tcx = -1; cy = -1;\n    \tif( matrix->value.height & 0x1 )\n    \t\tcy = matrix->value.height >> 1;\n    \tif( matrix->value.width & 0x1 )\n    \t\tcx = matrix->value.width >> 1;\n\n    \t/* Build contents.\n    \t */\n    \tfor( y = 0; y < matrixview->height; y++ )\n    \t\tfor( x = 0; x < matrixview->width; x++ ) {\n    \t\t\tGtkWidget *but;\n\n    \t\t\tbut = gtk_button_new_with_label( \"0\" );\n    \t\t\tgtk_signal_connect( GTK_OBJECT( but ), \"clicked\", \n    \t\t\t\tGTK_SIGNAL_FUNC( matrixview_toggle_change_cb ),\n    \t\t\t\tmatrixview );\n    \t\t\tif( x == cx && y == cy )\n    \t\t\t\tgtk_widget_set_name( but, \"centre_widget\" );\n\t\t\t/*\n\n\t\t\t\tFIXME ... this b0rks thanks to pangolayout\n\t\t\t\tconfusion\n\n    \t\t\tset_fixed( GTK_BIN( but )->child, 1 );\n\t\t\t */\n\n    \t\t\tgtk_table_attach( GTK_TABLE( matrixview->table ), but,\n    \t\t\t\tx, x + 1, y, y + 1, GTK_FILL, GTK_FILL, 2, 2 );\n    \t\t\tmatrixview->items = \n    \t\t\t\tg_slist_append( matrixview->items, but );\n    \t\t}\n}\n\n/* Change to a scale in a Tslider. \n */\n/*ARGSUSED*/\nstatic void\nmatrixview_slider_change_cb( Tslider *tslider, Matrixview *matrixview )\n{\n    \tMatrix *matrix = MATRIX( VOBJECT( matrixview )->iobject );\n    \tint pos = g_slist_index( matrixview->items, tslider );\n\tint x = pos % matrixview->width;\n\tint y = pos / matrixview->width;\n\tint i = x + y * matrix->value.width;\n\n    \tg_assert( pos >= 0 );\n\n    \t/* Install value.\n    \t */\n    \tif( matrix->value.coeff[i] != tslider->svalue ) {\n    \t\tmatrix->value.coeff[i] = tslider->svalue;\n\n    \t\tclassmodel_update( CLASSMODEL( matrix ) );\n    \t\tsymbol_recalculate_all();\n    \t}\n}\n\n/* Build a set of slider items for a matrix. \n */\nstatic void\nmatrixview_slider_build( Matrixview *matrixview )\n{\n    \tint x, y;\n\n    \tmatrixview->table = gtk_table_new( matrixview->height, \n\t\tmatrixview->width, TRUE );\n    \tgtk_box_pack_start( GTK_BOX( matrixview->box ), \n    \t\tmatrixview->table, TRUE, TRUE, 0 );\n\n    \tfor( y = 0; y < matrixview->height; y++ )\n    \t\tfor( x = 0; x < matrixview->width; x++ ) {\n    \t\t\tTslider *tslider = tslider_new();\n\n    \t\t\ttslider_set_conversions( tslider, NULL, NULL );\n    \t\t\ttslider->from = -2;\n    \t\t\ttslider->to = 2;\n    \t\t\ttslider->digits = 3;\n\n    \t\t\tgtk_signal_connect_object( GTK_OBJECT( tslider ), \n    \t\t\t\t\"text_changed\",\n    \t\t\t\tGTK_SIGNAL_FUNC( view_changed_cb ), \n    \t\t\t\tGTK_OBJECT( matrixview ) );\n    \t\t\tgtk_signal_connect_object( GTK_OBJECT( tslider ), \n    \t\t\t\t\"activate\", \n    \t\t\t\tGTK_SIGNAL_FUNC( view_activate_cb ), \n    \t\t\t\tGTK_OBJECT( matrixview ) );\n    \t\t\tgtk_signal_connect( GTK_OBJECT( tslider ), \n    \t\t\t\t\"slider_changed\", \n    \t\t\t\tGTK_SIGNAL_FUNC( matrixview_slider_change_cb ),\n    \t\t\t\tmatrixview );\n\n    \t\t\tgtk_container_set_border_width( \n    \t\t\t\tGTK_CONTAINER( tslider ), 2 );\n    \t\t\tgtk_table_attach_defaults( \n    \t\t\t\tGTK_TABLE( matrixview->table ), \n    \t\t\t\tGTK_WIDGET( tslider ),\n    \t\t\t\tx, x + 1, y, y + 1 );\n    \t\t\tmatrixview->items = g_slist_append( matrixview->items, \n    \t\t\t\ttslider );\n    \t\t}\n}\n\nstatic gboolean\nmatrixview_text_focus_in( GtkWidget *entry, GdkEvent *event, void *data )\n{\n    \tgtk_editable_select_region( GTK_EDITABLE( entry ), 0, -1 );\n\n\treturn( FALSE );\n}\n\nstatic gboolean\nmatrixview_text_focus_out( GtkWidget *entry, GdkEvent *event, void *data )\n{\n    \tgtk_editable_select_region( GTK_EDITABLE( entry ), 0, 0 );\n\n\treturn( FALSE );\n}\n\nstatic void\nmatrixview_text_connect( Matrixview *matrixview, GtkWidget *txt )\n{\n    \tgtk_signal_connect_object( GTK_OBJECT( txt ), \"changed\",\n    \t\tGTK_SIGNAL_FUNC( view_changed_cb ), \n    \t\tGTK_OBJECT( matrixview ) );\n    \tgtk_signal_connect_object( GTK_OBJECT( txt ), \"activate\",\n    \t\tGTK_SIGNAL_FUNC( view_activate_cb ), \n    \t\tGTK_OBJECT( matrixview ) );\n\n    \t/* Select text on focus-in, deselect on focus out.\n    \t */\n    \tgtk_signal_connect( GTK_OBJECT( txt ), \"focus_in_event\",\n    \t\tGTK_SIGNAL_FUNC( matrixview_text_focus_in ), NULL );\n    \tgtk_signal_connect( GTK_OBJECT( txt ), \"focus_out_event\",\n    \t\tGTK_SIGNAL_FUNC( matrixview_text_focus_out ), NULL );\n}\n\nstatic void\nmatrixview_text_build_scale_offset( Matrixview *matrixview )\n{\n\tGtkSizeGroup *group;\n\n    \tmatrixview->cbox = gtk_vbox_new( FALSE, 2 );\n        gtk_box_pack_end( GTK_BOX( matrixview->box ), \n    \t\tGTK_WIDGET( matrixview->cbox ), FALSE, FALSE, 0 );\n\n\tgroup = gtk_size_group_new( GTK_SIZE_GROUP_HORIZONTAL );\n\n\tmatrixview->scale = \n\t\tbuild_glabeltext4( matrixview->cbox, group, _( \"Scale\" ) );\n\tgtk_entry_set_width_chars( GTK_ENTRY( matrixview->scale ), 6 );\n    \tmatrixview_text_connect( matrixview, matrixview->scale );\n\n\tmatrixview->offset = \n\t\tbuild_glabeltext4( matrixview->cbox, group, _( \"Offset\" ) );\n\tgtk_entry_set_width_chars( GTK_ENTRY( matrixview->offset ), 6 );\n    \tmatrixview_text_connect( matrixview, matrixview->offset );\n\n\tUNREF( group );\n}\n\n/* Make a GtkListStore from a MatrixValue.\n */\nGtkListStore *\nmatrixview_liststore_new( MatrixValue *matrixvalue )\n{\n\tint width = matrixvalue->width;\n\tint height = matrixvalue->height;\n\n\tGType *types;\n\tint i, y;\n\tGtkListStore *store;\n\n\ttypes = g_new( GType, width );\n\tfor( i = 0; i < width; i++ )\n\t\ttypes[i] = G_TYPE_DOUBLE;\n\tstore = gtk_list_store_newv( width, types );\n\tg_free( types );\n\n\tfor( y = 0; y < height; y++ ) {\n\t\tGtkTreeIter iter;\n\n\t\tgtk_list_store_append( store, &iter );\n\n\t\tfor( i = 0; i < width; i++ ) \n\t\t\tgtk_list_store_set( store, &iter, \n\t\t\t\ti, matrixvalue->coeff[y * width + i], -1 );\n\t}\n\n\treturn( store );\n}\n\nstatic void\nmatrixview_edited_cb( GtkCellRendererText *renderer, \n\tchar *path, char *new_text, void *user_data )\n{\n\tMatrixview *matrixview = MATRIXVIEW( user_data );\n\tGtkTreeModel *tree = GTK_TREE_MODEL( matrixview->store );\n\tGtkTreeIter iter;\n\n\tif( gtk_tree_model_get_iter_from_string( tree, &iter, path ) ) {\n\t\tint col = GPOINTER_TO_INT( g_object_get_data( \n\t\t\tG_OBJECT( renderer ), \"nip2_column_num\" ) );\n\n\t\tgtk_list_store_set( GTK_LIST_STORE( tree ), &iter, \n\t\t\tcol, atof( new_text ),\n\t\t\t-1 ); \n\n\t\tview_scannable_register( VIEW( matrixview ) );\n\t\tsymbol_recalculate_all();\n\t}\n}\n\nstatic void\nmatrixview_cell_data_cb( GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,\n\tGtkTreeModel *tree, GtkTreeIter *iter, void *data )\n{\n\tint col = GPOINTER_TO_INT( g_object_get_data( \n\t\tG_OBJECT( cell ), \"nip2_column_num\" ) );\n\tdouble d;\n\tchar buf[256];\n\n\tgtk_tree_model_get( tree, iter, col, &d, -1 );\n\tvips_snprintf( buf, 256, \"%g\", d ); \n\tg_object_set( cell, \"text\", buf, NULL );\n}\n\n/* Build a set of text items for a matrix. \n */\nstatic void\nmatrixview_text_build( Matrixview *matrixview )\n{\n    \tMatrix *matrix = MATRIX( VOBJECT( matrixview )->iobject );\n\n\tint i;\n\tGtkTreeViewColumn *column;\n    \tint cell_height;\n\tGtkTreeSelection *selection;\n\n\tif( !matrix->value.coeff )\n\t\treturn;\n\n\tmatrixview->store = matrixview_liststore_new( &matrix->value );\n\tmatrixview->sheet = gtk_tree_view_new_with_model( \n\t\tGTK_TREE_MODEL( matrixview->store ) );\n\tgtk_tree_view_set_headers_visible( GTK_TREE_VIEW( matrixview->sheet ),\n\t\tFALSE );\n\n\t/* Stops a harmless compiler warning.\n\t */\n\tcolumn = NULL;\n\n\tfor( i = 0; i < matrix->value.width; i++ ) {\n\t\tGtkCellRenderer *renderer;\n\t\tchar buf[256];\n\n\t\trenderer = gtk_cell_renderer_text_new();\n\t\tg_object_set( renderer, \"editable\", TRUE, NULL );\n\t\tg_object_set_data( G_OBJECT( renderer ), \n\t\t\t\"nip2_column_num\", GINT_TO_POINTER( i ) );\n\t\tg_signal_connect( G_OBJECT( renderer ), \"edited\",\n\t\t\tG_CALLBACK( matrixview_edited_cb ), matrixview );\n\n\t\tcolumn = gtk_tree_view_column_new();\n\t\tgtk_tree_view_column_set_sizing( column, \n\t\t\tGTK_TREE_VIEW_COLUMN_FIXED );\n\t\tgtk_tree_view_column_set_fixed_width( column, \n\t\t\tmatrixview_column_width );\n\t\tim_snprintf( buf, 256, \"%d\", i );\n\t\tgtk_tree_view_column_set_title( column, buf );\n\t\tgtk_tree_view_column_pack_start( column, renderer, FALSE );\n\t\tgtk_tree_view_column_set_attributes( column, renderer, \n\t\t\t\"text\", i, \n\t\t\tNULL );\n\t\tgtk_tree_view_column_set_cell_data_func( column, renderer, \n\t\t\tmatrixview_cell_data_cb, NULL, NULL ); \n\t\tgtk_tree_view_append_column( GTK_TREE_VIEW( matrixview->sheet ),\n\t\t\tcolumn );\n\t}\n\n\tgtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW( matrixview->sheet ),\n\t\tTRUE );\n\tgtk_tree_view_column_cell_get_size( column,\n\t\tNULL, NULL, NULL, NULL, &cell_height );\n\n\tselection = gtk_tree_view_get_selection( \n\t\tGTK_TREE_VIEW( matrixview->sheet ) );\n\tgtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );\n\tgtk_tree_view_set_rubber_banding( GTK_TREE_VIEW( matrixview->sheet ), \n\t\tTRUE );\n\n\tgtk_tree_view_set_grid_lines( GTK_TREE_VIEW( matrixview->sheet ), \n\t\tGTK_TREE_VIEW_GRID_LINES_BOTH );\n\n\tif( matrix->value.width > matrixview_max_width || \n\t\tmatrix->value.height > matrixview_max_height ) {\n\t\tGtkRequisition requisition;\n\t\tgint spacing;\n\t\tint border;\n\t\tint width, height;\n\n\t\tif( matrix->value.width > matrixview_max_width )\n\t\t\tgtk_tree_view_set_headers_visible( \n\t\t\t\tGTK_TREE_VIEW( matrixview->sheet ),\n\t\t\t\tTRUE );\n\n\t\tmatrixview->swin = gtk_scrolled_window_new( NULL, NULL );\n\t\tgtk_scrolled_window_set_policy( \n\t\t\tGTK_SCROLLED_WINDOW( matrixview->swin ),\n\t\t\tGTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );\n\t\tgtk_container_add( GTK_CONTAINER( matrixview->swin ), \n\t\t\tmatrixview->sheet );\n\n\t\t/* Calculate how big we should make the scrolled window. We\n\t\t * need to leave space for the scrollbars.\n\t\t */\n\t\tgtk_widget_size_request( \n\t\t\tgtk_scrolled_window_get_hscrollbar( \n\t\t\t\tGTK_SCROLLED_WINDOW( matrixview->swin ) ),\n\t\t\t&requisition );\n\t\tgtk_widget_style_get( GTK_WIDGET( matrixview->swin ),\n\t\t\t\"scrollbar-spacing\", &spacing,\n\t\t\tNULL );\n\t\tborder = requisition.height + spacing;\n\n\t\t/* Subarea of matrix we show, in cells.\n\t\t */\n\t\twidth = IM_MIN( matrix->value.width, matrixview_max_width );\n\t\theight = IM_MIN( matrix->value.height, matrixview_max_height );\n\n\t\t/* Convert to pixels.\n\t\t */\n\t\twidth *= matrixview_column_width;\n\t\theight *= cell_height;\n\n\t\t/* Will we be showing scrollbars? Need to add a bit.\n\t\t */\n\t\tif( matrixview->width > matrixview_max_width )\n\t\t\theight += border;\n\t\tif( matrixview->height > matrixview_max_height )\n\t\t\twidth += border;\n\n\t\tgtk_widget_set_size_request( GTK_WIDGET( matrixview->swin ), \n\t\t\twidth + 5, height + 5 );\n\n\t\tgtk_box_pack_start( GTK_BOX( matrixview->box ), \n\t\t\tmatrixview->swin, FALSE, FALSE, 0 );\n\t}\n\telse {\n\t\tgtk_box_pack_start( GTK_BOX( matrixview->box ), \n\t\t\tmatrixview->sheet, FALSE, FALSE, 0 );\n\t}\n\n    \tif( matrixview->display == MATRIX_DISPLAY_TEXT_SCALE_OFFSET )\n    \t\t/* Make the scale/offset widgets too.\n    \t\t */\n    \t\tmatrixview_text_build_scale_offset( matrixview );\n}\n\n/* Set the label on a toggle button to reflect its value.\n */\nstatic void\nmatrixview_toggle_set_label( GtkWidget *button, double v )\n{\n    \tGtkWidget *label = GTK_BIN( button )->child;\n\n    \tg_return_if_fail( GTK_IS_LABEL( label ) );\n\n    \tswitch( (int) v ) {\n    \tcase 0:\n    \t\tset_glabel( label, \"0\" );\n    \t\tbreak;\n\n    \tcase 255:\n    \t\tset_glabel( label, \"1\" );\n    \t\tbreak;\n\n    \tdefault:\n    \t\tset_glabel( label, \"*\" );\n    \t\tbreak;\n    \t}\n}\n\n/* Refresh a set of toggle items for a matrix. \n */\nstatic void\nmatrixview_toggle_refresh( Matrixview *matrixview )\n{\n    \tMatrix *matrix = MATRIX( VOBJECT( matrixview )->iobject );\n\n    \tint x, y;\n    \tGSList *p;\n\n    \tfor( p = matrixview->items, y = 0; y < matrixview->height; y++ )\n    \t\tfor( x = 0; x < matrixview->width; x++, p = p->next ) {\n    \t\t\tGtkWidget *wid = GTK_WIDGET( p->data );\n    \t\t\tint i = x + y * matrix->value.width;\n\n    \t\t\tmatrixview_toggle_set_label( wid, \n\t\t\t\tmatrix->value.coeff[i] );\n    \t\t}\n}\n\n/* Refresh a set of slider items for a matrix. \n */\nstatic void\nmatrixview_slider_refresh( Matrixview *matrixview )\n{\n    \tMatrix *matrix = MATRIX( VOBJECT( matrixview )->iobject );\n\n    \tint x, y;\n    \tGSList *p;\n\n    \tfor( p = matrixview->items, y = 0; y < matrixview->height; y++ )\n    \t\tfor( x = 0; x < matrixview->width; x++, p = p->next ) {\n    \t\t\tTslider *tslider = TSLIDER( p->data );\n    \t\t\tint i = x + y * matrix->value.width;\n\n    \t\t\ttslider->value = matrix->value.coeff[i];\n    \t\t\ttslider->svalue = matrix->value.coeff[i];\n\n    \t\t\ttslider_changed( tslider );\n    \t\t}\n}\n\nstatic void\nmatrixview_text_set( Matrixview *matrixview, GtkWidget *txt, double val )\n{\n    \tif( txt ) {\n    \t\tgtk_signal_handler_block_by_data( \n    \t\t\tGTK_OBJECT( txt ), matrixview );\n    \t\tset_gentry( txt, \"%g\", val ); \n    \t\tgtk_signal_handler_unblock_by_data( \n    \t\t\tGTK_OBJECT( txt ), matrixview );\n    \t}\n}\n\n/* Fill the widgets!\n */\nstatic void\nmatrixview_text_refresh( Matrixview *matrixview )\n{\n    \tMatrix *matrix = MATRIX( VOBJECT( matrixview )->iobject );\n\tMatrixValue *matrixvalue = &matrix->value;\n\tint width = matrixvalue->width;\n\tint height = matrixvalue->height;\n\tGtkTreeModel *tree = GTK_TREE_MODEL( matrixview->store );\n\n\tint x, y;\n\tGtkTreeIter iter;\n\n\tif( !matrixvalue->coeff )\n\t\treturn;\n\n    \tmatrixview_text_set( matrixview, matrixview->scale, matrix->scale );\n    \tmatrixview_text_set( matrixview, matrixview->offset, matrix->offset );\n\n\tgtk_tree_model_get_iter_first( tree, &iter );\n\n\tfor( y = 0; y < height; y++ ) {\n\t\tfor( x = 0; x < width; x++ ) \n\t\t\tgtk_list_store_set( matrixview->store, &iter, \n\t\t\t\tx, matrixvalue->coeff[x + y * width], \n\t\t\t\t-1 );\n\n\t\tgtk_tree_model_iter_next( tree, &iter );\n\t}\n}\n\nstatic void\nmatrixview_refresh( vObject *vobject )\n{\n    \tMatrixview *matrixview = MATRIXVIEW( vobject );\n    \tMatrix *matrix = MATRIX( VOBJECT( matrixview )->iobject );\n\n    \tgboolean built;\n    \tgboolean hclip;\n    \tgboolean vclip;\n\tint width, height;\n\tint i;\n\n    \tbuilt = FALSE;\n    \thclip = FALSE;\n    \tvclip = FALSE;\n\n\t/* Find required size ... limit displays which are tables of widgets \n\t * to avoid huge slowness.\n\t */\n\twidth = matrix->value.width;\n\theight = matrix->value.height;\n\n\tif( matrix->display == MATRIX_DISPLAY_TOGGLE ||\n\t\tmatrix->display == MATRIX_DISPLAY_SLIDER ) {\n\t\tif( width * height > matrixview_max_cells ) {\n\t\t\tif( width > height ) {\n\t\t\t\twidth = IM_CLIP( 1, \n\t\t\t\t\tmatrixview_max_cells / height, \n\t\t\t\t\tmatrix->value.width );\n\t\t\t\thclip = TRUE;\n\t\t\t}\n\t\t\telse {\n\t\t\t\theight = IM_CLIP( 1, \n\t\t\t\t\tmatrixview_max_cells / width, \n\t\t\t\t\tmatrix->value.height );\n\t\t\t\tvclip = TRUE;\n\t\t\t}\n\t\t}\n\n\t\t/* Clip twice to make sure we clip in both directions if \n\t\t * necessary.\n\t\t */\n\t\tif( width * height > matrixview_max_cells ) {\n\t\t\tif( width > height ) {\n\t\t\t\twidth = IM_CLIP( 1, \n\t\t\t\t\tmatrixview_max_cells / height, \n\t\t\t\t\tmatrix->value.width );\n\t\t\t\thclip = TRUE;\n\t\t\t}\n\t\t\telse {\n\t\t\t\theight = IM_CLIP( 1, \n\t\t\t\t\tmatrixview_max_cells / width, \n\t\t\t\t\tmatrix->value.height );\n\t\t\t\tvclip = TRUE;\n\t\t\t}\n\t\t}\n\t}\n\n#ifdef DEBUG\n    \tprintf( \"matrixview_refresh\\n\" );\n#endif /*DEBUG*/\n\n    \t/* Is there a UI already there we can reuse? Has to be same size and\n    \t * type.\n    \t */\n    \tif( matrixview->display != matrix->display || \n    \t\tmatrixview->width != width || \n    \t\tmatrixview->height != height ) {\n    \t\t/* Kill old UI stuff.\n    \t\t */\n    \t\tIM_FREEF( gtk_widget_destroy, matrixview->sheet );\n    \t\tIM_FREEF( gtk_widget_destroy, matrixview->table );\n    \t\tIM_FREEF( gtk_widget_destroy, matrixview->swin );\n    \t\tIM_FREEF( g_slist_free, matrixview->items );\n    \t\tIM_FREEF( gtk_widget_destroy, matrixview->cbox );\n    \t\tmatrixview->scale = NULL;\n    \t\tmatrixview->offset = NULL;\n\n\t\t/* So the builders know how many widgets to make.\n\t\t */\n    \t\tmatrixview->width = width;\n    \t\tmatrixview->height = height;\n    \t\tmatrixview->display = matrix->display;\n\n    \t\t/* Make new contents. \n    \t\t */\n\t\tswitch( matrix->display ) {\n\t\tcase MATRIX_DISPLAY_TOGGLE:\n\t\t\tmatrixview_toggle_build( matrixview );\n\t\t\tbreak;\n\n\t\tcase MATRIX_DISPLAY_SLIDER:\n\t\t\tmatrixview_slider_build( matrixview );\n\t\t\tbreak;\n\n\t\tcase MATRIX_DISPLAY_TEXT:\n\t\tcase MATRIX_DISPLAY_TEXT_SCALE_OFFSET:\n\t\t\tmatrixview_text_build( matrixview );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tg_assert( FALSE );\n\t\t}\n\n\t\tif( hclip ) {\n\t\t\tgtk_table_resize( GTK_TABLE( matrixview->table ), \n\t\t\t\tmatrixview->height, matrixview->width + 1 );\n\n\t\t\tfor( i = 0; i < matrixview->height; i++ ) {\n\t\t\t\tGtkWidget *lab;\n\n\t\t\t\tlab = gtk_label_new( \"---\" );\n\t\t\t\tgtk_table_attach( \n\t\t\t\t\tGTK_TABLE( matrixview->table ), lab,\n\t\t\t\t\tmatrixview->width, \n\t\t\t\t\tmatrixview->width + 1, \n\t\t\t\t\ti, i + 1, \n\t\t\t\t\tGTK_FILL, GTK_FILL, 2, 2 );\n\t\t\t}\n\t\t}\n\n\t\tif( vclip ) {\n\t\t\tgtk_table_resize( GTK_TABLE( matrixview->table ), \n\t\t\t\tmatrixview->height + 1, matrixview->width );\n\n\t\t\tfor( i = 0; i < matrixview->width; i++ ) {\n\t\t\t\tGtkWidget *lab;\n\n\t\t\t\tlab = gtk_label_new( \"|\" );\n\t\t\t\tgtk_table_attach( \n\t\t\t\t\tGTK_TABLE( matrixview->table ), lab,\n\t\t\t\t\ti, i + 1, \n\t\t\t\t\tmatrixview->height, \n\t\t\t\t\tmatrixview->height + 1, \n\t\t\t\t\tGTK_FILL, GTK_FILL, 2, 2 );\n\t\t\t}\n\t\t}\n\n    \t\tbuilt = TRUE;\n    \t}\n\n    \tswitch( matrixview->display ) {\n    \tcase MATRIX_DISPLAY_TOGGLE:\n    \t\tmatrixview_toggle_refresh( matrixview );\n    \t\tbreak;\n\n    \tcase MATRIX_DISPLAY_SLIDER:\n    \t\tmatrixview_slider_refresh( matrixview );\n    \t\tbreak;\n\n    \tcase MATRIX_DISPLAY_TEXT:\n    \tcase MATRIX_DISPLAY_TEXT_SCALE_OFFSET:\n    \t\tmatrixview_text_refresh( matrixview );\n    \t\tbreak;\n\n    \tdefault:\n    \t\tg_assert( FALSE );\n    \t}\n\n    \t/* If we've built a new display, need to show after _refresh.\n    \t */\n    \tif( built ) {\n    \t\tgtk_widget_show_all( GTK_WIDGET( matrixview ) );\n    \t\tview_resize( VIEW( matrixview ) );\n    \t}\n\n    \tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\nmatrixview_class_init( MatrixviewClass *class )\n{\n    \tGtkObjectClass *object_class = (GtkObjectClass *) class;\n    \tvObjectClass *vobject_class = (vObjectClass *) class;\n    \tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n    \tobject_class->destroy = matrixview_destroy;\n\n    \t/* Create signals.\n    \t */\n\n    \t/* Init methods.\n    \t */\n    \tvobject_class->refresh = matrixview_refresh;\n\n    \tview_class->scan = matrixview_scan;\n}\n\nstatic void\nmatrixview_init( Matrixview *matrixview )\n{\n#ifdef DEBUG\n    \tprintf( \"matrixview_init\\n\" );\n#endif /*DEBUG*/\n\n    \tmatrixview->box = gtk_hbox_new( FALSE, 12 );\n        gtk_box_pack_start( GTK_BOX( matrixview ), \n    \t\tGTK_WIDGET( matrixview->box ), FALSE, FALSE, 0 );\n\n    \t/* Build on 1st refresh.\n    \t */\n    \tmatrixview->store = NULL;\n    \tmatrixview->sheet = NULL;\n    \tmatrixview->swin = NULL;\n    \tmatrixview->table = NULL;\n    \tmatrixview->items = NULL;\n    \tmatrixview->width = -1;\n    \tmatrixview->height = -1;\n    \tmatrixview->cbox = NULL;\n    \tmatrixview->scale = NULL;\n    \tmatrixview->offset = NULL;\n}\n\nGtkType\nmatrixview_get_type( void )\n{\n    \tstatic GtkType matrixview_type = 0;\n\n    \tif( !matrixview_type ) {\n    \t\tstatic const GtkTypeInfo info = {\n    \t\t\t\"Matrixview\",\n    \t\t\tsizeof( Matrixview ),\n    \t\t\tsizeof( MatrixviewClass ),\n    \t\t\t(GtkClassInitFunc) matrixview_class_init,\n    \t\t\t(GtkObjectInitFunc) matrixview_init,\n    \t\t\t/* reserved_1 */ NULL,\n    \t\t\t/* reserved_2 */ NULL,\n    \t\t\t(GtkClassInitFunc) NULL,\n    \t\t};\n\n    \t\tmatrixview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info );\n    \t}\n\n    \treturn( matrixview_type );\n}\n\nView *\nmatrixview_new( void )\n{\n    \tMatrixview *matrixview = gtk_type_new( TYPE_MATRIXVIEW );\n\n    \treturn( VIEW( matrixview ) );\n}\n\n"
  },
  {
    "path": "src/matrixview.h",
    "content": "/* a matrixview in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_MATRIXVIEW (matrixview_get_type())\n#define MATRIXVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_MATRIXVIEW, Matrixview ))\n#define MATRIXVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_MATRIXVIEW, MatrixviewClass ))\n#define IS_MATRIXVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_MATRIXVIEW ))\n#define IS_MATRIXVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_MATRIXVIEW ))\n\ntypedef struct _Matrixview {\n\tGraphicview parent_object;\n\n\tGtkWidget *box;\t\t\t/* Top level hbox we lay out in */\n\n\t/* If we're displaying a matrix with a gtktreeview. \n\t */\n\tGtkListStore *store;\n\tGtkWidget *sheet;\n\tGtkWidget *swin;\n\n\t/* Displaying a table of widgets: sliders or toggles. \n\t */\n\tGtkWidget *table;\t\t/* Matrix table */\n\tGSList *items; \t\t\t/* Widgets for elems */\n\tMatrixDisplayType display;\t/* What's in items at the mo */\n\tint width;\t\t\t/* Size of mat panel we have */\n\tint height;\n\n\tGtkWidget *cbox;\t\t/* Convolution only: scale & offset */\n\tGtkWidget *scale;\t\t\n\tGtkWidget *offset;\n} Matrixview;\n\ntypedef struct _MatrixviewClass {\n\tGraphicviewClass parent_class;\n\n\t/* My methods.\n\t */\n} MatrixviewClass;\n\nGtkType matrixview_get_type( void );\nView *matrixview_new( void );\n"
  },
  {
    "path": "src/model.c",
    "content": "/* abstract base class for things which form the model half of a model/view\n * pair\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* Stuff from bison ... needed as we call the lexer directly to rewrite\n * expressions.\n */\n#include \"parse.h\"\n\n/* Our signals. \n */\nenum {\n\tSIG_SCROLLTO,\t/* Views should try to make themselves visible */\n\tSIG_LAYOUT,\t/* Views should lay out their children */\n\tSIG_RESET,\t/* Reset edit mode in views */\n\tSIG_FRONT,\t/* Bring views to front */\n\tSIG_DISPLAY,\t/* Display on/off */\n\tSIG_LAST\n};\n\nstatic iContainerClass *parent_class = NULL;\n\nstatic guint model_signals[SIG_LAST] = { 0 };\n\n/* Base model ... built at startup.\n */\nstatic Model *model_base = NULL;\n\n/* All the model classes which can be built from XML.\n */\nstatic GSList *model_registered_loadable = NULL;\n\n/* The loadstate the lexer gets its rename stuff from.\n */\nModelLoadState *model_loadstate = NULL;\n\n/* Rename list functions.\n */\nstatic void *\nmodel_rename_destroy( ModelRename *rename )\n{\n\tIM_FREE( rename->old_name );\n\tIM_FREE( rename->new_name );\n\tIM_FREE( rename );\n\n\treturn( NULL );\n}\n\nstatic ModelRename *\nmodel_rename_new( const char *old_name, const char *new_name )\n{\n\tModelRename *rename;\n\n\tif( !(rename = INEW( NULL, ModelRename )) )\n\t\treturn( NULL );\n\trename->old_name = im_strdup( NULL, old_name );\n\trename->new_name = im_strdup( NULL, new_name );\n\tif( !rename->old_name || !rename->new_name ) {\n\t\tmodel_rename_destroy( rename );\n\t\treturn( NULL );\n\t}\n\n\treturn( rename );\n}\n\ngboolean\nmodel_loadstate_rename_new( ModelLoadState *state, \n\tconst char *old_name, const char *new_name )\n{\n\t/* Make a rename, even if old_name == new_name, since we want to have\n\t * new_name on the taken list.\n\t */\n\tModelRename *rename;\n\n\tif( !(rename = model_rename_new( old_name, new_name )) )\n\t\treturn( FALSE );\n\tstate->renames = g_slist_prepend( state->renames, rename );\n\n\treturn( TRUE );\n}\n\nstatic void *\nmodel_loadstate_taken_sub( ModelRename *rename, const char *name )\n{\n\tif( strcmp( rename->new_name, name ) == 0 )\n\t\treturn( rename );\n\n\treturn( NULL );\n}\n\n/* Is something already being renamed to @name.\n */\ngboolean\nmodel_loadstate_taken( ModelLoadState *state, const char *name )\n{\n\treturn( slist_map( state->renames, \n\t\t(SListMapFn) model_loadstate_taken_sub, (char *) name ) != \n\t\tNULL ); \n}\n\ngboolean\nmodel_loadstate_column_rename_new( ModelLoadState *state, \n\tconst char *old_name, const char *new_name )\n{\n\tif( strcmp( old_name, new_name ) != 0 ) { \n\t\tModelRename *rename;\n\n\t\tif( !(rename = model_rename_new( old_name, new_name )) )\n\t\t\treturn( FALSE );\n\t\tstate->column_renames = \n\t\t\tg_slist_prepend( state->column_renames, rename );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Is something already being renamed to @name.\n */\ngboolean\nmodel_loadstate_column_taken( ModelLoadState *state, const char *name )\n{\n\treturn( !!slist_map( state->column_renames, \n\t\t(SListMapFn) model_loadstate_taken_sub, (char *) name ) );\n}\n\nvoid\nmodel_loadstate_destroy( ModelLoadState *state )\n{\n\t/* We are probably registered as the xml error handler ... unregister!\n\t */\n\txmlSetGenericErrorFunc( NULL, NULL );\n\n\tIM_FREE( state->filename );\n\tIM_FREE( state->filename_user );\n\tIM_FREEF( xmlFreeDoc, state->xdoc );\n\tslist_map( state->renames, \n\t\t(SListMapFn) model_rename_destroy, NULL );\n\tslist_map( state->column_renames, \n\t\t(SListMapFn) model_rename_destroy, NULL );\n\tg_slist_free( state->renames );\n\n\tif( state->old_dir ) {\n\t\tpath_rewrite_add( state->old_dir, NULL, FALSE );\n\t\tIM_FREE( state->old_dir );\n\t}\n\n\tIM_FREE( state );\n}\n\nstatic void\nmodel_loadstate_error( ModelLoadState *state, const char *fmt, ... )\n{\n\tva_list ap;\n\n\tva_start( ap, fmt );\n\t(void) vips_buf_vappendf( &state->error_log, fmt, ap );\n\tva_end( ap );\n}\n\nstatic void\nmodel_loadstate_error_get( ModelLoadState *state )\n{\n\tchar *utf8;\n\n\tutf8 = f2utf8( vips_buf_all( &state->error_log ) );\n\terror_top( _( \"Load failed.\" ) );\n\terror_sub( _( \"Unable to load from file \\\"%s\\\". Error log is:\\n%s\" ),\n\t\tstate->filename, utf8 );\n\tg_free( utf8 );\n}\n\nModelLoadState *\nmodel_loadstate_new( const char *filename, const char *filename_user )\n{\n\tModelLoadState *state;\n\n\tif( !(state = INEW( NULL, ModelLoadState )) )\n\t\treturn( NULL );\n\tstate->xdoc = NULL;\n\tstate->renames = NULL;\n\tstate->column_renames = NULL; \n\tstate->major = MAJOR_VERSION;\n\tstate->minor = MINOR_VERSION;\n\tstate->micro = MICRO_VERSION;\n\tstate->rewrite_path = FALSE;\n\tstate->old_dir = FALSE;\n\n\tstate->filename = im_strdup( NULL, filename );\n\tif( filename_user )\n\t\tstate->filename_user = im_strdup( NULL, filename_user );\n\telse\n\t\tstate->filename_user = im_strdup( NULL, filename );\n\tif( !state->filename ||\n\t\t!state->filename_user ) { \n\t\tmodel_loadstate_destroy( state );\n\t\treturn( NULL );\n\t}\n\n\tvips_buf_init_static( &state->error_log, \n\t\tstate->error_log_buffer, MAX_STRSIZE );\n\n\txmlSetGenericErrorFunc( state, \n\t\t(xmlGenericErrorFunc) model_loadstate_error );\n\tif( !(state->xdoc = (xmlDoc *) callv_string_filename( \n\t\t(callv_string_fn) xmlParseFile, \n\t\tstate->filename, NULL, NULL, NULL )) ) {\n\t\tmodel_loadstate_error_get( state );\n\t\tmodel_loadstate_destroy( state );\n\t\treturn( NULL );\n\t}\n\n\treturn( state );\n}\n\nModelLoadState *\nmodel_loadstate_new_openfile( iOpenFile *of )\n{\n\tModelLoadState *state;\n\tchar load_buffer[MAX_STRSIZE];\n\n\tif( !(state = INEW( NULL, ModelLoadState )) )\n\t\treturn( NULL );\n\tstate->renames = NULL;\n\tstate->xdoc = NULL;\n\tif( !(state->filename = im_strdup( NULL, of->fname )) ) {\n\t\tmodel_loadstate_destroy( state );\n\t\treturn( NULL );\n\t}\n\tvips_buf_init_static( &state->error_log, \n\t\tstate->error_log_buffer, MAX_STRSIZE );\n\n\txmlSetGenericErrorFunc( state, \n\t\t(xmlGenericErrorFunc) model_loadstate_error );\n\tif( !ifile_read_buffer( of, load_buffer, MAX_STRSIZE ) ) {\n\t\tmodel_loadstate_destroy( state );\n\t\treturn( NULL );\n\t}\n\tif( !(state->xdoc = xmlParseMemory( load_buffer, MAX_STRSIZE )) ) { \n\t\tmodel_loadstate_error_get( state );\n\t\tmodel_loadstate_destroy( state );\n\t\treturn( NULL );\n\t}\n\n\treturn( state );\n}\n\n/* If old_name is on the global rewrite list, rewrite it! Called from the\n * lexer.\n */\nchar *\nmodel_loadstate_rewrite_name( char *name )\n{\n\tModelLoadState *state = model_loadstate;\n\tGSList *i;\n\n\tif( !state || !state->renames )\n\t\treturn( NULL );\n\n\tfor( i = state->renames; i; i = i->next ) {\n\t\tModelRename *rename = (ModelRename *) (i->data);\n\n\t\tif( strcmp( name, rename->old_name ) == 0 )\n\t\t\treturn( rename->new_name );\n\t}\n\n\treturn( NULL );\n}\n\n/* Use the lexer to rewrite an expression, swapping all symbols on the rewrite \n * list.\n */\nvoid\nmodel_loadstate_rewrite( ModelLoadState *state, char *old_rhs, char *new_rhs )\n{\n\tint yychar;\n\textern int yylex( void );\n\n\tmodel_loadstate = state;\n\tattach_input_string( old_rhs );\n\tif( setjmp( parse_error_point ) ) {\n\t\t/* Here for yyerror in lex. Just ignore errors --- the parser\n\t\t * will spot them later anyway.\n\t\t */\n\t\tmodel_loadstate = NULL;\n\t\treturn; \n\t}\n\n\t/* Lex and rewrite.\n\t */\n\tstate->rewrite_path = FALSE;\n\twhile( (yychar = yylex()) > 0 ) {\n\t\t/* If we see an Image_file or Matrix_file token, rewrite the \n\t\t * following token if it's a string constant.\n\t\t */\n\t\tstate->rewrite_path = FALSE;\n\t\tif( yychar == TK_IDENT &&\n\t\t\tstrcmp( yylval.yy_name, \"Image_file\" ) == 0 )\n\t\t\tstate->rewrite_path = TRUE;\n\t\tif( yychar == TK_IDENT &&\n\t\t\tstrcmp( yylval.yy_name, \"Matrix_file\" ) == 0 )\n\t\t\tstate->rewrite_path = TRUE;\n\n\t\tfree_lex( yychar );\n\t}\n\n\tmodel_loadstate = NULL;\n\n\t/* Take copy of lexed and rewritten stuff.\n\t */\n\tim_strncpy( new_rhs, vips_buf_all( &lex_text ), MAX_STRSIZE );\n}\n\nView *\nmodel_view_new( Model *model, View *parent )\n{\n\tModelClass *model_class = MODEL_GET_CLASS( model );\n\tView *view;\n\n\tif( !model_class->view_new ) \n\t\treturn( NULL );\n\n\tview = model_class->view_new( model, parent );\n\tview_link( view, model, parent );\n\n\treturn( view );\n}\n\n/* Register a model subclass as loadable ... what we allow when we load an\n * XML node's children.\n */\nvoid \nmodel_register_loadable( ModelClass *model_class )\n{\n\tmodel_registered_loadable = g_slist_prepend( model_registered_loadable, \n\t\tmodel_class );\n}\n\nvoid\nmodel_scrollto( Model *model, ModelScrollPosition position )\n{\n\tg_assert( IS_MODEL( model ) );\n\n\tg_signal_emit( G_OBJECT( model ), \n\t\tmodel_signals[SIG_SCROLLTO], 0, position );\n}\n\nvoid\nmodel_layout( Model *model )\n{\n\tg_assert( IS_MODEL( model ) );\n\n\tg_signal_emit( G_OBJECT( model ), model_signals[SIG_LAYOUT], 0 );\n}\n\nvoid\nmodel_front( Model *model )\n{\n\tg_assert( IS_MODEL( model ) );\n\n\tg_signal_emit( G_OBJECT( model ), model_signals[SIG_FRONT], 0 );\n}\n\nvoid\nmodel_display( Model *model, gboolean display )\n{\n\tif( model ) { \n\t\tg_assert( IS_MODEL( model ) );\n\n\t\tg_signal_emit( G_OBJECT( model ), \n\t\t\tmodel_signals[SIG_DISPLAY], 0, display );\n\t}\n}\n\nvoid *\nmodel_reset( Model *model )\n{\n\tg_assert( IS_MODEL( model ) );\n\n\tg_signal_emit( G_OBJECT( model ), model_signals[SIG_RESET], 0 );\n\n\treturn( NULL );\n}\n\nvoid *\nmodel_edit( GtkWidget *parent, Model *model )\n{\n\tModelClass *model_class = MODEL_GET_CLASS( model );\n\n\tif( model_class->edit )\n\t\tmodel_class->edit( parent, model );\n\telse {\n\t\terror_top( _( \"Not implemented.\" ) );\n\t\terror_sub( _( \"_%s() not implemented for class \\\"%s\\\".\" ), \n\t\t\t\"edit\", \n\t\t\tG_OBJECT_CLASS_NAME( model_class ) );\n\t}\n\n\treturn( NULL );\n}\n\nvoid *\nmodel_header( GtkWidget *parent, Model *model )\n{\n\tModelClass *model_class = MODEL_GET_CLASS( model );\n\n\tif( model_class->header )\n\t\tmodel_class->header( parent, model );\n\telse {\n\t\terror_top( _( \"Not implemented.\" ) );\n\t\terror_sub( _( \"_%s() not implemented for class \\\"%s\\\".\" ), \n\t\t\t\"header\", \n\t\t\tG_OBJECT_CLASS_NAME( model_class ) );\n\t}\n\n\treturn( NULL );\n}\n\nvoid *\nmodel_save( Model *model, xmlNode *xnode )\n{\n\tModelClass *model_class = MODEL_GET_CLASS( model );\n\n\tif( model_save_test( model ) ) {\n\t\tif( model_class->save && !model_class->save( model, xnode ) )\n\t\t\treturn( model );\n\t}\n\n\treturn( NULL );\n}\n\ngboolean\nmodel_save_test( Model *model )\n{\n\tModelClass *model_class = MODEL_GET_CLASS( model );\n\n\tif( model_class->save_test )\n\t\treturn( model_class->save_test( model ) );\n\n\treturn( TRUE );\n}\n\nvoid *\nmodel_save_text( Model *model, iOpenFile *of )\n{\n\tModelClass *model_class = MODEL_GET_CLASS( model );\n\n\tif( model_class->save_text && !model_class->save_text( model, of ) )\n\t\treturn( model );\n\n\treturn( NULL );\n}\n\nvoid *\nmodel_load( Model *model, \n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\tModelClass *model_class = MODEL_GET_CLASS( model );\n\n\tif( model_class->load ) {\n\t\tif( !model_class->load( model, state, parent, xnode ) )\n\t\t\treturn( model );\n\t}\n\telse {\n\t\terror_top( _( \"Not implemented.\" ) );\n\t\terror_sub( _( \"_%s() not implemented for class \\\"%s\\\".\" ), \n\t\t\t\"load\", \n\t\t\tG_OBJECT_CLASS_NAME( model_class ) );\n\t}\n\n\treturn( NULL );\n}\n\nvoid *\nmodel_load_text( Model *model, Model *parent, iOpenFile *of )\n{\n\tModelClass *model_class = MODEL_GET_CLASS( model );\n\n\tif( model_class->load_text ) {\n\t\tif( !model_class->load_text( model, parent, of ) )\n\t\t\treturn( model );\n\t}\n\telse {\n\t\terror_top( \"Not implemented.\" );\n\t\terror_sub( _( \"_%s() not implemented for class \\\"%s\\\".\" ), \n\t\t\t\"load_text\", \n\t\t\tG_OBJECT_CLASS_NAME( model_class ) );\n\t}\n\n\treturn( NULL );\n}\n\nvoid *\nmodel_empty( Model *model )\n{\n\tModelClass *model_class = MODEL_GET_CLASS( model );\n\n\tif( model_class->empty )\n\t\tmodel_class->empty( model );\n\n\treturn( NULL );\n}\n\nstatic void\nmodel_real_scrollto( Model *model, ModelScrollPosition position )\n{\n}\n\nstatic void\nmodel_real_front( Model *model )\n{\n}\n\nstatic void\nmodel_real_display( Model *model, gboolean display )\n{\n\tif( display != model->display ) {\n\t\tmodel->display = display;\n\t\tiobject_changed( IOBJECT( model ) );\n\t}\n}\n\nstatic xmlNode *\nmodel_real_save( Model *model, xmlNode *xnode )\n{\n\tconst char *tname = G_OBJECT_TYPE_NAME( model );\n\txmlNode *xthis;\n\n\tif( !(xthis = xmlNewChild( xnode, NULL, (xmlChar *) tname, NULL )) ) {\n\t\terror_top( _( \"XML library error.\" ) );\n\t\terror_sub( _( \"model_save: xmlNewChild() failed\" ) );\n\t\treturn( NULL );\n\t}\n\n\tif( icontainer_map( ICONTAINER( model ), \n\t\t(icontainer_map_fn) model_save, xthis, NULL ) )\n\t\treturn( NULL );\n\n\tif( model->window_width != -1 ) {\n\t\tif( !set_iprop( xthis, \"window_x\", model->window_x ) ||\n\t\t\t!set_iprop( xthis, \"window_y\", model->window_y ) ||\n\t\t\t!set_iprop( xthis, \"window_width\", \n\t\t\t\tmodel->window_width ) ||\n\t\t\t!set_iprop( xthis, \"window_height\", \n\t\t\t\tmodel->window_height ) )\n\t\t\treturn( NULL );\n\t}\n\n\treturn( xthis );\n}\n\nstatic void *\nmodel_new_xml_sub( ModelClass *model_class, \n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\tGtkType type = GTK_CLASS_TYPE( model_class );\n\tconst char *tname = gtk_type_name( type );\n\n\tif( strcasecmp( (char *) xnode->name, tname ) == 0 ) {\n\t\tModel *model = MODEL( g_object_new( type, NULL ) );\n\n\t\tif( model_load( model, state, parent, xnode ) ) {\n\t\t\tg_object_unref( model );\n\t\t\treturn( model_class );\n\t\t}\n\n\t\treturn( NULL );\n\t}\n\n\treturn( NULL );\n}\n\ngboolean\nmodel_new_xml( ModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\t/* \n\n\t\tFIXME ... slow! some sort of hash? time this at some point\n\n\t */\n\tif( slist_map3( model_registered_loadable,\n\t\t(SListMap3Fn) model_new_xml_sub, state, parent, xnode ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic gboolean \nmodel_real_load( Model *model,\n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\tconst char *tname = G_OBJECT_TYPE_NAME( model );\n\txmlNode *i;\n\n\t/* Should just be a sanity check.\n\t */\n\tif( strcasecmp( (char *) xnode->name, tname ) != 0 ) {\n\t\terror_top( _( \"XML load error.\" ) );\n\t\terror_sub( _( \"Can't load node of type \\\"%s\\\" into \"\n\t\t\t\"object of type \\\"%s\\\"\" ), xnode->name, tname );\n\t\treturn( FALSE );\n\t}\n\n\t(void) get_iprop( xnode, \"window_x\", &model->window_x );\n\t(void) get_iprop( xnode, \"window_y\", &model->window_y );\n\t(void) get_iprop( xnode, \"window_width\", &model->window_width );\n\t(void) get_iprop( xnode, \"window_height\", &model->window_height );\n\n\tif( !ICONTAINER( model )->parent )\n\t\ticontainer_child_add( ICONTAINER( parent ), \n\t\t\tICONTAINER( model ), -1 );\n\n\tfor( i = xnode->children; i; i = i->next ) \n\t\tif( !model_new_xml( state, MODEL( model ), i ) )\n\t\t\treturn( FALSE );\n\n#ifdef DEBUG\n\tprintf( \"model_real_load: finished loading %s (name = %s)\\n\", \n\t\ttname, \n\t\tNN( IOBJECT( model )->name ) );\n#endif /*DEBUG*/\n\n\treturn( TRUE );\n}\n\nstatic void\nmodel_real_empty( Model *model )\n{\n\ticontainer_map( ICONTAINER( model ),\n\t\t(icontainer_map_fn) icontainer_child_remove, NULL, NULL );\n}\n\nstatic void\nmodel_class_init( ModelClass *class )\n{\n\tiObjectClass *object_class = IOBJECT_CLASS( class );\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tclass->view_new = NULL;\n\tclass->edit = NULL;\n\tclass->scrollto = model_real_scrollto;\n\tclass->layout = NULL;\n\tclass->front = model_real_front;\n\tclass->display = model_real_display;\n\tclass->reset = NULL;\n\tclass->save = model_real_save;\n\tclass->save_test = NULL;\n\tclass->save_text = NULL;\n\tclass->load = model_real_load;\n\tclass->load_text = NULL;\n\tclass->empty = model_real_empty;\n\n\t/* Create signals.\n\t */\n\tmodel_signals[SIG_SCROLLTO] = g_signal_new( \"scrollto\",\n\t\tG_OBJECT_CLASS_TYPE( object_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ModelClass, scrollto ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__INT,\n\t\tG_TYPE_NONE, 1,\n\t\tG_TYPE_INT );\n\tmodel_signals[SIG_LAYOUT] = g_signal_new( \"layout\",\n\t\tG_OBJECT_CLASS_TYPE( object_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ModelClass, layout ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\tmodel_signals[SIG_FRONT] = g_signal_new( \"front\",\n\t\tG_OBJECT_CLASS_TYPE( object_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ModelClass, front ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\tmodel_signals[SIG_RESET] = g_signal_new( \"reset\",\n\t\tG_OBJECT_CLASS_TYPE( object_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ModelClass, reset ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\tmodel_signals[SIG_DISPLAY] = g_signal_new( \"display\",\n\t\tG_OBJECT_CLASS_TYPE( object_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ModelClass, display ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__BOOLEAN,\n\t\tG_TYPE_NONE, 1,\n\t\tG_TYPE_BOOLEAN );\n}\n\nstatic void\nmodel_init( Model *model )\n{\n\tmodel->display = TRUE;\n\n\t/* Magic: -1 means none of these saved settings are valid. It'd be\n\t * nice to do something better, but we'd break old workspaces.\n\t */\n\tmodel->window_x = 0;\n\tmodel->window_y = 0;\n\tmodel->window_width = -1;\t\n\tmodel->window_height = 0;\n}\n\nGType\nmodel_get_type( void )\n{\n\tstatic GType model_type = 0;\n\n\tif( !model_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ModelClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) model_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Model ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) model_init,\n\t\t};\n\n\t\tmodel_type = g_type_register_static( TYPE_ICONTAINER, \n\t\t\t\"Model\", &info, 0 );\n\t}\n\n\treturn( model_type );\n}\n\nvoid\nmodel_base_init( void )\n{\n\tmodel_base = MODEL( g_object_new( TYPE_MODEL, NULL ) );\n\n\t/* We have to init some of our other classes to get them registered \n\t * with the class loader.\n\t */\n\t(void) g_type_class_ref( TYPE_CLOCK );\n\t(void) g_type_class_ref( TYPE_COLOUR );\n\t(void) g_type_class_ref( TYPE_EXPRESSION );\n\t(void) g_type_class_ref( TYPE_FONTNAME );\n\t(void) g_type_class_ref( TYPE_GROUP );\n\t(void) g_type_class_ref( TYPE_IARROW );\n\t(void) g_type_class_ref( TYPE_IIMAGE );\n\t(void) g_type_class_ref( TYPE_IREGION );\n\t(void) g_type_class_ref( TYPE_ITEXT );\n\t(void) g_type_class_ref( TYPE_MATRIX );\n\t(void) g_type_class_ref( TYPE_NUMBER );\n\t(void) g_type_class_ref( TYPE_OPTION );\n\t(void) g_type_class_ref( TYPE_PATHNAME );\n\t(void) g_type_class_ref( TYPE_PLOT );\n\t(void) g_type_class_ref( TYPE_REAL );\n\t(void) g_type_class_ref( TYPE_SLIDER );\n\t(void) g_type_class_ref( TYPE_STRING );\n\t(void) g_type_class_ref( TYPE_TOGGLE );\n\t(void) g_type_class_ref( TYPE_VECTOR );\n\n\t(void) g_type_class_ref( TYPE_RHS );\n\t(void) g_type_class_ref( TYPE_ROW );\n\t(void) g_type_class_ref( TYPE_SUBCOLUMN );\n\t(void) g_type_class_ref( TYPE_WORKSPACE );\n\t(void) g_type_class_ref( TYPE_COLUMN );\n}\n\ntypedef struct {\n\tiDialog *idlg;\t\t/* The yesno we run */\n\tModel *model;\t\t/* The model we watch */\n\tguint destroy_sid;\t/* sid for the destroy */\n\tiWindowFn done_cb;\t/* Call this at the end */\n} ModelCheckDestroy;\n\n/* OK to destroy.\n */\nstatic void\nmodel_check_destroy_sub( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tModelCheckDestroy *mcd = (ModelCheckDestroy *) client;\n\n\tmcd->idlg = NULL;\n\tIDESTROY( mcd->model );\n\tsymbol_recalculate_all();\n\n\tmcd->done_cb( iwnd, NULL, nfn, sys );\n}\n\n/* The model we are watching has been killed, maybe by us.\n */\nstatic void\nmodel_check_destroy_destroy_cb( Model *model, ModelCheckDestroy *mcd )\n{\n\tg_assert( IS_MODEL( model ) );\n\tg_assert( IS_MODEL( mcd->model ) );\n\tg_assert( !mcd->idlg || IS_IDIALOG( mcd->idlg ) );\n\n\tmcd->model = NULL;\n\tmcd->destroy_sid = 0;\n\n\tif( mcd->idlg ) {\n\t\tiWindow *iwnd = IWINDOW( mcd->idlg );\n\n\t\tmcd->idlg = NULL;\n\t\tiwindow_kill( iwnd );\n\t}\n}\n\n/* Our dialog is done.\n */\nstatic void \nmodel_check_destroy_finished( void *client, iWindowResult result ) \n{ \n\tModelCheckDestroy *mcd = (ModelCheckDestroy *) client;\n\n\tFREESID( mcd->destroy_sid, mcd->model );\n\tIM_FREE( mcd );\n}\n\nvoid\nmodel_check_destroy( GtkWidget *parent, Model *model, iWindowFn done_cb )\n{\n\tchar txt[30];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tconst char *name;\n\n\tModelCheckDestroy *mcd = INEW( NULL, ModelCheckDestroy );\n\n\tmcd->idlg = NULL;\n\tmcd->model = model;\n\tmcd->done_cb = done_cb ? done_cb : iwindow_true_cb;\n\n\tif( IS_SYMBOL( model ) ) {\n\t\tsymbol_qualified_name( SYMBOL( model ), &buf );\n\t\tname = vips_buf_all( &buf );\n\t}\n\telse\n\t\tname = IOBJECT( model )->name;\n\n\tmcd->idlg = box_yesno( parent,\n\t\tmodel_check_destroy_sub, iwindow_true_cb, mcd, \n\t\tmodel_check_destroy_finished, mcd,\n\t\tGTK_STOCK_DELETE, \n\t\t_( \"Delete?\" ),\n\t\t_( \"Are you sure you want to delete %s \\\"%s\\\"?\" ), \n\t\tIOBJECT_GET_CLASS_NAME( model ), name );\n\n\t/* In case someone else kills this model before we do.\n\t */\n\tmcd->destroy_sid = g_signal_connect( model, \"destroy\",\n\t\tG_CALLBACK( model_check_destroy_destroy_cb ), mcd );\n}\n\n/* Useful for icontainer_map_all() ... trigger all heapmodel_clear_edited()\n * methods.\n */\nvoid *\nmodel_clear_edited( Model *model )\n{\n\tvoid *result;\n\n\tif( IS_HEAPMODEL( model ) && \n\t\t(result = heapmodel_clear_edited( HEAPMODEL( model ) )) )\n\t\treturn( result );\n\n\treturn( NULL );\n}\n"
  },
  {
    "path": "src/model.h",
    "content": "/* abstract base class for things which form the model of a model/view pair \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* When scrolling, do we want the top or the bottom of the object visible.\n * Important for Columns, since we sometimes want to see the title bar and\n * sometimes the edit box at the bottom.\n */\ntypedef enum {\n\tMODEL_SCROLL_TOP,\n\tMODEL_SCROLL_BOTTOM\n} ModelScrollPosition;\n\n/* How to rename symbols.\n */\ntypedef struct _ModelRename {\n\tchar *old_name;\n\tchar *new_name;\n} ModelRename;\n\n/* What we track during a load operation.\n */\ntypedef struct _ModelLoadState {\n\tchar *filename;\t\t/* Name we loaded from */\n\tchar *filename_user;\t/* The filename to record in the model */\n\txmlDoc *xdoc;\t\t/* Document we load from */\n\n\t/* \n\n\t\tFIXME ... a linked list? try a hash sometime\n\t\tsee model_loadstate_rewrite_name()\n\n\t\twould probably only see a speedup for merging very large\n\t\tworkspaces, not something we do often\n\n\t */\n\tGSList *renames;\t/* Rename table for this load context */\n\n\t/* The column renames we have planned. Don't rewrite exprs with these.\n\t */\n\tGSList *column_renames;\n\n\t/* Version info we read from this XML file.\n\t */\n\tint major;\n\tint minor;\n\tint micro;\n\n\t/* Log error messages here.\n\t */\n\tchar error_log_buffer[MAX_STRSIZE];\n\tVipsBuf error_log;\n\n\t/* Set this bool to rewrite string constants using the filename\n\t * rewrite system.\n\t */\n\tgboolean rewrite_path;\n\n\t/* The old_dir we added with path_rewrite_add() ... if non, NULL,\n\t * unset this rewrite rule on close.\n\t */\n\tchar *old_dir;\n} ModelLoadState;\n\n#define TYPE_MODEL (model_get_type())\n#define MODEL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_MODEL, Model ))\n#define MODEL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_MODEL, ModelClass))\n#define IS_MODEL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_MODEL ))\n#define IS_MODEL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_MODEL ))\n#define MODEL_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_MODEL, ModelClass ))\n\nstruct _Model {\n\tiContainer parent_object;\n\n\t/* My instance vars.\n\t */\n\tgboolean display;\t/* This model should have a view */\n\n\t/* For things that have a pop-up window (eg. iimage, plot), the\n\t * position and size of the window.\n\t */\n\tint window_x, window_y;\n\tint window_width, window_height;\n};\n\ntypedef struct _ModelClass {\n\tiContainerClass parent_class;\n\n\t/* Build display methods.\n\n\t\tview_new\tmake a view for this model ... make the top\n\t\t\t\tview yourself, thereafter view will watch\n\t\t\t\tchild_add etc. and manage subviews\n\t\t\t\tautomatically ... use model->display to create\n\t\t\t\tand destroy views\n\n\t */\n\n\tView *(*view_new)( Model *model, View *parent );\n\n\t/* Change methods\n\n\t\tedit\t\topen an editor on the model\n\n\t\theader\t\tview model header \n\n\t\tscrollto\ttry to make views visible\n\n\t\treset\t\tsignals views to reset ... eg. textview pops\n\t\t\t\tback to whatever the ws says it should be\n\t\t\t\tdisplaying (value or formula)\n\n\t\tlayout \t\ttry to lay child view out\n\n\t\tfront\t\ttrigger view_child_front() for all views\n\n\t\tdisplay\t\tcreate and destroy views\n\n\t */\n\n\tvoid (*edit)( GtkWidget *, Model * );\n\tvoid (*header)( GtkWidget *, Model * );\n\tvoid (*scrollto)( Model *, ModelScrollPosition );\n\tvoid (*reset)( Model * );\n\tvoid (*layout)( Model * );\n\tvoid (*front)( Model * );\n\tvoid (*display)( Model *, gboolean display );\n\n\t/* Load and save methods.\n\n\t\tsave\t\twrite model as child of node\n\n\t\tsave_test\tpredicate ... save model if save_test is \n\t\t\t\tdefined and true\n\n\t\tsave_text\tplain text save ... eg. for toolkits\n\n\t\tload\t\t_init() model from xmlNode\n\n\t\tload_text\t_init() from plain text ... eg. toolkit\n\n\t\tempty\t\tremove contents of model\n\n\t */\n\txmlNode *(*save)( Model *, xmlNode * );\n\tgboolean (*save_test)( Model * );\n\tgboolean (*save_text)( Model *, iOpenFile * );\n\tgboolean (*load)( Model *model, \n\t\tModelLoadState *state, Model *parent, xmlNode *xnode );\n\tgboolean (*load_text)( Model *model, Model *parent, iOpenFile * );\n\tvoid (*empty)( Model * );\n} ModelClass;\n\nextern ModelLoadState *model_loadstate;\n\ngboolean model_loadstate_rename_new( ModelLoadState *state, \n\tconst char *old_name, const char *new_name );\ngboolean model_loadstate_taken( ModelLoadState *state, const char *name );\ngboolean model_loadstate_column_rename_new( ModelLoadState *state, \n\tconst char *old_name, const char *new_name );\ngboolean model_loadstate_column_taken( ModelLoadState *state, \n\tconst char *name );\nModelLoadState *model_loadstate_new( \n\tconst char *filename, const char *filename_user );\nModelLoadState *model_loadstate_new_openfile( iOpenFile *of );\nvoid model_loadstate_destroy( ModelLoadState *state );\nchar *model_loadstate_rewrite_name( char *name );\nvoid model_loadstate_rewrite( ModelLoadState *state, \n\tchar *old_rhs, char *new_rhs );\n\nvoid model_register_loadable( ModelClass *model_class );\n\nView *model_view_new( Model *model, View *parent );\nvoid model_scrollto( Model *model, ModelScrollPosition position );\nvoid model_layout( Model *model );\nvoid *model_reset( Model *model );\nvoid *model_edit( GtkWidget *parent, Model *model );\nvoid *model_header( GtkWidget *parent, Model *model );\nvoid model_front( Model *model );\nvoid model_display( Model *model, gboolean display );\n\nvoid *model_save( Model *model, xmlNode * );\ngboolean model_save_test( Model *model );\nvoid *model_save_text( Model *model, iOpenFile * );\nvoid *model_load( Model *model,\n\tModelLoadState *state, Model *parent, xmlNode *xnode );\nvoid *model_load_text( Model *model, Model *parent, iOpenFile * );\nvoid *model_empty( Model *model );\n\ngboolean model_new_xml( ModelLoadState *state, Model *parent, xmlNode *xnode );\n\nGType model_get_type( void );\n\nvoid model_base_init( void );\n\nView *model_build_display_all( Model *model, View *parent );\n\nvoid model_check_destroy( GtkWidget *parent, Model *model, iWindowFn done_cb );\n\nvoid *model_clear_edited( Model *model );\n"
  },
  {
    "path": "src/nip2-cli.c",
    "content": "/* nip2-cli.c ... run the nip2 executable, connecting stdin and stdout to the\n * console\n *\n * 11/12/09\n * \t- use SetHandleInformation() to stop the child inheriting the read\n * \t  handle (thanks Leo)\n */\n\n/*\n\n    Copyright (C) 2008 Imperial College, London\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* Adapted from sample code by Leo Davidson, with the author's permission.\n */\n\n/* Windows does not let a single exe run in both command-line and GUI mode. To\n * run nip2 in command-line mode, we run this CLI wrapper program instead,\n * which starts the main nip2 exe, connecting stdin/out/err appropriately.\n */\n\n#include <windows.h>\n#include <stdio.h>\n#include <io.h>\n#include <ctype.h>\n\n#include <glib.h>\n\nvoid\nprint_last_error ()\n{\n  char *buf;\n\n  if (FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |\n\t\t      FORMAT_MESSAGE_IGNORE_INSERTS |\n\t\t      FORMAT_MESSAGE_FROM_SYSTEM,\n\t\t      NULL,\n\t\t      GetLastError (),\n\t\t      MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),\n\t\t      (LPSTR) & buf, 0, NULL))\n    {\n      fprintf (stderr, \"%s\", buf);\n      LocalFree (buf);\n    }\n}\n\nint\nmain (int argc, char **argv)\n{\n  char *dirname;\n  char command[2048];\n  gboolean quote;\n  int i, j;\n\n  HANDLE hChildStdoutRd;\n  HANDLE hChildStdoutWr;\n  SECURITY_ATTRIBUTES saAttr;\n\n  PROCESS_INFORMATION processInformation;\n  STARTUPINFO startUpInfo;\n\n  DWORD dwRead;\n  CHAR buf[1024];\n\n  /* we run the nip2.exe in the same directory as this exe: swap the last \n   * pathname component for nip2.exe\n   * we change the argv[0] pointer, probably not a good idea\n   */\n  dirname = g_path_get_dirname (argv[0]);\n  argv[0] = g_build_filename (dirname, \"nip2.exe\", NULL);\n  g_free (dirname);\n\n  if (_access (argv[0], 00))\n    {\n      fprintf (stderr, \"cannot access \\\"%s\\\"\\n\", argv[0]);\n      exit (1);\n    }\n\n  /* build the command string ... we have to quote items containing spaces\n   */\n  command[0] = '\\0';\n  for (i = 0; i < argc; i++)\n    {\n      quote = FALSE;\n      for (j = 0; argv[i][j]; j++)\n\t{\n\t  if (isspace (argv[i][j]))\n\t    {\n\t      quote = TRUE;\n\t      break;\n\t    }\n\t}\n      if (i > 0)\n\t{\n\t  strncat (command, \" \", sizeof (command) - 1);\n\t}\n      if (quote)\n\t{\n\t  strncat (command, \"\\\"\", sizeof (command) - 1);\n\t}\n      strncat (command, argv[i], sizeof (command) - 1);\n      if (quote)\n\t{\n\t  strncat (command, \"\\\"\", sizeof (command) - 1);\n\t}\n    }\n\n  if (strlen (command) == sizeof (command) - 1)\n    {\n      fprintf (stderr, \"command too long\\n\");\n      exit (1);\n    }\n\n  /* Create a pipe for the child process's STDOUT. \n   */\n  hChildStdoutRd = NULL;\n  hChildStdoutWr = NULL;\n  saAttr.nLength = sizeof (SECURITY_ATTRIBUTES);\n  saAttr.bInheritHandle = TRUE;\n  saAttr.lpSecurityDescriptor = NULL;\n  if (!CreatePipe (&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))\n    {\n      fprintf (stderr, \"CreatePipe failed: \");\n      print_last_error ();\n      fprintf (stderr, \"\\n\");\n      exit (1);\n    }\n\n  /* Ensure the read handle to the pipe for STDOUT is not inherited.\n   */\n  if (!SetHandleInformation(hChildStdoutRd, HANDLE_FLAG_INHERIT, 0))\n    {\n      fprintf (stderr, \"SetHandleInformation failed: \");\n      print_last_error ();\n      fprintf (stderr, \"\\n\");\n      exit (1);\n    }\n\n  /* Run command.\n   */\n  startUpInfo.cb = sizeof (STARTUPINFO);\n  startUpInfo.lpReserved = NULL;\n  startUpInfo.lpDesktop = NULL;\n  startUpInfo.lpTitle = NULL;\n  startUpInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;\n  startUpInfo.hStdOutput = hChildStdoutWr;\n  startUpInfo.hStdError = hChildStdoutWr;\n  startUpInfo.cbReserved2 = 0;\n  startUpInfo.lpReserved2 = NULL;\n  startUpInfo.wShowWindow = SW_SHOWNORMAL;\n  if (!CreateProcess (NULL, command, NULL,\t/* default security */\n\t\t      NULL,\t/* default thread security */\n\t\t      TRUE,\t/* inherit handles */\n\t\t      CREATE_DEFAULT_ERROR_MODE | DETACHED_PROCESS, NULL,\t/* use default environment */\n\t\t      NULL,\t/* set default directory */\n\t\t      &startUpInfo, &processInformation))\n    {\n      fprintf (stderr, \"error running \\\"%s\\\": \", command);\n      print_last_error ();\n      fprintf (stderr, \"\\n\");\n      exit (1);\n    }\n\n  /* Close the write end of the pipe before reading from the read end.\n   */\n  CloseHandle (hChildStdoutWr);\n\n  while (ReadFile (hChildStdoutRd, buf, sizeof (buf) - 1, &dwRead, NULL) &&\n\t dwRead > 0)\n    {\n      buf[dwRead] = '\\0';\n      printf (\"%s\", buf);\n    }\n\n  CloseHandle (hChildStdoutRd);\n\n  return (0);\n}\n"
  },
  {
    "path": "src/nip2-icon.rc",
    "content": "1 ICON \"nip2-icon.ico\"\n"
  },
  {
    "path": "src/nipmarshal.c",
    "content": "#include \"nipmarshal.h\"\n\n#include\t<glib-object.h>\n\n\n#ifdef G_ENABLE_DEBUG\n#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)\n#define g_marshal_value_peek_char(v)     g_value_get_char (v)\n#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)\n#define g_marshal_value_peek_int(v)      g_value_get_int (v)\n#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)\n#define g_marshal_value_peek_long(v)     g_value_get_long (v)\n#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)\n#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)\n#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)\n#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)\n#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)\n#define g_marshal_value_peek_float(v)    g_value_get_float (v)\n#define g_marshal_value_peek_double(v)   g_value_get_double (v)\n#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)\n#define g_marshal_value_peek_param(v)    g_value_get_param (v)\n#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)\n#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)\n#define g_marshal_value_peek_object(v)   g_value_get_object (v)\n#else /* !G_ENABLE_DEBUG */\n/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.\n *          Do not access GValues directly in your code. Instead, use the\n *          g_value_get_*() functions\n */\n#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int\n#define g_marshal_value_peek_char(v)     (v)->data[0].v_int\n#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint\n#define g_marshal_value_peek_int(v)      (v)->data[0].v_int\n#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint\n#define g_marshal_value_peek_long(v)     (v)->data[0].v_long\n#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong\n#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64\n#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64\n#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long\n#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong\n#define g_marshal_value_peek_float(v)    (v)->data[0].v_float\n#define g_marshal_value_peek_double(v)   (v)->data[0].v_double\n#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer\n#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer\n#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer\n#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer\n#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer\n#endif /* !G_ENABLE_DEBUG */\n\n\n/* VOID:OBJECT,INT (nipmarshal.list:25) */\nvoid\nnip_VOID__OBJECT_INT (GClosure     *closure,\n                      GValue       *return_value G_GNUC_UNUSED,\n                      guint         n_param_values,\n                      const GValue *param_values,\n                      gpointer      invocation_hint G_GNUC_UNUSED,\n                      gpointer      marshal_data)\n{\n  typedef void (*GMarshalFunc_VOID__OBJECT_INT) (gpointer     data1,\n                                                 gpointer     arg_1,\n                                                 gint         arg_2,\n                                                 gpointer     data2);\n  register GMarshalFunc_VOID__OBJECT_INT callback;\n  register GCClosure *cc = (GCClosure*) closure;\n  register gpointer data1, data2;\n\n  g_return_if_fail (n_param_values == 3);\n\n  if (G_CCLOSURE_SWAP_DATA (closure))\n    {\n      data1 = closure->data;\n      data2 = g_value_peek_pointer (param_values + 0);\n    }\n  else\n    {\n      data1 = g_value_peek_pointer (param_values + 0);\n      data2 = closure->data;\n    }\n  callback = (GMarshalFunc_VOID__OBJECT_INT) (marshal_data ? marshal_data : cc->callback);\n\n  callback (data1,\n            g_marshal_value_peek_object (param_values + 1),\n            g_marshal_value_peek_int (param_values + 2),\n            data2);\n}\n\n/* VOID:DOUBLE,DOUBLE (nipmarshal.list:26) */\nvoid\nnip_VOID__DOUBLE_DOUBLE (GClosure     *closure,\n                         GValue       *return_value G_GNUC_UNUSED,\n                         guint         n_param_values,\n                         const GValue *param_values,\n                         gpointer      invocation_hint G_GNUC_UNUSED,\n                         gpointer      marshal_data)\n{\n  typedef void (*GMarshalFunc_VOID__DOUBLE_DOUBLE) (gpointer     data1,\n                                                    gdouble      arg_1,\n                                                    gdouble      arg_2,\n                                                    gpointer     data2);\n  register GMarshalFunc_VOID__DOUBLE_DOUBLE callback;\n  register GCClosure *cc = (GCClosure*) closure;\n  register gpointer data1, data2;\n\n  g_return_if_fail (n_param_values == 3);\n\n  if (G_CCLOSURE_SWAP_DATA (closure))\n    {\n      data1 = closure->data;\n      data2 = g_value_peek_pointer (param_values + 0);\n    }\n  else\n    {\n      data1 = g_value_peek_pointer (param_values + 0);\n      data2 = closure->data;\n    }\n  callback = (GMarshalFunc_VOID__DOUBLE_DOUBLE) (marshal_data ? marshal_data : cc->callback);\n\n  callback (data1,\n            g_marshal_value_peek_double (param_values + 1),\n            g_marshal_value_peek_double (param_values + 2),\n            data2);\n}\n\n/* BOOLEAN:INT,INT (nipmarshal.list:27) */\nvoid\nnip_BOOLEAN__INT_INT (GClosure     *closure,\n                      GValue       *return_value G_GNUC_UNUSED,\n                      guint         n_param_values,\n                      const GValue *param_values,\n                      gpointer      invocation_hint G_GNUC_UNUSED,\n                      gpointer      marshal_data)\n{\n  typedef gboolean (*GMarshalFunc_BOOLEAN__INT_INT) (gpointer     data1,\n                                                     gint         arg_1,\n                                                     gint         arg_2,\n                                                     gpointer     data2);\n  register GMarshalFunc_BOOLEAN__INT_INT callback;\n  register GCClosure *cc = (GCClosure*) closure;\n  register gpointer data1, data2;\n  gboolean v_return;\n\n  g_return_if_fail (return_value != NULL);\n  g_return_if_fail (n_param_values == 3);\n\n  if (G_CCLOSURE_SWAP_DATA (closure))\n    {\n      data1 = closure->data;\n      data2 = g_value_peek_pointer (param_values + 0);\n    }\n  else\n    {\n      data1 = g_value_peek_pointer (param_values + 0);\n      data2 = closure->data;\n    }\n  callback = (GMarshalFunc_BOOLEAN__INT_INT) (marshal_data ? marshal_data : cc->callback);\n\n  v_return = callback (data1,\n                       g_marshal_value_peek_int (param_values + 1),\n                       g_marshal_value_peek_int (param_values + 2),\n                       data2);\n\n  g_value_set_boolean (return_value, v_return);\n}\n\n"
  },
  {
    "path": "src/nipmarshal.h",
    "content": "\n#ifndef __nip_MARSHAL_H__\n#define __nip_MARSHAL_H__\n\n#include\t<glib-object.h>\n\nG_BEGIN_DECLS\n\n/* VOID:OBJECT,INT (nipmarshal.list:25) */\nextern void nip_VOID__OBJECT_INT (GClosure     *closure,\n                                  GValue       *return_value,\n                                  guint         n_param_values,\n                                  const GValue *param_values,\n                                  gpointer      invocation_hint,\n                                  gpointer      marshal_data);\n\n/* VOID:DOUBLE,DOUBLE (nipmarshal.list:26) */\nextern void nip_VOID__DOUBLE_DOUBLE (GClosure     *closure,\n                                     GValue       *return_value,\n                                     guint         n_param_values,\n                                     const GValue *param_values,\n                                     gpointer      invocation_hint,\n                                     gpointer      marshal_data);\n\n/* BOOLEAN:INT,INT (nipmarshal.list:27) */\nextern void nip_BOOLEAN__INT_INT (GClosure     *closure,\n                                  GValue       *return_value,\n                                  guint         n_param_values,\n                                  const GValue *param_values,\n                                  gpointer      invocation_hint,\n                                  gpointer      marshal_data);\n\nG_END_DECLS\n\n#endif /* __nip_MARSHAL_H__ */\n\n"
  },
  {
    "path": "src/nipmarshal.list",
    "content": "# see glib-genmarshal(1) for a detailed description of the file format,\n# possible parameter types are:\n#   VOID        indicates   no   return   type,  or  no  extra\n#               parameters. if VOID is used as  the  parameter\n#               list, no additional parameters may be present.\n#   BOOLEAN     for boolean types (gboolean)\n#   CHAR        for signed char types (gchar)\n#   UCHAR       for unsigned char types (guchar)\n#   INT         for signed integer types (gint)\n#   UINT        for unsigned integer types (guint)\n#   LONG        for signed long integer types (glong)\n#   ULONG       for unsigned long integer types (gulong)\n#   ENUM        for enumeration types (gint)\n#   FLAGS       for flag enumeration types (guint)\n#   FLOAT       for single-precision float types (gfloat)\n#   DOUBLE      for double-precision float types (gdouble)\n#   STRING      for string types (gchar*)\n#   BOXED       for boxed (anonymous but reference counted) types (GBoxed*)\n#   POINTER     for anonymous pointer types (gpointer)\n#   PARAM       for GParamSpec or derived types  (GParamSpec*)\n#   OBJECT      for GObject or derived types (GObject*)\n#   NONE        deprecated alias for VOID\n#   BOOL        deprecated alias for BOOLEAN\n\nVOID: OBJECT, INT\nVOID: DOUBLE, DOUBLE\nBOOLEAN: INT, INT\n\n"
  },
  {
    "path": "src/number.c",
    "content": "/* an editable number\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic View *\nnumber_view_new( Model *model, View *parent )\n{\n\treturn( numberview_new() );\n}\n\n/* Members of number we automate.\n */\nstatic ClassmodelMember number_members[] = {\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_CAPTION, \"caption\", N_( \"Caption\" ),\n\t\tG_STRUCT_OFFSET( iObject, caption ) },\n\t{ CLASSMODEL_MEMBER_DOUBLE, NULL, 0,\n\t\tMEMBER_VALUE, \"value\", N_( \"Value\" ),\n\t\tG_STRUCT_OFFSET( Number, value ) }\n};\n\nstatic void\nnumber_class_init( NumberClass *class )\n{\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Init methods.\n\t */\n\tiobject_class->user_name = _( \"Number\" );\n\n\tmodel_class->view_new = number_view_new;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n\n\tclassmodel_class->members = number_members;\n\tclassmodel_class->n_members = IM_NUMBER( number_members );\n}\n\nstatic void\nnumber_init( Number *number )\n{\n\tnumber->value = 0.0;\n\n\tiobject_set( IOBJECT( number ), CLASS_NUMBER, NULL );\n}\n\nGType\nnumber_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( NumberClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) number_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Number ),\n\t\t\t32,             /* n_pnumberlocs */\n\t\t\t(GInstanceInitFunc) number_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"Number\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/number.h",
    "content": "/* a colour number in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_NUMBER (number_get_type())\n#define NUMBER( obj ) (GTK_CHECK_CAST( (obj), TYPE_NUMBER, Number ))\n#define NUMBER_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_NUMBER, NumberClass ))\n#define IS_NUMBER( obj ) (GTK_CHECK_TYPE( (obj), TYPE_NUMBER ))\n#define IS_NUMBER_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_NUMBER ))\n\nstruct _Number {\n\tClassmodel parent_class;\n\n\t/* Class fields.\n\t */\n\tdouble value;\n};\n\ntypedef struct _NumberClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} NumberClass;\n\nGType number_get_type( void );\n"
  },
  {
    "path": "src/numberview.c",
    "content": "/* a view of a text thingy\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic EditviewClass *parent_class = NULL;\n\n/* Re-read the text in a tally entry. \n */\nstatic void *\nnumberview_scan( View *view )\n{\n\tNumberview *numberview = NUMBERVIEW( view );\n\tNumber *number = NUMBER( VOBJECT( numberview )->iobject );\n    \tExpr *expr = HEAPMODEL( number )->row->expr;\n\tdouble value;\n\n#ifdef DEBUG\n\tRow *row = HEAPMODEL( number )->row;\n\n\tprintf( \"numberview_scan: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\texpr_error_clear( expr );\n\n\tif( !get_geditable_double( EDITVIEW( numberview )->text, &value ) ) {\n\t\texpr_error_set( expr );\n\t\treturn( view );\n\t}\n\n\tif( number->value != value ) {\n\t\tnumber->value = value;\n\t\tclassmodel_update( CLASSMODEL( number ) ) ;\n\t}\n\n\treturn( VIEW_CLASS( parent_class )->scan( view ) );\n}\n\nstatic void \nnumberview_refresh( vObject *vobject )\n{\n\tNumberview *numberview = NUMBERVIEW( vobject );\n\tNumber *number = NUMBER( VOBJECT( numberview )->iobject );\n\n#ifdef DEBUG\n\tRow *row = HEAPMODEL( number )->row;\n\n\tprintf( \"numberview_refresh: \" );\n\trow_name_print( row );\n\tprintf( \" (%p)\\n\", vobject );\n#endif /*DEBUG*/\n\n\teditview_set_entry( EDITVIEW( numberview ), \n\t\t\"%g\", number->value );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\nnumberview_class_init( NumberviewClass *class )\n{\n\tViewClass *view_class = (ViewClass *) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = numberview_refresh;\n\n\tview_class->scan = numberview_scan;\n}\n\nstatic void\nnumberview_init( Numberview *numberview )\n{\n}\n\nGtkType\nnumberview_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Numberview\",\n\t\t\tsizeof( Numberview ),\n\t\t\tsizeof( NumberviewClass ),\n\t\t\t(GtkClassInitFunc) numberview_class_init,\n\t\t\t(GtkObjectInitFunc) numberview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_EDITVIEW, &info );\n\t}\n\n\treturn( type );\n}\n\nView *\nnumberview_new( void )\n{\n\tNumberview *numberview = gtk_type_new( TYPE_NUMBERVIEW );\n\n\treturn( VIEW( numberview ) );\n}\n"
  },
  {
    "path": "src/numberview.h",
    "content": "/* edit a number\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_NUMBERVIEW (numberview_get_type())\n#define NUMBERVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_NUMBERVIEW, Numberview ))\n#define NUMBERVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_NUMBERVIEW, NumberviewClass ))\n#define IS_NUMBERVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_NUMBERVIEW ))\n#define IS_NUMBERVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_NUMBERVIEW ))\n\ntypedef struct _Numberview {\n\tEditview parent_object;\n\n} Numberview;\n\ntypedef struct _NumberviewClass {\n\tEditviewClass parent_class;\n\n\t/* My methods.\n\t */\n} NumberviewClass;\n\nGtkType numberview_get_type( void );\nView *numberview_new( void );\n"
  },
  {
    "path": "src/option.c",
    "content": "/* an input option ... put/get methods\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic void\noption_finalize( GObject *gobject )\n{\n\tOption *option;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_OPTION( gobject ) );\n\n\toption = OPTION( gobject );\n\n\t/* My instance finalize stuff.\n\t */\n\tIM_FREEF( slist_free_all, option->labels );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic View *\noption_view_new( Model *model, View *parent )\n{\n\treturn( optionview_new() );\n}\n\n/* Members of option we automate.\n */\nstatic ClassmodelMember option_members[] = {\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_CAPTION, \"caption\", N_( \"Caption\" ),\n\t\tG_STRUCT_OFFSET( iObject, caption ) },\n\t{ CLASSMODEL_MEMBER_STRING_LIST, NULL, 0,\n\t\tMEMBER_LABELS, \"labels\", N_( \"Labels\" ),\n\t\tG_STRUCT_OFFSET( Option, labels ) },\n\t{ CLASSMODEL_MEMBER_INT, NULL, 0,\n\t\tMEMBER_VALUE, \"value\", N_( \"Value\" ),\n\t\tG_STRUCT_OFFSET( Option, value ) }\n};\n\nstatic void\noption_class_init( OptionClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->finalize = option_finalize;\n\n\tmodel_class->view_new = option_view_new;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n\n\tclassmodel_class->members = option_members;\n\tclassmodel_class->n_members = IM_NUMBER( option_members );\n}\n\nstatic void\noption_init( Option *option )\n{\n        option->labels = NULL;\n\toption->value = 0;\n\n\tiobject_set( IOBJECT( option ), CLASS_OPTION, NULL );\n}\n\nGType\noption_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( OptionClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) option_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Option ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) option_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"Option\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/option.h",
    "content": "/* a option in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_OPTION (option_get_type())\n#define OPTION( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_OPTION, Option ))\n#define OPTION_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_OPTION, OptionClass))\n#define IS_OPTION( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_OPTION ))\n#define IS_OPTION_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_OPTION ))\n#define OPTION_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_OPTION, OptionClass ))\n\ntypedef struct _Option {\n\tClassmodel parent_class;\n\n\t/* Base class fields.\n\t */\n\tGSList *labels;\t\t/* [[char]] for option fields */\n\tint value;\t\t/* Index of current option */\n} Option;\n\ntypedef struct _OptionClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} OptionClass;\n\nGType option_get_type( void );\n"
  },
  {
    "path": "src/optionview.c",
    "content": "/* run the display for a option in a workspace \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GraphicviewClass *parent_class = NULL;\n\n/* Copy a gslist of strings.\n */\nstatic GSList *\nlstring_copy( GSList *lstring )\n{\n\tGSList *new;\n\tGSList *p;\n\n\tnew = NULL;\n\tfor( p = lstring; p; p = p->next )\n\t\tnew = g_slist_prepend( new, \n\t\t\tg_strdup( (const char *) p->data ) );\n\n\tnew = g_slist_reverse( new );\n\n\treturn( new );\n}\n\n/* Are two lstrings equal?\n */\nstatic gboolean\nlstring_equal( GSList *a, GSList *b )\n{\n\tfor( ; a && b; a = a->next, b = b->next )\n\t\tif( strcmp( (const char *) a->data, \n\t\t\t(const char *) b->data ) != 0 )\n\t\t\treturn( FALSE );\n\n\tif( a || b )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic void\noptionview_destroy( GtkObject *object )\n{\n\tOptionview *optionview;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_OPTIONVIEW( object ) );\n\n\toptionview = OPTIONVIEW( object );\n\n\t/* My instance destroy stuff.\n\t */\n\tIM_FREEF( slist_free_all, optionview->labels );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\noptionview_link( View *view, Model *model, View *parent )\n{\n\tOptionview *optionview = OPTIONVIEW( view );\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\tif( GRAPHICVIEW( view )->sview )\n\t\tgtk_size_group_add_widget( GRAPHICVIEW( view )->sview->group,   \n\t\t\toptionview->label );\n}\n\n/* Change to a optionview widget ... update the model. \n */\nstatic void\noptionview_change_cb( GtkWidget *wid, Optionview *optionview )\n{\n\tOption *option = OPTION( VOBJECT( optionview )->iobject );\n\tClassmodel *classmodel = CLASSMODEL( option );\n\n\tconst int nvalue = gtk_combo_box_get_active( \n\t\tGTK_COMBO_BOX( optionview->options ) );\n\n\tif( option->value != nvalue ) {\n\t\toption->value = nvalue;\n\n\t\tclassmodel_update( classmodel );\n\t\tsymbol_recalculate_all();\n\t}\n}\n\nstatic gboolean\noptionview_scroll_cb( GtkWidget *wid, GdkEvent *event, Optionview *optionview )\n{\n\t/* Stop any other scroll handlers running. We don't want the scroll \n\t * wheel to change widgets while we're moving.\n\t */\n\treturn( TRUE ); \n}\n\nstatic void \noptionview_refresh( vObject *vobject )\n{\n\tOptionview *optionview = OPTIONVIEW( vobject );\n\tOption *option = OPTION( VOBJECT( optionview )->iobject );\n\n\tGSList *p;\n\tint i;\n\n#ifdef DEBUG\n\tprintf( \"optionview_refresh: \" );\n\trow_name_print( HEAPMODEL( option )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Only rebuild the menu if there's been a change.\n\t */\n\tif( !lstring_equal( optionview->labels, option->labels ) ) {\n\t\t/* If the menu is currently up, we can get strange things \n\t\t * happening if we destroy it.\n\t\t */\n\t\tif( optionview->options )\n\t\t\tgtk_combo_box_popdown( \n\t\t\t\tGTK_COMBO_BOX( optionview->options ) );\n\t\tIM_FREEF( gtk_widget_destroy, optionview->options );\n\n\t\toptionview->options = gtk_combo_box_new_text();\n\t\tfor( p = option->labels, i = 0; p; p = p->next, i++ ) \n\t\t\tgtk_combo_box_append_text( \n\t\t\t\tGTK_COMBO_BOX( optionview->options ),\n\t\t\t\t(const char *) p->data );\n\t\tgtk_box_pack_start( GTK_BOX( optionview->hbox ), \n\t\t\toptionview->options, TRUE, TRUE, 0 );\n\n\t\tgtk_signal_connect( GTK_OBJECT( optionview->options ), \n\t\t\t\"changed\", \n\t\t\tGTK_SIGNAL_FUNC( optionview_change_cb ), optionview );\n\t\tgtk_widget_show( optionview->options );\n\n\t\tIM_FREEF( slist_free_all, optionview->labels );\n\t\toptionview->labels = lstring_copy( option->labels );\n\n\t\tg_signal_connect( GTK_OBJECT( optionview->options ),\n\t\t\t\"scroll-event\", \n\t\t\tGTK_SIGNAL_FUNC( optionview_scroll_cb ), optionview );\n\t}\n\n\tif( optionview->options ) {\n\t\tgtk_signal_handler_block_by_data( \n\t\t\tGTK_OBJECT( optionview->options ), optionview );\n\t\tgtk_combo_box_set_active( GTK_COMBO_BOX( optionview->options ), \n\t\t\toption->value );\n\t\tgtk_signal_handler_unblock_by_data( \n\t\t\tGTK_OBJECT( optionview->options ), optionview );\n\t}\n\n\tset_glabel( optionview->label, _( \"%s:\" ), IOBJECT( option )->caption );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\noptionview_class_init( OptionviewClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = optionview_destroy;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = optionview_refresh;\n\n\tview_class->link = optionview_link;\n}\n\nstatic void\noptionview_init( Optionview *optionview )\n{\n        optionview->hbox = gtk_hbox_new( FALSE, 12 );\n        gtk_box_pack_start( GTK_BOX( optionview ), \n\t\toptionview->hbox, TRUE, FALSE, 0 );\n\n        optionview->label = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( optionview->label ), 0, 0.5 );\n\tgtk_box_pack_start( GTK_BOX( optionview->hbox ), \n\t\toptionview->label, FALSE, FALSE, 2 );\n\n\toptionview->options = NULL;\n\n\toptionview->labels = NULL;\n\n        gtk_widget_show_all( optionview->hbox );\n}\n\nGtkType\noptionview_get_type( void )\n{\n\tstatic GtkType optionview_type = 0;\n\n\tif( !optionview_type ) {\n\t\tstatic const GtkTypeInfo sinfo = {\n\t\t\t\"Optionview\",\n\t\t\tsizeof( Optionview ),\n\t\t\tsizeof( OptionviewClass ),\n\t\t\t(GtkClassInitFunc) optionview_class_init,\n\t\t\t(GtkObjectInitFunc) optionview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\toptionview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &sinfo );\n\t}\n\n\treturn( optionview_type );\n}\n\nView *\noptionview_new( void )\n{\n\tOptionview *optionview = gtk_type_new( TYPE_OPTIONVIEW );\n\n\treturn( VIEW( optionview ) );\n}\n"
  },
  {
    "path": "src/optionview.h",
    "content": "/* a optionview in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_OPTIONVIEW (optionview_get_type())\n#define OPTIONVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_OPTIONVIEW, Optionview ))\n#define OPTIONVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_OPTIONVIEW, OptionviewClass ))\n#define IS_OPTIONVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_OPTIONVIEW ))\n#define IS_OPTIONVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_OPTIONVIEW ))\n\ntypedef struct _Optionview {\n\tGraphicview parent_object;\n\n\tGtkWidget *label;\n\tGtkWidget *hbox;\n\tGtkWidget *options;\n\n\t/* The [[char]] we set on the previous refresh. Use this to avoid\n\t * rebuilding the optionmenu unless we have to.\n\t */\n\tGSList *labels;\n} Optionview;\n\ntypedef struct _OptionviewClass {\n\tGraphicviewClass parent_class;\n\n\t/* My methods.\n\t */\n} OptionviewClass;\n\nGtkType optionview_get_type( void );\nView *optionview_new( void );\n"
  },
  {
    "path": "src/paintboxview.c",
    "content": "/* widgets for the paintbox bar\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GtkFrameClass *parent_class = NULL;\n\n/* The popup menu.\n */\nstatic GtkWidget *paintboxview_menu = NULL;\n\nstatic void\npaintboxview_destroy( GtkObject *object )\n{\n\tPaintboxview *pbv;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_PAINTBOXVIEW( object ) );\n\n\tpbv = PAINTBOXVIEW( object );\n\n#ifdef DEBUG\n\tprintf( \"paintboxview_destroy: %p\\n\", pbv );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\tFREESID( pbv->ii_undo_changed_sid, pbv->ii );\n\tFREESID( pbv->ii_destroy_sid, pbv->ii );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\npaintboxview_realize( GtkWidget *widget )\n{\n\tPaintboxview *pbv = PAINTBOXVIEW( widget );\n\tiWindow *iwnd = IWINDOW( iwindow_get_root( widget ) );\n\tguint key;\n\tGdkModifierType mods;\n\n\tgtk_accelerator_parse( \"<ctrl>z\", &key, &mods );\n\tgtk_widget_add_accelerator( GTK_WIDGET( pbv->undo ), \"clicked\",\n\t\tiwnd->accel_group, key, mods, 0 );\n\tgtk_accelerator_parse( \"<shift><ctrl>z\", &key, &mods );\n\tgtk_widget_add_accelerator( GTK_WIDGET( pbv->redo ), \"clicked\",\n\t\tiwnd->accel_group, key, mods, 0 );\n\n\tGTK_WIDGET_CLASS( parent_class )->realize( widget );\n}\n\n/* Hide this paintboxview.\n */\nstatic void\npaintboxview_hide_cb( GtkWidget *menu, GtkWidget *host, Paintboxview *pbv )\n{\n\timagemodel_set_paintbox( pbv->imagemodel, FALSE );\n}\n\nstatic void\npaintboxview_class_init( PaintboxviewClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tGtkWidgetClass *widget_class = (GtkWidgetClass *) class;\n\n\tGtkWidget *pane;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = paintboxview_destroy;\n\twidget_class->realize = paintboxview_realize;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\n\tpane = paintboxview_menu = popup_build( _( \"Paintbox bar menu\" ) );\n\tpopup_add_but( pane, GTK_STOCK_CLOSE,\n\t\tPOPUP_FUNC( paintboxview_hide_cb ) );\n}\n\n/* \"toggled\" on a tool select button\n */\nstatic void\npaintboxview_tool_toggled_cb( GtkWidget *wid, Paintboxview *pbv )\n{\n\tif( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( wid ) ) ) {\n\t\tImagemodel *imagemodel = pbv->imagemodel;\n\t\tint i;\n\n\t\tfor( i = 0; i < IMAGEMODEL_LAST; i++ )\n\t\t\tif( wid == pbv->tool[i] )\n\t\t\t\tbreak;\n\n\t\tif( i != (int) IMAGEMODEL_LAST ) \n\t\t\timagemodel_set_state( imagemodel, i, wid );\n\t}\n}\n\n/* New nib selected.\n */\nstatic void\npaintboxview_scale_change_cb( Tslider *tslider, Paintboxview *pbv )\n{\n\tImagemodel *imagemodel = pbv->imagemodel;\n\n\tif( imagemodel->nib_radius != tslider->value ) {\n\t\timagemodel->nib_radius = tslider->value; \n\t\tiobject_changed( IOBJECT( imagemodel ) );\n\t}\n}\n\nstatic void\npaintboxview_double_cb( GtkWidget *wid, GdkEvent *event, \n\tPaintboxview *pbv )\n{\n\timageinfo_colour_edit( wid, IMAGEDISPLAY( pbv->ink )->conv->ii );\n}\n\nstatic void\npaintboxview_font_changed_cb( GtkWidget *widget, Paintboxview *pbv )\n{\n\tFontbutton *fontbutton = FONTBUTTON( widget );\n\tImagemodel *imagemodel = pbv->imagemodel;\n\tconst char *font_name;\n\n\tfont_name = fontbutton_get_font_name( fontbutton ); \n\tif( strcmp( font_name, imagemodel->font_name ) != 0 ) {\n\t\tIM_SETSTR( imagemodel->font_name, font_name );\n\t\tiobject_changed( IOBJECT( imagemodel ) );\n\t}\n}\n\nstatic void\npaintboxview_undo_cb( GtkWidget *widget, Paintboxview *pbv )\n{\n\tif( !imageinfo_undo( pbv->ii ) )\n\t\tiwindow_alert( widget, GTK_MESSAGE_ERROR );\n\n\t/* Ask everyone to drop cache, the image has changed.\n\t */\n\tim_invalidate( imageinfo_get( FALSE, pbv->ii ) );\n\n\timagemodel_paint_recalc( pbv->imagemodel );\n}\n\nstatic void\npaintboxview_redo_cb( GtkWidget *widget, Paintboxview *pbv )\n{\n\tif( !imageinfo_redo( pbv->ii ) )\n\t\tiwindow_alert( widget, GTK_MESSAGE_ERROR );\n\n\t/* Ask everyone to drop cache, the image has changed.\n\t */\n\tim_invalidate( imageinfo_get( FALSE, pbv->ii ) );\n\n\timagemodel_paint_recalc( pbv->imagemodel );\n}\n\nstatic void\npaintboxview_clear_cb2( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tPaintboxview *pbv = PAINTBOXVIEW( client );\n\n\timageinfo_undo_clear( pbv->ii );\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\npaintboxview_clear_cb( GtkWidget *widget, Paintboxview *pbv )\n{\n\tbox_yesno( GTK_WIDGET( widget ),\n\t\tpaintboxview_clear_cb2, iwindow_true_cb, pbv,\n\t\tiwindow_notify_null, NULL,\n\t\tGTK_STOCK_CLEAR,\n\t\t_( \"Clear undo history?\" ), \n\t\t_( \"Are you sure you want to clear all undo and redo? \"\n\t\t\"This will free up memory, but you will no longer be \"\n\t\t\"able to undo or redo any of the painting you have \"\n\t\t\"done so far.\" ) );\n}\n\nstatic void\npaintboxview_text_changed_cb( GtkWidget *widget, Paintboxview *pbv )\n{\n\tconst char *text = gtk_entry_get_text( GTK_ENTRY( pbv->text ) );\n\n\tIM_SETSTR( pbv->imagemodel->text, text );\n}\n\nstatic void\npaintboxview_init( Paintboxview *pbv )\n{\n\t/* Order important! Keep in sync with ImagemodelState.\n\t */\n\tstatic const char *tool_names[IMAGEMODEL_LAST] = {\n\t\tSTOCK_SELECT, \t\t/* IMAGEMODEL_SELECT */\n\t\tSTOCK_MOVE, \t\t/* IMAGEMODEL_PAN */\n\t\tGTK_STOCK_ZOOM_IN, \t/* IMAGEMODEL_MAGIN */\n\t\tGTK_STOCK_ZOOM_OUT,\t/* IMAGEMODEL_MAGOUT*/\n\t\tSTOCK_DROPPER,\t\t/* IMAGEMODEL_DROPPER */\n\t\tSTOCK_PAINTBRUSH,\t/* IMAGEMODEL_PEN */\n\t\tSTOCK_LINE,\t\t/* IMAGEMODEL_LINE */\n\t\tSTOCK_RECT,\t\t/* IMAGEMODEL_RECT */\n\t\tSTOCK_FLOOD,\t\t/* IMAGEMODEL_FLOOD */\n\t\tSTOCK_FLOOD_BLOB,\t/* IMAGEMODEL_BLOB */\n\t\tSTOCK_TEXT,\t\t/* IMAGEMODEL_TEXT */\n\t\tSTOCK_SMUDGE \t\t/* IMAGEMODEL_SMUDGE */\n\t};\n\n\tstatic const char *tool_tooltips[] = {\n\t\tN_( \"Manipulate regions\" ), \t\t/* IMAGEMODEL_SELECT */\n\t\tN_( \"Pan window\" ),\t \t\t/* IMAGEMODEL_PAN */\n\t\tN_( \"Zoom in on mouse\" ), \t\t/* IMAGEMODEL_MAGIN */\n\t\tN_( \"Zoom out\" ),\t\t\t/* IMAGEMODEL_MAGOUT*/\n\t\tN_( \"Read pixel into inkwell\" ),\t/* IMAGEMODEL_DROPPER */\n\t\tN_( \"Freehand draw \" ),\t\t\t/* IMAGEMODEL_PEN */\n\t\tN_( \"Draw straight lines\" ),\t\t/* IMAGEMODEL_LINE */\n\t\tN_( \"Fill rectangles\" ),\t\t/* IMAGEMODEL_RECT */\n\t\tN_( \"Flood while pixel not equal to ink\" ),\t\t\n\t\t\t\t\t\t\t/* IMAGEMODEL_FLOOD */\n\t\tN_( \"Flood while pixel equal to click\" ),\n\t\t\t\t\t\t\t/* IMAGEMODEL_BLOB */\n\t\tN_( \"Draw text\" ),\t\t\t/* IMAGEMODEL_TEXT */\n\t\tN_( \"Smudge\" ) \t\t\t\t/* IMAGEMODEL_SMUDGE */\n\t};\n\n\tGtkWidget *eb;\n\tGtkWidget *hb, *hb2;\n\tGtkWidget *image;\n\tint i;\n\n\tpbv->imagemodel = NULL;\n\tpbv->ii_undo_changed_sid = 0;\n\tpbv->ii_destroy_sid = 0;\n\tpbv->ii = NULL;\n\n        gtk_frame_set_shadow_type( GTK_FRAME( pbv ), GTK_SHADOW_OUT );\n\n\teb = gtk_event_box_new();\n        gtk_container_add( GTK_CONTAINER( pbv ), eb );\n        popup_attach( eb, paintboxview_menu, pbv );\n\n\thb = gtk_hbox_new( FALSE, 4 );\n        gtk_container_set_border_width( GTK_CONTAINER( hb ), 1 );\n        gtk_container_add( GTK_CONTAINER( eb ), hb );\n\n\t/* The first 4 tools are harmless (region, move, zoom in, zoom out)\n\t * and not linked to the paint actions .. so have them first on their\n\t * own.\n\t */\n\thb2 = gtk_hbox_new( FALSE, 0 );\n\tfor( i = 0; i < 4; i++ ) {\n\t\tpbv->tool[i] = gtk_toggle_button_new();\n\t\tgtk_signal_connect( GTK_OBJECT( pbv->tool[i] ), \"toggled\", \n\t\t\tGTK_SIGNAL_FUNC( paintboxview_tool_toggled_cb ), pbv );\n\t\timage = gtk_image_new_from_stock( tool_names[i],\n\t\t\tGTK_ICON_SIZE_BUTTON );\n\t\tset_tooltip( pbv->tool[i], \"%s\", tool_tooltips[i] );\n\t\tgtk_container_add( GTK_CONTAINER( pbv->tool[i] ), image );\n\n\t\tgtk_box_pack_start( GTK_BOX( hb2 ), \n\t\t\tpbv->tool[i], FALSE, FALSE, 0 );\n\t}\n\tgtk_box_pack_start( GTK_BOX( hb ), hb2, FALSE, FALSE, 0 );\n\n\thb2 = gtk_hbox_new( FALSE, 0 );\n\n\tpbv->undo = gtk_button_new();\n\timage = gtk_image_new_from_stock( GTK_STOCK_UNDO, \n\t\tGTK_ICON_SIZE_BUTTON );\n\tgtk_container_add( GTK_CONTAINER( pbv->undo ), image );\n\tgtk_signal_connect( GTK_OBJECT( pbv->undo ), \"clicked\", \n\t\tGTK_SIGNAL_FUNC( paintboxview_undo_cb ), pbv );\n\tset_tooltip( pbv->undo, _( \"Undo last paint action\" ) );\n        gtk_box_pack_start( GTK_BOX( hb2 ), pbv->undo, FALSE, FALSE, 0 );\n\n\tpbv->redo = gtk_button_new();\n\timage = gtk_image_new_from_stock( GTK_STOCK_REDO, \n\t\tGTK_ICON_SIZE_BUTTON );\n\tgtk_container_add( GTK_CONTAINER( pbv->redo ), image );\n\tgtk_signal_connect( GTK_OBJECT( pbv->redo ), \"clicked\", \n\t\tGTK_SIGNAL_FUNC( paintboxview_redo_cb ), pbv );\n\tset_tooltip( pbv->redo, _( \"Redo last paint action\" ) );\n        gtk_box_pack_start( GTK_BOX( hb2 ), pbv->redo, FALSE, FALSE, 0 );\n\n\tpbv->clear = gtk_button_new();\n\timage = gtk_image_new_from_stock( GTK_STOCK_CLEAR, \n\t\tGTK_ICON_SIZE_BUTTON );\n\tgtk_container_add( GTK_CONTAINER( pbv->clear ), image );\n\tgtk_signal_connect( GTK_OBJECT( pbv->clear ), \"clicked\", \n\t\tGTK_SIGNAL_FUNC( paintboxview_clear_cb ), pbv );\n\tset_tooltip( pbv->clear, _( \"Clear all undo and redo buffers\" ) );\n        gtk_box_pack_start( GTK_BOX( hb2 ), pbv->clear, FALSE, FALSE, 0 );\n\n\tgtk_box_pack_start( GTK_BOX( hb ), hb2, FALSE, FALSE, 0 );\n\n\thb2 = gtk_hbox_new( FALSE, 0 );\n\tfor( i = 4; i < IM_NUMBER( tool_names ); i++ ) {\n\t\tpbv->tool[i] = gtk_toggle_button_new();\n\t\tgtk_signal_connect( GTK_OBJECT( pbv->tool[i] ), \"toggled\", \n\t\t\tGTK_SIGNAL_FUNC( paintboxview_tool_toggled_cb ), pbv );\n\t\timage = gtk_image_new_from_stock( tool_names[i],\n\t\t\tGTK_ICON_SIZE_BUTTON );\n\t\tset_tooltip( pbv->tool[i], \"%s\", tool_tooltips[i] );\n\t\tgtk_container_add( GTK_CONTAINER( pbv->tool[i] ), image );\n\n\t\tgtk_box_pack_start( GTK_BOX( hb2 ), \n\t\t\tpbv->tool[i], FALSE, FALSE, 0 );\n\t}\n\tgtk_box_pack_start( GTK_BOX( hb ), hb2, FALSE, FALSE, 0 );\n\n\tpbv->nib = tslider_new();\n\tpbv->nib->from = 0;\n\tpbv->nib->to = 64;\n\tpbv->nib->value = 0;\n\tpbv->nib->svalue = 1;\n\tpbv->nib->digits = 2;\n\ttslider_changed( pbv->nib );\n        gtk_box_pack_start( GTK_BOX( hb ), \n\t\tGTK_WIDGET( pbv->nib ), FALSE, TRUE, 0 );\n        gtk_signal_connect( GTK_OBJECT( pbv->nib ), \"changed\", \n\t\tGTK_SIGNAL_FUNC( paintboxview_scale_change_cb ), pbv );\n\ttslider_set_ignore_scroll( pbv->nib, FALSE );\n\n\tpbv->ink = (GtkWidget *) colourdisplay_new( NULL );\n        doubleclick_add( GTK_WIDGET( pbv->ink ), FALSE,\n                NULL, NULL, \n\t\tDOUBLECLICK_FUNC( paintboxview_double_cb ), pbv );\n\tgtk_widget_set_size_request( GTK_WIDGET( pbv->ink ), \n\t\t20, 10 );\n        gtk_box_pack_start( GTK_BOX( hb ), pbv->ink, FALSE, TRUE, 0 );\n\n\tpbv->font = GTK_WIDGET( fontbutton_new() );\n        gtk_box_pack_start( GTK_BOX( hb ), pbv->font, FALSE, TRUE, 0 );\n\tgtk_signal_connect( GTK_OBJECT( pbv->font ), \"changed\", \n\t\tGTK_SIGNAL_FUNC( paintboxview_font_changed_cb ), pbv );\n\n\tpbv->text = gtk_entry_new();\n        gtk_box_pack_start( GTK_BOX( hb ), pbv->text, TRUE, TRUE, 0 );\n\tgtk_signal_connect( GTK_OBJECT( pbv->text ), \"changed\", \n\t\tGTK_SIGNAL_FUNC( paintboxview_text_changed_cb ), pbv );\n\tset_tooltip( pbv->text, _( \"Enter text for text tool\" ) );\n\n\tgtk_widget_show_all( eb );\n}\n\nGtkType\npaintboxview_get_type( void )\n{\n\tstatic GtkType paintboxview_type = 0;\n\n\tif( !paintboxview_type ) {\n\t\tstatic const GtkTypeInfo sinfo = {\n\t\t\t\"Paintboxview\",\n\t\t\tsizeof( Paintboxview ),\n\t\t\tsizeof( PaintboxviewClass ),\n\t\t\t(GtkClassInitFunc) paintboxview_class_init,\n\t\t\t(GtkObjectInitFunc) paintboxview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tpaintboxview_type = \n\t\t\tgtk_type_unique( GTK_TYPE_FRAME, &sinfo );\n\t}\n\n\treturn( paintboxview_type );\n}\n\nstatic void\npaintboxview_ii_undo_changed_cb( Imageinfo *imageinfo, Paintboxview *pbv )\n{\n\tgtk_widget_set_sensitive( GTK_WIDGET( pbv->undo ), \n\t\timageinfo->undo != NULL );\n\tgtk_widget_set_sensitive( GTK_WIDGET( pbv->redo ), \n\t\timageinfo->redo != NULL );\n\tgtk_widget_set_sensitive( GTK_WIDGET( pbv->clear ), \n\t\timageinfo->undo != NULL || imageinfo->redo != NULL );\n}\n\nstatic void\npaintboxview_ii_destroy_cb( Imageinfo *imageinfo, Paintboxview *pbv )\n{\n\tpbv->ii_destroy_sid = 0;\n\tpbv->ii_undo_changed_sid = 0;\n\tpbv->ii = NULL;\n}\n\n/* Our model has changed ... update.\n */\nstatic void\npaintboxview_changed_cb( Imagemodel *imagemodel, Paintboxview *pbv )\n{\n\tConversion *conv = imagemodel->conv;\n\tColourdisplay *ink = COLOURDISPLAY( pbv->ink );\n\tint i;\n\n#ifdef DEBUG\n\tprintf( \"paintboxview_conv_changed_cb: %p\\n\", conv );\n#endif /*DEBUG*/\n\n\t/* Has the ii changed? Link to it for undo/redo changes.\n\t */\n\tif( pbv->ii != conv->ii ) {\n\t\tFREESID( pbv->ii_undo_changed_sid, pbv->ii );\n\t\tFREESID( pbv->ii_destroy_sid, pbv->ii );\n\n\t\tpbv->ii = conv->ii;\n\n\t\tif( conv->ii ) {\n\t\t\tpbv->ii_undo_changed_sid = g_signal_connect( \n\t\t\t\tG_OBJECT( conv->ii ), \"undo_changed\", \n\t\t\t\tG_CALLBACK( paintboxview_ii_undo_changed_cb ), \n\t\t\t\tpbv );\n\t\t\tpbv->ii_destroy_sid = g_signal_connect( \n\t\t\t\tG_OBJECT( conv->ii ), \"destroy\", \n\t\t\t\tG_CALLBACK( paintboxview_ii_destroy_cb ), \n\t\t\t\tpbv );\n\t\t\tpaintboxview_ii_undo_changed_cb( conv->ii, pbv );\n\t\t}\n\n\t\t/* Update ink display for the new image.\n\t\t */\n\t\tconversion_set_image( IMAGEDISPLAY( ink )->conv, \n\t\t\timagemodel->ink );\n\t}\n\n\twidget_visible( GTK_WIDGET( pbv ), imagemodel->show_paintbox );\n\tif( !imagemodel->show_paintbox )\n\t\treturn;\n\n\tfor( i = 0; i < IMAGEMODEL_LAST; i++ ) \n\t\tgtk_toggle_button_set_active( \n\t\t\tGTK_TOGGLE_BUTTON( pbv->tool[i] ), \n\t\t\ti == (int) imagemodel->state );\n\n\tfontbutton_set_font_name( FONTBUTTON( pbv->font ),\n\t\tpbv->imagemodel->font_name );\n}\n\nstatic void\npaintboxview_link( Paintboxview *pbv, Imagemodel *imagemodel )\n{\n#ifdef DEBUG\n\tprintf( \"paintboxview_link: %p\\n\", pbv );\n#endif /*DEBUG*/\n\n\tpbv->imagemodel = imagemodel;\n\tg_signal_connect( G_OBJECT( imagemodel ), \"changed\", \n\t\tG_CALLBACK( paintboxview_changed_cb ), pbv );\n}\n\nPaintboxview *\npaintboxview_new( Imagemodel *imagemodel )\n{\n\tPaintboxview *pbv = gtk_type_new( TYPE_PAINTBOXVIEW );\n\n\tpaintboxview_link( pbv, imagemodel );\n\n\treturn( pbv );\n}\n\n"
  },
  {
    "path": "src/paintboxview.h",
    "content": "/* Decls for paintboxview.c ... widgets in the paint bar\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\nextern iWindowShape paintboxview_shape[];\n\n#define TYPE_PAINTBOXVIEW (paintboxview_get_type())\n#define PAINTBOXVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_PAINTBOXVIEW, Paintboxview ))\n#define PAINTBOXVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_PAINTBOXVIEW, PaintboxviewClass ))\n#define IS_PAINTBOXVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PAINTBOXVIEW ))\n#define IS_PAINTBOXVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PAINTBOXVIEW ))\n\nstruct _Paintboxview {\n\tGtkFrame parent_class;\n\n\tImagemodel *imagemodel;\n\n\t/* Spot undo/redo changes on imagemodel->conv->ii.\n\t */\n\tImageinfo *ii;\n\tguint ii_undo_changed_sid;\n\tguint ii_destroy_sid;\n\n\tGtkWidget *undo;\n\tGtkWidget *redo;\n\tGtkWidget *clear;\n\tGtkWidget *tool[IMAGEMODEL_LAST];\n\tTslider *nib;\n\tGtkWidget *ink;\n\tGtkWidget *font;\n\tGtkWidget *text;\n};\n\ntypedef struct _PaintboxviewClass {\n\tGtkFrameClass parent_class;\n\n\t/* My methods.\n\t */\n} PaintboxviewClass;\n\nGtkType paintboxview_get_type( void );\nPaintboxview *paintboxview_new( Imagemodel *imagemodel );\n"
  },
  {
    "path": "src/pane.c",
    "content": "/* a side panel that can slide in and out of view\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* \n#define DEBUG\n */\n\n/* Our signals. \n */\nenum {\n\tSIG_CHANGED,\t/* Change to position or openness */\n\tSIG_LAST\n};\n\nstatic GtkHPanedClass *parent_class = NULL;\n\nstatic guint pane_signals[SIG_LAST] = { 0 };\n\n#ifdef DEBUG\nstatic char *\npane_handedness2char( PaneHandedness handedness )\n{\n\tswitch( handedness ) {\n\tcase PANE_HIDE_LEFT:\treturn( \"PANE_HIDE_LEFT\" );\n\tcase PANE_HIDE_RIGHT:\treturn( \"PANE_HIDE_RIGHT\" );\n\tdefault:\t\tg_assert( 0 );\n\t}\n}\n#endif /*DEBUG*/\n\nstatic void\npane_changed( Pane *pane )\n{\n\tg_assert( IS_PANE( pane ) );\n\n#ifdef DEBUG\n\tprintf( \"pane_changed: %p %s\\n\", \n\t\tpane, pane_handedness2char( pane->handedness ) );\n#endif /*DEBUG*/\n\n\tg_signal_emit( G_OBJECT( pane ), pane_signals[SIG_CHANGED], 0 );\n}\n\nstatic int\npane_closed_position( Pane *pane )\n{\n\t/* Can't use max/min since we need to be able to work before our\n\t * window has been built.\n\t */\n\treturn( pane->handedness == PANE_HIDE_RIGHT ? 10000 : 0 ); \n}\n\n/* An open position ... used in case we are asked to open, but the position is\n * already closed.\n */\nstatic int\npane_open_position( Pane *pane )\n{\n\tint max_position;\n\tint min_position;\n\n\tg_object_get( pane, \n\t\t\"max_position\", &max_position, \n\t\t\"min_position\", &min_position, \n\t\tNULL );\n\n\treturn( pane->handedness == PANE_HIDE_RIGHT ? \n\t\tmax_position - 200: min_position + 200 ); \n}\n\nstatic void\npane_destroy( GtkObject *object )\n{\n\tPane *pane;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_PANE( object ) );\n\n\tpane = PANE( object );\n\n#ifdef DEBUG\n\tprintf( \"pane_destroy: %p %s\\n\",\n\t\tpane, pane_handedness2char( pane->handedness ) );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\tIM_FREEF( g_source_remove, pane->animate_timeout );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\npane_class_init( PaneClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = pane_destroy;\n\n\tclass->changed = NULL;\n\n\tpane_signals[SIG_CHANGED] = g_signal_new( \"changed\",\n\t\tG_OBJECT_CLASS_TYPE( object_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( PaneClass, changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n}\n\n/* Position property has changed. We block the notify signal before we set\n * position, so this change must have come from a user drag or parent window\n * resize.\n */\nstatic void\npane_notify_position_cb( Pane *pane )\n{\n\tint max_position;\n\tint min_position;\n\tint position;\n\n\t/* Can get here even though we block notify during position set in\n\t * animate, because of delays in window setup.\n\t */\n\tif( pane->animate_timeout )\n\t\treturn;\n\n\tg_object_get( pane, \n\t\t\"max_position\", &max_position, \n\t\t\"min_position\", &min_position, \n\t\tNULL );\n\n\t/* We can have 10,000 as position (meaning way to the\n\t * right), take account of any clipping there may be.\n\t */\n\tpane->position = IM_CLIP( min_position, pane->position, max_position );\n\n\t/* And the new value.\n\t */\n\tposition = gtk_paned_get_position( GTK_PANED( pane ) );\n\n#ifdef DEBUG\n\tprintf( \"pane_notify_position_cb: %p %s %d\\n\", \n\t\tpane, pane_handedness2char( pane->handedness ), position );\n#endif /*DEBUG*/\n\n\tpane_set_position( pane, position );\n\tpane_set_user_position( pane, position );\n\n\t/* Look for dragged close.\n\t */\n\tif( pane->open &&\n\t\tpane->handedness == PANE_HIDE_LEFT && \n\t\tposition == min_position ) \n\t\tpane_set_open( pane, FALSE );\n\tif( pane->open &&\n\t\tpane->handedness == PANE_HIDE_RIGHT &&\n\t\tposition == max_position )\n\t\tpane_set_open( pane, FALSE );\n}\n\nstatic void\npane_init( Pane *pane )\n{\n\tpane->handedness = PANE_HIDE_LEFT;\n\tpane->panechild = NULL;\n\tpane->open = FALSE;\n\tpane->position = 0; \t\t\n\tpane->user_position = 0; \t\t/* overwritten on _link() */\n\tpane->target_position = 0;\n\tpane->close_on_end = FALSE;\n\tpane->last_set_position = 0;\n\tpane->animate_timeout = 0;\n\n\tg_signal_connect( pane, \"notify::position\", \n\t\tG_CALLBACK( pane_notify_position_cb ), NULL );\n}\n\nGType\npane_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( PaneClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) pane_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Pane ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) pane_init,\n\t\t};\n\n\t\ttype = g_type_register_static( GTK_TYPE_HPANED, \n\t\t\t\"Pane\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\n/* Operations on the model.\n */\n\nvoid\npane_set_position( Pane *pane, int position )\n{\n\tif( pane->position != position ) {\n#ifdef DEBUG\n\t\tprintf( \"pane_set_position: %p %s %d\\n\",\n\t\t\tpane, pane_handedness2char( pane->handedness ),\n\t\t\tposition );\n#endif /*DEBUG*/\n\n\t\tg_signal_handlers_block_by_func( pane, \n\t\t\tpane_notify_position_cb, NULL );\n\t\tgtk_paned_set_position( GTK_PANED( pane ), position );\n\t\tg_signal_handlers_unblock_by_func( pane, \n\t\t\tpane_notify_position_cb, NULL );\n\n\t\tpane->position = position;\n\t\tpane_changed( pane );\n\t}\n}\n\nvoid\npane_set_user_position( Pane *pane, int user_position )\n{\n\tif( pane->user_position != user_position ) {\n#ifdef DEBUG\n\t\tprintf( \"pane_set_user_position: %p %s %d\\n\",\n\t\t\tpane, pane_handedness2char( pane->handedness ),\n\t\t\tuser_position );\n#endif /*DEBUG*/\n\n\t\tpane->user_position = user_position;\n\t\tpane_changed( pane );\n\t}\n}\n\nvoid\npane_set_open( Pane *pane, gboolean open )\n{\n\tif( pane->open != open ) {\n#ifdef DEBUG\n\t\tprintf( \"pane_set_open: %p %s %d\\n\",\n\t\t\tpane, pane_handedness2char( pane->handedness ),\n\t\t\topen );\n#endif /*DEBUG*/\n\n\t\twidget_visible( GTK_WIDGET( pane->panechild ), open );\n\t\tpane->open = open;\n\t\tpane_changed( pane );\n\t}\n}\n\n/* Set everything all at once on startup.\n */\nvoid\npane_set_state( Pane *pane, gboolean open, int user_position )\n{\n\tif( pane->open != open ||\n\t\tpane->user_position != user_position ) {\n\t\tg_signal_handlers_block_by_func( pane, \n\t\t\tpane_notify_position_cb, NULL );\n\t\tgtk_paned_set_position( GTK_PANED( pane ), user_position );\n\t\tg_signal_handlers_unblock_by_func( pane, \n\t\t\tpane_notify_position_cb, NULL );\n\n\t\twidget_visible( GTK_WIDGET( pane->panechild ), open );\n\n\t\tpane->open = open;\n\t\tpane->user_position = user_position;\n\t\tpane->position = user_position;\n\n\t\tpane_changed( pane );\n\t}\n}\n\nvoid\npane_set_child( Pane *pane, Panechild *panechild )\n{\n\tg_assert( !pane->panechild );\n\n\tpane->panechild = panechild;\n\n\tif( pane->handedness == PANE_HIDE_LEFT )\n\t\tgtk_paned_pack1( GTK_PANED( pane ), \n\t\t\tGTK_WIDGET( panechild ), TRUE, TRUE );\n\telse\n\t\tgtk_paned_pack2( GTK_PANED( pane ), \n\t\t\tGTK_WIDGET( panechild ), TRUE, TRUE );\n}\n\n/* Control.\n */\n\nstatic gboolean\npane_animate_timeout_cb( Pane *pane )\n{\n\tint position = pane->position;\n\tint target = pane->target_position;\n\n\tint new;\n\tgboolean more;\n\n#ifdef DEBUG\n\tprintf( \"pane_animate_timeout_cb: %p %s\\n\",\n\t\tpane, pane_handedness2char( pane->handedness ) );\n#endif /*DEBUG*/\n\n\tmore = TRUE;\n\tnew = position + (target - position) / 2;\n\tif( ABS( position - target ) < 5 || \n\t\tnew == pane->last_set_position ) {\n\t\t/* At our target!\n\t\t */\n\t\tnew = target;\n\t\tmore = FALSE;\n\t\tpane->animate_timeout = 0;\n\t}\n\n\tpane_set_position( pane, new );\n\tpane->last_set_position = new;\n\n\tif( !more &&\n\t\tpane->close_on_end )\n\t\tpane_set_open( pane, FALSE );\n\n\treturn( more );\n}\n\n/* Close the pane with an animation.\n */\nvoid\npane_animate_closed( Pane *pane )\n{\n\tif( !pane->animate_timeout && \n\t\tpane->open ) {\n\t\tint max_position;\n\t\tint min_position;\n\t\tint target_position;\n\n\t\ttarget_position = pane_closed_position( pane );\n\t\tg_object_get( pane, \n\t\t\t\"max_position\", &max_position, \n\t\t\t\"min_position\", &min_position, \n\t\t\tNULL );\n\n\t\t/* Can be zero if we're here very early.\n\t\t */\n\t\tif( max_position > 0 ) \n\t\t\ttarget_position = \n\t\t\t\tIM_CLIP( min_position, \n\t\t\t\t\ttarget_position, max_position );\n\t\tpane->target_position = target_position;\n\t\tpane->close_on_end = TRUE;\n\t\tpane->last_set_position = -1;\n\n\t\tpane->animate_timeout = g_timeout_add( 50, \n\t\t\t(GSourceFunc) pane_animate_timeout_cb, pane );\n\t}\n}\n\n/* Open the pane with an animation.\n */\nvoid\npane_animate_open( Pane *pane )\n{\n\tif( !pane->animate_timeout && \n\t\t!pane->open ) {\n\t\tint max_position;\n\t\tint min_position;\n\t\tint target_position;\n\n\t\ttarget_position = pane->user_position;\n\t\tg_object_get( pane, \n\t\t\t\"max_position\", &max_position, \n\t\t\t\"min_position\", &min_position, \n\t\t\tNULL );\n\n\t\t/* Can be zero if we're here very early.\n\t\t */\n\t\tif( max_position > 0 ) \n\t\t\ttarget_position = \n\t\t\t\tIM_CLIP( min_position, \n\t\t\t\t\ttarget_position, max_position );\n\n\t\t/* user_position can be max or min if the pane was dragged\n\t\t * closed.\n\t\t */\n\t\tif( target_position == max_position ||\n\t\t\ttarget_position == min_position )\n\t\t\ttarget_position = pane_open_position( pane );\n\n#ifdef DEBUG\n\t\tprintf( \"pane_animate_open: %p %s %d\\n\", \n\t\t\tpane, pane_handedness2char( pane->handedness ), \n\t\t\ttarget_position );\n#endif /*DEBUG*/\n\n\t\tpane->target_position = target_position;\n\t\tpane->close_on_end = FALSE;\n\t\tpane->last_set_position = -1;\n\t\tpane_set_open( pane, TRUE );\n\n\t\tpane->animate_timeout = g_timeout_add( 50, \n\t\t\t(GSourceFunc) pane_animate_timeout_cb, pane );\n\t}\n}\n\nstatic void\npane_link( Pane *pane, PaneHandedness handedness )\n{\n#ifdef DEBUG\n\tprintf( \"pane_link: %p %s\\n\",\n\t\tpane, pane_handedness2char( handedness ) );\n#endif /*DEBUG*/\n\n\tpane->handedness = handedness;\n\tpane_set_open( pane, FALSE );\n}\n\nPane *\npane_new( PaneHandedness handedness )\n{\n\tPane *pane;\n\n\tpane = PANE( g_object_new( TYPE_PANE, NULL ) );\n\tpane_link( pane, handedness );\n\n\treturn( pane );\n}\n"
  },
  {
    "path": "src/pane.h",
    "content": "/* a side panel that can slide in and out of view\n */\n\n/*\n\n    Copyright (C) 2007 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_PANE (pane_get_type())\n#define PANE( obj ) (GTK_CHECK_CAST( (obj), TYPE_PANE, Pane ))\n#define PANE_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_PANE, PaneClass ))\n#define IS_PANE( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PANE ))\n#define IS_PANE_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PANE ))\n\n/* Can hide on the left or the right hand side of a window.\n */\ntypedef enum {\n\tPANE_HIDE_LEFT,\n\tPANE_HIDE_RIGHT\n} PaneHandedness;\n\ntypedef struct _Pane {\n\tGtkHPaned parent_object;\n\n\tPaneHandedness handedness;\t/* Hide on left or right */\n\n\t/* The child pane we show on left or right.\n\t */\n\tPanechild *panechild;\n\n\t/* Are we visible or not.\n\t */\n\tgboolean open;\n\n\t/* The position of the divider. This changes as the pane is animated\n\t * open and closed and does not reflect the position the user has\n\t * selected by dragging.\n\t */\n\tint position;\t\t\n\n\t/* The position the user wants the pane to sit at.\n\t */\n\tint user_position;\n\n\t/* Animating towards this position. If close_on_end is true, close the\n\t * pane at the end of animation.\n\t */\n\tint target_position;\n\tgboolean close_on_end;\n\n\t/* Set animation speed with this.\n\t */\n\tint last_set_position;\t\t\n\n\t/* Timeout for animation.\n\t */\n\tguint animate_timeout;\n} Pane;\n\ntypedef struct _PaneClass {\n\tGtkHPanedClass parent_class;\n\n\t/* Either position or open have changed.\n\t */\n\tvoid (*changed)( Pane * );\n} PaneClass;\n\nGType pane_get_type( void );\n\nPane *pane_new( PaneHandedness handedness );\n\nvoid pane_set_position( Pane *pane, int position );\nvoid pane_set_user_position( Pane *pane, int user_position );\nvoid pane_set_open( Pane *pane, gboolean open );\nvoid pane_set_state( Pane *pane, gboolean open, int user_position );\nvoid pane_set_child( Pane *pane, Panechild *panechild );\n\nvoid pane_animate_closed( Pane *pane );\nvoid pane_animate_open( Pane *pane );\n\n"
  },
  {
    "path": "src/panechild.c",
    "content": "/* The thing that sits in a pane showing the title and close button.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk \n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\nstatic void\npanechild_finalize( GObject *gobject )\n{\n\tPanechild *panechild = PANECHILD( gobject );\n\n#ifdef DEBUG\n\tprintf( \"panechild_finalize\\n\" );\n#endif /*DEBUG*/\n\n\t/* My instance finalize stuff.\n\t */\n\tIM_FREE( panechild->title );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\npanechild_refresh( vObject *vobject )\n{\n\tPanechild *panechild = PANECHILD( vobject );\n\n#ifdef DEBUG\n\tprintf( \"panechild_refresh:\\n\" );\n#endif /*DEBUG*/\n\n\tset_glabel( panechild->label, \"%s\", panechild->title );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\npanechild_class_init( PanechildClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = panechild_finalize;\n\n\tvobject_class->refresh = panechild_refresh;\n}\n\nstatic void\npanechild_hide_cb( GtkWidget *wid, Panechild *panechild )\n{\n\tpane_animate_closed( panechild->pane );\n}\n\nstatic void\npanechild_init( Panechild *panechild )\n{\n\tGtkWidget *hbox;\n\tGtkWidget *but;\n        GtkWidget *icon;\n\n#ifdef DEBUG\n\tprintf( \"panechild_init:\\n\" );\n#endif /*DEBUG*/\n\n\tpanechild->pane = NULL;\n\tpanechild->title = NULL;\n\tpanechild->label = NULL;\n\n\thbox = gtk_hbox_new( FALSE, 7 );\n\tgtk_box_pack_start( GTK_BOX( panechild ), hbox, FALSE, FALSE, 0 );\n\n        but = gtk_button_new();\n        gtk_button_set_relief( GTK_BUTTON( but ), GTK_RELIEF_NONE );\n        gtk_box_pack_end( GTK_BOX( hbox ), but, FALSE, FALSE, 0 );\n        set_tooltip( but, _( \"Close the pane\" ) );\n\ticon = gtk_image_new_from_stock( GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU );\n        gtk_container_add( GTK_CONTAINER( but ), icon );\n        gtk_signal_connect( GTK_OBJECT( but ), \"clicked\",\n                GTK_SIGNAL_FUNC( panechild_hide_cb ), panechild );\n\n        panechild->label = gtk_label_new( \"\" );\n\tgtk_misc_set_alignment( GTK_MISC( panechild->label ), 0.0, 0.5 );\n        gtk_box_pack_start( GTK_BOX( hbox ), panechild->label, TRUE, TRUE, 2 );\n\n\tgtk_widget_show_all( hbox );\n}\n\nGtkType\npanechild_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( PanechildClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) panechild_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Panechild ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) panechild_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_VOBJECT,\n\t\t\t\"Panechild\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nPanechild *\npanechild_new( Pane *pane, const char *title )\n{\n\tPanechild *panechild = gtk_type_new( TYPE_PANECHILD );\n\n\tIM_SETSTR( panechild->title, title );\n\n\tpanechild->pane = pane;\n\tpane_set_child( pane, panechild );\n\n\treturn( panechild );\n}\n\n"
  },
  {
    "path": "src/panechild.h",
    "content": "/* The thing that sits in a pane showing the title and close button.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_PANECHILD (panechild_get_type())\n#define PANECHILD( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_PANECHILD, Panechild ))\n#define PANECHILD_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_PANECHILD, PanechildClass ))\n#define IS_PANECHILD( obj ) \\\n\t(GTK_CHECK_TYPE( (obj), TYPE_PANECHILD ))\n#define IS_PANECHILD_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PANECHILD ))\n\nstruct _Panechild {\n\tvObject parent_object;\n\n\tPane *pane;\t\t\t/* The pane we are part of */\n\n\tconst char *title;\t\t/* Title we display */\n\tGtkWidget *label;\t\t/* Titlebar label */\n};\n\ntypedef struct _PanechildClass {\n\tvObjectClass parent_class;\n\n} PanechildClass;\n\nGtkType panechild_get_type( void );\nPanechild *panechild_new( Pane *pane, const char *title );\n"
  },
  {
    "path": "src/parse.y",
    "content": "%{\n\n/* Parse ip's macro language.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/*\n#define DEBUG\n */\n\n/* trace text read system\n#define DEBUG_CHARACTER\n */\n\n/* The lexer from lex.l.\n */\nint yylex( void );\nvoid yyrestart( FILE *input_file );\n\n/* Declare file-private stuff, shared with the lexer. Bison will put this\n * stuff into parse.h, so just declare, don't define. Sadly we can't have\n * these things static :(\n */\n\n/* Global .. the symbol whose definition we are currently parsing, the symbol\n * which all defs in this parse action should be made local to.\n */\nextern Symbol *current_symbol;\nextern Symbol *root_symbol;\n\n/* The current parse context.\n */\nextern Compile *current_compile;\nextern ParseNode *current_parsenode;\n\n/* The kit we are adding new symbols to.\n */\nextern Toolkit *current_kit;\n\n/* Where it should go in the kit.\n */\nextern int tool_position;\n\n/* Lineno of start of last top-level def.\n */\nextern int last_top_lineno;\n\n/* Text we've gathered in this lex.\n */\nextern char lex_text_buffer[MAX_STRSIZE];\n\n/* Stack of symbols for parser - each represents a new scope level.\n */\nextern Symbol *scope_stack_symbol[MAX_SSTACK];\nextern Compile *scope_stack_compile[MAX_SSTACK];\nextern int scope_sp;\n\n/* Use to generate unique ids for anonymouse parse objects (eg. lambdas etc).\n */\nextern int parse_object_id;\n\n/* Get text for parsed objects.\n */\nchar *input_text( char *out );\nvoid input_reset( void );\nvoid input_push( int n );\nvoid input_backtoch( char ch );\nvoid input_back1( void );\nvoid input_pop( void );\n\n/* Nest and unnest scopes.\n */\nvoid scope_push( void );\nvoid scope_pop( void );\nvoid scope_pop_all( void );\nvoid scope_reset( void );\n\n/* Helper functions.\n */\nvoid *parse_toplevel_end( Symbol *sym );\nvoid *parse_access_end( Symbol *sym, Symbol *main );\n\n%}\n\n%union {\n\tstruct sym_table *yy_symtab;\n\tParseNode *yy_node;\n\tchar *yy_name;\n\tParseConst yy_const;\n\tUnOp yy_uop;\n\tBinOp yy_binop;\n}\n\n%token TK_TAG TK_IDENT TK_CONST TK_DOTDOTDOT TK_LAMBDA TK_FROM TK_TO TK_SUCHTHAT\n%token TK_UMINUS TK_UPLUS TK_POW \n%token TK_LESS TK_LESSEQ TK_MORE TK_MOREEQ TK_NOTEQ\n%token TK_LAND TK_LOR TK_BAND TK_BOR TK_JOIN TK_DIFF\n%token TK_IF TK_THEN TK_ELSE \n%token TK_CHAR TK_SHORT TK_CLASS TK_SCOPE\n%token TK_INT TK_FLOAT TK_DOUBLE TK_SIGNED TK_UNSIGNED TK_COMPLEX\n%token TK_SEPARATOR TK_DIALOG TK_LSHIFT TK_RSHIFT\n\n%type <yy_node> expr binop uop rhs list_expression comma_list body \n%type <yy_node> simple_pattern complex_pattern list_pattern\n%type <yy_node> leaf_pattern\n%type <yy_node> crhs cexprlist prhs lambda\n%type <yy_const> TK_CONST \n%type <yy_name> TK_IDENT TK_TAG\n\n%left TK_SUCHTHAT \n%left TK_LAMBDA \n%nonassoc TK_IF \n%left ',' \n%left TK_TO \n%left TK_LOR \n%left TK_LAND '@'\n%left TK_BOR\n%left '^' \n%left TK_BAND\n%nonassoc TK_EQ TK_NOTEQ TK_PEQ TK_PNOTEQ\n%nonassoc TK_LESS TK_LESSEQ TK_MORE TK_MOREEQ \n%left TK_LSHIFT TK_RSHIFT\n%left '+' '-'\n%left '*' '/' '%' \n%left '!' '~' TK_JOIN TK_DIFF TK_UMINUS TK_UPLUS \n%right TK_POW ':'\n%right TK_CONST '(' \n%right TK_IDENT TK_TAG TK_SCOPE '['\n%right TK_APPLICATION\n%left '?' '.' \n\n%start select\n\n/* \n\n  Our syntax for list comprehensions is not LALR(1). We have:\n\n  \tsimple_pattern '<-' expr ';' |\n\texpr ';'\n\n  simple_pattern can be something like\n\n\ta:x\n\n  which is also an expr. We don't know which branch to take until we see a\n  '<' or a ';'.\n\n  Use bison's GLR system to parse this, and ignore the first 13 reduce/reduce\n  conflicts caused by this ambiguity.\n\n  FIXME ... we now depend on bison, but we still have some yacc compatibility\n  stuff in here, and we don't use all of bison's nice features (eg. for\n  tracking line numbers in the source file). Fix this up at some stage.\n\n */\n\n%glr-parser\n%expect-rr 13\n\n%error-verbose\n\n%%\n\nselect: \n      \t',' main | \n\t'^' single_definition | \n\t'*' params_plus_rhs optsemi {\n\t\tcompile_check( current_compile );\n\t} | \n\tprhs {\n\t\tchar buf[MAX_STRSIZE];\n\n\t\tcurrent_compile->tree = $1;\n\n\t\t/* Junk any old text.\n\t\t */\n\t\tIM_FREE( current_compile->text );\n\t\tIM_FREE( current_compile->prhstext );\n\t\tIM_FREE( current_compile->rhstext );\n\n\t\t/* Set new text.\n\t\t */\n\t\tIM_SETSTR( current_compile->rhstext, input_text( buf ) );\n\n\t\tcompile_check( current_compile );\n\t}\n\t;\n\nprhs: \n    \tTK_BAND expr {\n\t\t$$ = $2;\n\t} | \n\t'@' cexprlist {\n\t\t$$ = $2;\n\t}\n\t;\n\nmain: \n    \t/* Empty */ | \n\tmain single_definition\n\t;\n\nsingle_definition: \n      \tdirective {\n\t\ttool_position += 1;\n\t} | \n\ttoplevel_definition optsemi {\n\t\ttool_position += 1;\n\t}\n\t;\n\ndirective: \n\tTK_SEPARATOR {\n\t\tTool *tool;\n\n\t\tif( !is_top( current_symbol ) )\n\t\t\tyyerror( _( \"not top level\" ) );\n\n\t\ttool = tool_new_sep( current_kit, tool_position );\n\t\ttool->lineno = input_state.lineno;\n\n\t\tinput_reset();\n\t} | \n\tTK_DIALOG TK_CONST TK_CONST {\n\t\tTool *tool;\n\n\t\tif( !is_top( current_symbol ) )\n\t\t\tyyerror( _( \"not top level\" ) );\n\n\t\t/* Should have two strings.\n\t\t */\n\t\tif( $2.type != PARSE_CONST_STR || $3.type != PARSE_CONST_STR )\n\t\t\tyyerror( _( \"not strings\" ) );\n\n\t\t/* Add tool.\n\t\t */\n\t\ttool = tool_new_dia( current_kit, tool_position, \n\t\t\t$2.val.str, $3.val.str );\n\t\tif( !tool )\n\t\t\tyyerror( error_get_sub() );\n\t\ttool->lineno = input_state.lineno;\n\n\t\t/* Cast away const here.\n\t\t */\n\t\ttree_const_destroy( (ParseConst *) &$2 );\n\t\ttree_const_destroy( (ParseConst *) &$3 );\n\n\t\tinput_reset();\n\t}\n\t;\n\ntoplevel_definition: \n\t{\n\t\tlast_top_lineno = input_state.lineno;\n\t\tscope_reset();\n\t\tcurrent_compile = root_symbol->expr->compile;\n\t}\n\tdefinition {\n\t\tinput_reset();\n\t}\n\t;\n\n/* Parse a new defining occurence. This can be a local or a top-level.\n */\ndefinition: \n   \tsimple_pattern {\t\n\t\tSymbol *sym;\n\n\t\t/* Two forms: <name pattern-list rhs>, or <pattern rhs>.\n\t\t * Enforce the no-args-to-pattern-assignment rule in the arg\n\t\t * pattern parser.\n\t\t */\n\t\tif( $1->type == NODE_LEAF ) {\n\t\t\tconst char *name = IOBJECT( $1->leaf )->name;\n\n\t\t\t/* Make a new defining occurence.\n\t\t\t */\n\t\t\tsym = symbol_new_defining( current_compile, name );\n\n\t\t\t(void) symbol_user_init( sym );\n\t\t\t(void) compile_new_local( sym->expr );\n\t\t}\n\t\telse {\n\t\t\tchar name[256];\n\n\t\t\t/* We have <pattern rhs>. Make an anon symbol for this\n\t\t\t * value, then the variables in the pattern become\n\t\t\t * toplevels which access that.\n\t\t\t */\n\t\t\tif( !compile_pattern_has_leaf( $1 ) )\n\t\t\t\tyyerror( _( \"left-hand-side pattern \"\n\t\t\t\t\t\"contains no identifiers\" ) );\n\t\t\tim_snprintf( name, 256, \"$$pattern_lhs%d\",\n\t\t\t\tparse_object_id++ );\n\t\t\tsym = symbol_new_defining( current_compile, name );\n\t\t\tsym->generated = TRUE;\n\t\t\t(void) symbol_user_init( sym );\n\t\t\t(void) compile_new_local( sym->expr );\n\t\t}\n\n\t\t/* Note on the enclosing last_sym. Things like the program\n\t\t * window use this to work out what sym to display after a\n\t\t * parse. symbol_dispose() is careful to NULL this out.\n\t\t */\n\t\tcurrent_compile->last_sym = sym;\n\n\t\t/* Initialise symbol parsing variables. Save old current symbol,\n\t\t * add new one.\n\t\t */\n\t\tscope_push();\n\t\tcurrent_symbol = sym;\n\t\tcurrent_compile = sym->expr->compile;\n\n\t\tg_assert( !current_compile->param );\n\t\tg_assert( current_compile->nparam == 0 );\n\n\t\t/* Junk any old def text.\n\t\t */\n\t\tIM_FREE( current_compile->text );\n\t\tIM_FREE( current_compile->prhstext );\n\t\tIM_FREE( current_compile->rhstext );\n\t}\n\tparams_plus_rhs {\n\t\tcompile_check( current_compile );\n\n\t\t/* Link unresolved names into the outer scope.\n\t\t */\n\t\tcompile_resolve_names( current_compile, \n\t\t\tcompile_get_parent( current_compile ) );\n\n\t\t/* Is this the end of a top-level? Needs extra work to add to\n\t\t * the enclosing toolkit etc.\n\t\t */\n\t\tif( is_scope( symbol_get_parent( current_symbol ) ) ) \n\t\t\tparse_toplevel_end( current_symbol );\n\n\t\t/* Is this a pattern definition? Expand the pattern to a\n\t\t * set of access defs.\n\t\t */\n\t\tif( $1->type != NODE_LEAF ) {\n\t\t\tCompile *parent = compile_get_parent( current_compile );\n\t\t\tGSList *built_syms;\n\n\t\t\tbuilt_syms = compile_pattern_lhs( parent, \n\t\t\t\tcurrent_symbol, $1 );\n\n\t\t\tif( is_scope( symbol_get_parent( current_symbol ) ) )\n\t\t\t\tslist_map( built_syms,\n\t\t\t\t\t(SListMapFn) parse_toplevel_end, NULL );\n\t\t\tslist_map( built_syms,\n\t\t\t\t(SListMapFn) parse_access_end, \n\t\t\t\tcurrent_symbol );\n\n\t\t\tg_slist_free( built_syms );\n\t\t}\n\n\t\tscope_pop();\n\t}\n\t;\n\n/* Parse params/body/locals into current_expr\n */\nparams_plus_rhs: \n\t{\t\n\t\tinput_push( 1 );\n\n\t\t/* We've already read the character past the end of the \n\t\t * identifier (that's why we know the identifier is over).\n\t\t */\n\t\tinput_back1();\n\t}\n\tparams {\t\n\t\tinput_push( 2 );\n\t\tinput_backtoch( '=' );\n\t}\n\tbody {\n\t\tcurrent_compile->tree = $4;\n\t\tg_assert( current_compile->tree );\n\t\tinput_push( 4 );\n\t}\n\tlocals {\n\t\tchar buf[MAX_STRSIZE];\n\n\t\tinput_pop();\n\n\t\t/* Save body text as rhstext.\n\t\t */\n\t\tIM_SETSTR( current_compile->rhstext, input_text( buf ) );\n\t\tinput_pop();\n\n\t\t/* Save params '=' body as prhstext.\n\t\t */\n\t\tIM_SETSTR( current_compile->prhstext, input_text( buf ) );\n\t\tinput_pop();\n\n\t\t/* Save full text of definition.\n\t\t */\n\t\tIM_SETSTR( current_compile->text, input_text( buf ) );\n\n#ifdef DEBUG\n\t\tprintf( \"%s->compile->text = \\\"%s\\\"\\n\",\n\t\t\tIOBJECT( current_compile->sym )->name, \n\t\t\tcurrent_compile->text );\n\t\tprintf( \"%s->compile->prhstext = \\\"%s\\\"\\n\",\n\t\t\tIOBJECT( current_compile->sym )->name, \n\t\t\tcurrent_compile->prhstext );\n\t\tprintf( \"%s->compile->rhstext = \\\"%s\\\"\\n\",\n\t\t\tIOBJECT( current_compile->sym )->name, \n\t\t\tcurrent_compile->rhstext );\n#endif /*DEBUG*/\n\t}\n\t;\n\t\nparams: \n      \t/* Empty */ | \n\tparams simple_pattern {\n\t\tSymbol *sym;\n\n\t\t/* If the pattern is just an identifier, make it a direct\n\t\t * parameter. Otherwise make an anon param and put the pattern\n\t\t * in as a local with the same id.\n\t\t *\n\t\t *\tfred [a] = 12;\n\t\t *\n\t\t * parses to:\n\t\t *\n\t\t *\tfred $$arg42 = 12 { $$patt42 = [a]; }\n\t\t * \n\t\t * A later pass creates the \"a = $$arg42?0\" definition.\n\t\t */\n\t\tif( $2->type == NODE_LEAF ) {\n\t\t\tconst char *name = IOBJECT( $2->leaf )->name;\n\n\t\t\t/* Make defining occurence.\n\t\t\t */\n\t\t\tsym = symbol_new_defining( current_compile, name );\n\t\t\t(void) symbol_parameter_init( sym );\n\t\t}\n\t\telse {\n\t\t\tchar name[256];\n\n\t\t\tim_snprintf( name, 256, \"$$arg%d\", parse_object_id );\n\t\t\tsym = symbol_new_defining( current_compile, name );\n\t\t\tsym->generated = TRUE;\n\t\t\t(void) symbol_parameter_init( sym );\n\n\t\t\tim_snprintf( name, 256, \"$$patt%d\", parse_object_id++ );\n\t\t\tsym = symbol_new_defining( current_compile, name );\n\t\t\tsym->generated = TRUE;\n\t\t\t(void) symbol_user_init( sym );\n\t\t\t(void) compile_new_local( sym->expr );\n\t\t\tsym->expr->compile->tree = $2;\n\t\t}\n\t}\n\t;\n\nbody : \n     \t'=' TK_CLASS crhs {\n\t\t$$ = $3;\n\t} | \n\trhs {\n\t\t$$ = $1;\n\t}\n\t;\n\ncrhs: \n    \t{\n\t\tParseNode *pn = tree_class_new( current_compile );\n\n\t\tinput_push( 3 );\n\t\tscope_push();\n\t\tcurrent_symbol = current_compile->super;\n\t\tcurrent_compile = current_symbol->expr->compile;\n\n\t\tcurrent_parsenode = pn;\n\t}\n\tcexprlist {\n\t\tCompile *parent = compile_get_parent( current_compile );\n\t\tchar buf[MAX_STRSIZE];\n\t\tint len;\n\n\t\t(void) input_text( buf );\n\n\t\t/* Always read 1 char too many.\n\t\t */\n\t\tif( (len = strlen( buf )) > 0 ) \n\t\t\tbuf[len - 1] = '\\0';\n\n\t\tIM_SETSTR( current_compile->rhstext, buf );\n\t\tinput_pop();\n\t\tcurrent_compile->tree = $2;\n\n\t\tif( current_compile->tree->elist )\n\t\t\tparent->has_super = TRUE;\n\n\t\t/* Do some checking.\n\t\t */\n\t\tcompile_check( current_compile );\n\n\t\t/* Link unresolved names.\n\t\t */\n\t\tcompile_resolve_names( current_compile, parent );\n\n\t\tscope_pop();\n\n\t\t$$ = current_parsenode;\n\t\tcurrent_parsenode = NULL;\n\t}\n\t;\n\nrhs: \n   \t'=' expr { \t\n\t\t$$ = $2;\n\t} | \n\t'=' expr ',' expr optsemi rhs { \t\n\t\t$$ = tree_ifelse_new( current_compile, $4, $2, $6 );\n\t}\n\t;\n\nlocals:\t\n      \t';' | \n\t'{' deflist '}' | \n\t'{' '}' \n\t;\t\n\noptsemi: \n       \t/* Empty */ | \n\t';' optsemi\n\t;\n\ndeflist: \n       \tdefinition {\n\t\tinput_pop();\n\t\tinput_push( 5 );\n\t}\n\toptsemi | \n\tdeflist definition {\n\t\tinput_pop();\n\t\tinput_push( 6 );\n\t}\n\toptsemi\n\t;\n\ncexprlist: \n\t/* Empty */ {\n\t\t$$ = tree_super_new( current_compile );\n\t} | \n\tcexprlist expr %prec TK_APPLICATION {\n\t\t$$ = tree_super_extend( current_compile, $1, $2 );\n\t}\n\t;\n\nexpr: \n    \t'(' expr ')' { \n\t\t$$ = $2;\n\t} | \n\tTK_CONST {\n\t\t$$ = tree_const_new( current_compile, $1 );\n\t} | \n\tTK_IDENT {\n\t\t$$ = tree_leaf_new( current_compile, $1 );\n\t\tim_free( $1 );\n\t} | \n\tTK_TAG {\n\t\t$$ = tree_tag_new( current_compile, $1 );\n\t\tim_free( $1 );\n\t} | \n\tTK_SCOPE {\n\t\t$$ = tree_leaf_new( current_compile, \n\t\t\tIOBJECT( symbol_get_scope( current_symbol ) )->name );\n\t} | \n\tTK_IF expr TK_THEN expr TK_ELSE expr %prec TK_IF {\n\t\t$$ = tree_ifelse_new( current_compile, $2, $4, $6 );\n\t} | \n\texpr expr %prec TK_APPLICATION {\n\t\t$$ = tree_appl_new( current_compile, $1, $2 );\n\t} | \n\tlambda | \n\tlist_expression {\n\t\t$$ = $1;\n\t} | \n\t'(' expr ',' expr ')' {\t\n\t\t$$ = tree_binop_new( current_compile, BI_COMMA, $2, $4 );\n\t} | \n\tbinop | \n\tuop\n\t;\n\nlambda:\n\tTK_LAMBDA TK_IDENT %prec TK_LAMBDA {\n\t\tchar name[256];\n\t\tSymbol *sym;\n\n\t\t/* Make an anonymous symbol local to the current sym, compile\n\t\t * the expr inside that.\n\t\t */\n\t\tim_snprintf( name, 256, \"$$lambda%d\", parse_object_id++ );\n\t\tsym = symbol_new_defining( current_compile, name );\n\t\tsym->generated = TRUE;\n\t\t(void) symbol_user_init( sym );\n\t\t(void) compile_new_local( sym->expr );\n\n\t\t/* Initialise symbol parsing variables. Save old current symbol,\n\t\t * add new one.\n\t\t */\n\t\tscope_push();\n\t\tcurrent_symbol = sym;\n\t\tcurrent_compile = sym->expr->compile;\n\n\t\t/* Make the parameter.\n\t\t */\n\t\tsym = symbol_new_defining( current_compile, $2 );\n\t\tsymbol_parameter_init( sym );\n\t\tim_free( $2 );\n\t}\n\texpr {\n\t\tSymbol *sym;\n\n\t\tcurrent_compile->tree = $4;\n\n\t\tif( !compile_check( current_compile ) )\n\t\t\tyyerror( error_get_sub() );\n\n\t\t/* Link unresolved names in to the outer scope.\n\t\t */\n\t\tcompile_resolve_names( current_compile, \n\t\t\tcompile_get_parent( current_compile ) );\n\n\t\t/* The value of the expr is the anon we defined.\n\t\t */\n\t\tsym = current_symbol;\n\t\tscope_pop();\n\t\t$$ = tree_leafsym_new( current_compile, sym );\n\t}\n\t;\n\nlist_expression: \n      \t'[' expr TK_DOTDOTDOT ']' {\n\t\t$$ = tree_generator_new( current_compile, $2, NULL, NULL );\n\t} | \n\t'[' expr TK_DOTDOTDOT expr ']' {\n\t\t$$ = tree_generator_new( current_compile, $2, NULL, $4 );\n\t} | \n\t'[' expr ',' expr TK_DOTDOTDOT ']' {\n\t\t$$ = tree_generator_new( current_compile, $2, $4, NULL );\n\t} | \n\t'[' expr ',' expr TK_DOTDOTDOT expr ']' {\n\t\t$$ = tree_generator_new( current_compile, $2, $4, $6 );\n\t} | \n\t'[' expr TK_SUCHTHAT {\n\t\tchar name[256];\n\t\tSymbol *sym;\n\t\tCompile *enclosing = current_compile;\n\n\t\t/* Make an anonymous symbol local to the current sym, copy\n\t\t * the map expr inside that. \n\t\t */\n\t\tim_snprintf( name, 256, \"$$lcomp%d\", parse_object_id++ );\n\t\tsym = symbol_new_defining( current_compile, name );\n\t\t(void) symbol_user_init( sym );\n\t\tsym->generated = TRUE;\n\t\t(void) compile_new_local( sym->expr );\n\n\t\t/* Push a new scope.\n\t\t */\n\t\tscope_push();\n\t\tcurrent_symbol = sym;\n\t\tcurrent_compile = sym->expr->compile;\n\n\t\t/* Somewhere to save the result expr. We have to copy the\n\t\t * expr, as we want it to be bound in $$lcomp's context so\n\t\t * that it can see the generators.\n\t\t */\n\t\tsym = symbol_new_defining( current_compile, \"$$result\" );\n\t\tsym->generated = TRUE;\n\t\tsym->placeholder = TRUE;\n\t\t(void) symbol_user_init( sym );\n\t\t(void) compile_new_local( sym->expr );\n\t\tsym->expr->compile->tree = compile_copy_tree( enclosing, $2, \n\t\t\tsym->expr->compile );\n\t}\n\tgenerator frompred_list ']' {\n\t\tSymbol *sym;\n\n\t\t/* The map expr can refer to generator names. Resolve inwards\n\t\t * so it links to the generators.\n\t\t */\n\t\tcompile_resolve_names( compile_get_parent( current_compile ),\n\t\t\tcurrent_compile ); \n\n\t\t/* Generate the code for the list comp.\n\t\t */\n\t\tcompile_lcomp( current_compile );\n\n\t\tcompile_check( current_compile );\n\n\t\t/* Link unresolved names outwards.\n\t\t */\n\t\tcompile_resolve_names( current_compile, \n\t\t\tcompile_get_parent( current_compile ) );\n\n\t\t/* The value of the expr is the anon we defined.\n\t\t */\n\t\tsym = current_symbol;\n\t\tscope_pop();\n\t\t$$ = tree_leafsym_new( current_compile, sym );\n\t} |\n\t'[' comma_list ']' {\n\t\t$$ = $2;\n\t} | \n\t'[' ']' {\n\t\tParseConst elist;\n\n\t\telist.type = PARSE_CONST_ELIST;\n\t\t$$ = tree_const_new( current_compile, elist );\n\t}\n\t;\n\nfrompred_list: \n\t/* Empty */ {\n\t} |\n     \tfrompred_list ';' frompred {\n\t}\n\t;\n\ngenerator:\n       simple_pattern TK_FROM expr {\n\t\tchar name[256];\n\t\tSymbol *sym;\n\n\t\tim_snprintf( name, 256, \"$$pattern%d\", parse_object_id );\n\t\tsym = symbol_new_defining( current_compile, name );\n\t\tsym->generated = TRUE;\n\t\tsym->placeholder = TRUE;\n\t\t(void) symbol_user_init( sym );\n\t\t(void) compile_new_local( sym->expr );\n\t\tsym->expr->compile->tree = $1;\n\n\t\tim_snprintf( name, 256, \"$$generator%d\", parse_object_id++ );\n\t\tsym = symbol_new_defining( current_compile, name );\n\t\tsym->generated = TRUE;\n\t\tsym->placeholder = TRUE;\n\t\t(void) symbol_user_init( sym );\n\t\t(void) compile_new_local( sym->expr );\n\t\tsym->expr->compile->tree = $3;\n       }\n       ;\n\nfrompred:\n       generator |\n       expr {\n\t\tchar name[256];\n\t\tSymbol *sym;\n\n\t\tim_snprintf( name, 256, \"$$filter%d\", parse_object_id++ );\n\t\tsym = symbol_new_defining( current_compile, name );\n\t\tsym->generated = TRUE;\n\t\tsym->placeholder = TRUE;\n\t\t(void) symbol_user_init( sym );\n\t\t(void) compile_new_local( sym->expr );\n\t\tsym->expr->compile->tree = $1;\n       }\n       ;\n\ncomma_list: \n     \texpr ',' comma_list {\n\t\t$$ = tree_lconst_extend( current_compile, $3, $1 );\n\t} | \n\texpr {\n\t\t$$ = tree_lconst_new( current_compile, $1 );\n\t}\n\t;\n\n/* How odd, break the \"'+' { BI_ADD } | ...\" into a separate production and we\n * get reduce/reduce conflits. Copypaste a lot instead.\n */\nbinop: \n     \texpr '+' expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_ADD, $1, $3 );\n\t} | \n\texpr ':' expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_CONS, $1, $3 );\n\t} | \n\texpr '-' expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_SUB, $1, $3 );\n\t} | \n\texpr '?' expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_SELECT, $1, $3 );\n\t} | \n\texpr '/' expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_DIV, $1, $3 );\n\t} | \n\texpr '*' expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_MUL, $1, $3 );\n\t} | \n\texpr '%' expr {\n\t\t$$ = tree_binop_new( current_compile, BI_REM, $1, $3 );\n\t} | \n\texpr TK_JOIN expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_JOIN, $1, $3 );\n\t} | \n\texpr TK_POW expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_POW, $1, $3 );\n\t} | \n\texpr TK_LSHIFT expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_LSHIFT, $1, $3 );\n\t} | \n\texpr TK_RSHIFT expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_RSHIFT, $1, $3 );\n\t} | \n\texpr '^' expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_EOR, $1, $3 );\n\t} | \n\texpr TK_LAND expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_LAND, $1, $3 );\n\t} | \n\texpr TK_BAND expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_BAND, $1, $3 );\n\t} | \n\texpr '@' expr {\t\n\t\t$$ = tree_compose_new( current_compile, $1, $3 );\n\t} | \n\texpr TK_LOR expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_LOR, $1, $3 );\n\t} | \n\texpr TK_BOR expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_BOR, $1, $3 );\n\t} | \n\texpr TK_LESS expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_LESS, $1, $3 );\n\t} | \n\texpr TK_LESSEQ expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_LESSEQ, $1, $3 );\n\t} | \n\texpr TK_MORE expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_MORE, $1, $3 );\n\t} | \n\texpr TK_MOREEQ expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_MOREEQ, $1, $3 );\n\t} | \n\texpr TK_EQ expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_EQ, $1, $3 );\n\t} | \n\texpr TK_NOTEQ expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_NOTEQ, $1, $3 );\n\t} | \n\texpr TK_PEQ expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_PEQ, $1, $3 );\n\t} | \n\texpr TK_PNOTEQ expr {\t\n\t\t$$ = tree_binop_new( current_compile, BI_PNOTEQ, $1, $3 );\n\t} | \n\texpr '.' expr {\n\t\t$$ = tree_binop_new( current_compile, BI_DOT, $1, $3 );\n\t} |\n\texpr TK_DIFF expr {\t\n\t\tParseNode *pn1, *pn2;\n\n\t\tpn1 = tree_leaf_new( current_compile, \"difference\" );\n\t\tpn2 = tree_leaf_new( current_compile, \"equal\" );\n\t\tpn1 = tree_appl_new( current_compile, pn1, pn2 );\n\t\tpn1 = tree_appl_new( current_compile, pn1, $1 );\n\t\tpn1 = tree_appl_new( current_compile, pn1, $3 );\n\n\t\t$$ = pn1;\n\t} | \n\texpr TK_TO expr {\n\t\tParseNode *pn;\n\n\t\tpn = tree_leaf_new( current_compile, \"mknvpair\" );\n\t\tpn = tree_appl_new( current_compile, pn, $1 );\n\t\tpn = tree_appl_new( current_compile, pn, $3 );\n\n\t\t$$ = pn;\n\t}\n\t;\n\nsigned: \n      \t/* Nothing */ | \n\tTK_SIGNED\n\t;\n\nunsigned: \n\t/* Nothing */ | \n\tTK_UNSIGNED\n\t;\n\nuop: \n   \t'(' unsigned TK_CHAR ')' expr %prec TK_UMINUS {\t\n\t\t$$ = tree_unop_new( current_compile, UN_CUCHAR, $5 );\n\t} | \n\t'(' TK_SIGNED TK_CHAR ')' expr %prec TK_UMINUS {\t\n\t\t$$ = tree_unop_new( current_compile, UN_CSCHAR, $5 );\n\t} | \n\t'(' signed TK_SHORT ')' expr %prec TK_UMINUS {\t\n\t\t$$ = tree_unop_new( current_compile, UN_CSSHORT, $5 );\n\t} | \n\t'(' TK_UNSIGNED TK_SHORT ')' expr %prec TK_UMINUS {\n\t\t$$ = tree_unop_new( current_compile, UN_CUSHORT, $5 );\n\t} | \n\t'(' signed TK_INT ')' expr %prec TK_UMINUS {\t\n\t\t$$ = tree_unop_new( current_compile, UN_CSINT, $5 );\n\t} | \n\t'(' TK_UNSIGNED TK_INT ')' expr %prec TK_UMINUS {\n\t\t$$ = tree_unop_new( current_compile, UN_CUINT, $5 );\n\t} | \n\t'(' TK_FLOAT ')' expr %prec TK_UMINUS {\n\t\t$$ = tree_unop_new( current_compile, UN_CFLOAT, $4 );\n\t} | \n\t'(' TK_DOUBLE ')' expr %prec TK_UMINUS {\n\t\t$$ = tree_unop_new( current_compile, UN_CDOUBLE, $4 );\n\t} | \n\t'(' TK_COMPLEX ')' expr %prec TK_UMINUS {\n\t\t$$ = tree_unop_new( current_compile, UN_CCOMPLEX, $4 );\n\t} | \n\t'(' TK_DOUBLE TK_COMPLEX ')' expr %prec TK_UMINUS {\n\t\t$$ = tree_unop_new( current_compile, UN_CDCOMPLEX, $5 );\n\t} | \n\tTK_UMINUS expr {\n\t\t$$ = tree_unop_new( current_compile, UN_MINUS, $2 );\n\t} | \n\t'!' expr {\n\t\t$$ = tree_unop_new( current_compile, UN_NEG, $2 );\n\t} | \n\t'~' expr {\n\t\t$$ = tree_unop_new( current_compile, UN_COMPLEMENT, $2 );\n\t} | \n\tTK_UPLUS expr {\n\t\t$$ = tree_unop_new( current_compile, UN_PLUS, $2 );\n\t}\n\t;\n\n/* Stuff that can appear on the LHS of an equals, or as a parameter pattern.\n */\nsimple_pattern:\n\tleaf_pattern | \n\t'(' leaf_pattern ',' leaf_pattern ')' {\n\t\t$$ = tree_binop_new( current_compile, BI_COMMA, $2, $4 );\n\t} |\n\tsimple_pattern ':' simple_pattern { \n\t\t$$ = tree_binop_new( current_compile, BI_CONS, $1, $3 );\n\t} |\n\t'(' complex_pattern ')' {\n\t\t$$ = $2;\n\t} | \n\t'[' list_pattern ']' {\n\t\t$$ = $2;\n\t} |\n\t'[' ']' {\n\t\tParseConst elist;\n\n\t\telist.type = PARSE_CONST_ELIST;\n\t\t$$ = tree_const_new( current_compile, elist );\n\t}  \n\t;\n\n/* Stuff that can appear in a complex (a, b) pattern.\n */\nleaf_pattern:\n\tTK_IDENT {\n\t\t$$ = tree_leaf_new( current_compile, $1 );\n\t\tim_free( $1 );\n\t} | \n\tTK_CONST {\n\t\t$$ = tree_const_new( current_compile, $1 );\n\t} \n\t;\n\n/* What can appear in round brackets or a comma list.\n */\ncomplex_pattern:\n\tTK_IDENT TK_IDENT {\n\t\t$$ = tree_pattern_class_new( current_compile, $1,\n\t\t\ttree_leaf_new( current_compile, $2 ) );\n\t\tim_free( $1 );\n\t\tim_free( $2 );\n\t} |\n\tsimple_pattern\n\t;\n\nlist_pattern:\n     \tcomplex_pattern ',' list_pattern {\n\t\t$$ = tree_lconst_extend( current_compile, $3, $1 );\n\t} | \n\tcomplex_pattern {\n\t\t$$ = tree_lconst_new( current_compile, $1 );\n\t}\n\t;\n\n%%\n\n/* Return point on syntax error.\n */\njmp_buf parse_error_point;\n\n/* Text we've lexed.\n */\nchar lex_text_buffer[MAX_STRSIZE];\nVipsBuf lex_text = VIPS_BUF_STATIC( lex_text_buffer );\n\n/* State of input system.\n */\nInputState input_state;\n\n/* Defintions for the static decls at the top. We have to put the defs down\n * here to mkake sure they don't creep in to the generated parser.h.\n */\n\n/* Actually, we can't make these static :-( since they are declared extern at\n * the top of the file.\n */\nSymbol *current_symbol;\nSymbol *root_symbol;\nCompile *current_compile = NULL;\nParseNode *current_parsenode = NULL;\nToolkit *current_kit;\nint tool_position;\nint last_top_lineno;\nSymbol *scope_stack_symbol[MAX_SSTACK];\nCompile *scope_stack_compile[MAX_SSTACK];\nint scope_sp = 0;\nint parse_object_id = 0;\n\n/* Here for errors in parse. \n *\n * Bison calls yyerror with only a char* arg. This printf() version is called\n * from nip2 in a few places during parse.\n */\nvoid\nnip2yyerror( const char *sub, ... )\n{\n\tva_list ap;\n \tchar buf[4096];\n\n        va_start( ap, sub );\n        (void) im_vsnprintf( buf, 4096, sub, ap );\n        va_end( ap );\n\n\terror_top( _( \"Parse error.\" ) );\n\n\tif( current_compile && current_compile->last_sym ) \n\t\terror_sub( _( \"Error in %s: %s\" ), \n\t\t\tIOBJECT(  current_compile->last_sym )->name, buf );\n\telse\n\t\terror_sub( _( \"Error: %s\" ), buf );\n\n\tlongjmp( parse_error_point, -1 );\n}\n\n/* Bison calls this.\n */\nvoid\nyyerror( const char *msg )\n{\n\tnip2yyerror( \"%s\", msg );\n}\n\n/* Attach yyinput to a file.\n */\nvoid\nattach_input_file( iOpenFile *of )\n{\n\tInputState *is = &input_state;\n\n#ifdef DEBUG\n\tprintf( \"attach_input_file: \\\"%s\\\"\\n\", of->fname );\n#endif /*DEBUG*/\n\n\t/* Need to clear flex/bison's buffers in case we abandoned the\n\t * previous parse. \n\t */\n\tyyrestart( NULL );\n\n\tis->of = of;\n\tis->str = NULL;\n\tis->strpos = NULL;\n\tis->bwp = 0;\n\tis->bspsp = 0;\n\tis->bsp[is->bspsp] = 0;\n\tis->lineno = 1;\n\tis->charno = 0;\n\tis->pcharno = 0;\n\tis->charpos = 0;\n\tis->oldchar = -1;\n\n\t/* Init text gatherer.\n\t */\n\tvips_buf_rewind( &lex_text );\n}\n\n/* Attach yyinput to a string.\n */\nvoid\nattach_input_string( const char *str )\n{\n\tInputState *is = &input_state;\n\n#ifdef DEBUG\n\tprintf( \"attach_input_string: \\\"%s\\\"\\n\", str );\n#endif /*DEBUG*/\n\n\tyyrestart( NULL );\n\n\tis->of = NULL;\n\tis->str = (char *) str;\n\tis->strpos = (char *) str;\n\tis->bwp = 0;\n\tis->bspsp = 0;\n\tis->bsp[is->bspsp] = 0;\n\tis->lineno = 1;\n\tis->charno = 0;\n\tis->pcharno = 0;\n\tis->charpos = 0;\n\tis->oldchar = -1;\n\n\t/* Init text gatherer.\n\t */\n\tvips_buf_rewind( &lex_text );\n}\n\n/* Read a character from the input.\n */\nint\nip_input( void ) \n{\n\tInputState *is = &input_state;\n\tint ch;\n\n\tif( is->oldchar >= 0 ) {\n\t\t/* From unget buffer.\n\t\t */\n\t\tch = is->oldchar;\n\t\tis->oldchar = -1;\n\t}\n\telse if( is->of ) {\n\t\t/* Input from file. \n\t\t */\n\t\tif( (ch = getc( is->of->fp )) == EOF )\n\t\t\treturn( 0 );\n\t}\n\telse {\n\t\t/* Input from string. \n\t\t */\n\t\tif( (ch = *is->strpos) )\n\t\t\tis->strpos++;\n\t\telse\n\t\t\t/* No counts to update!\n\t\t\t */\n\t\t\treturn( 0 );\n\t}\n\n\t/* Update counts.\n\t */\n\tif( ch == '\\n' ) {\n\t\tis->lineno++;\n\t\tis->pcharno = is->charno + 1;\n\t\tis->charno = 0;\n\t}\n\tis->charno++;\n\tis->charpos++;\n\n\t/* Add this character to the characters we have accumulated for this\n\t * definition.\n\t */\n\tif( is->bwp >= MAX_STRSIZE )\n\t\tyyerror( _( \"definition is too long\" ) );\n\tif( is->bwp >= 0 )\n\t\tis->buf[is->bwp] = ch;\n\tis->bwp++;\n\n\t/* Add to lex text buffer.\n\t */\n\tif( is->charno > 0 )\n\t\tvips_buf_appendc( &lex_text, ch );\n\n#ifdef DEBUG_CHARACTER\n\tprintf( \"ip_input: returning '%c'\\n\", ch ); \n#endif /*DEBUG_CHARACTER*/\n\n\treturn( ch );\n}\n\n/* Unget an input character.\n */\nvoid\nip_unput( int ch )\n{\n\tInputState *is = &input_state;\n\n#ifdef DEBUG_CHARACTER\n\tprintf( \"ip_unput: ungetting '%c'\\n\", ch ); \n#endif /*DEBUG_CHARACTER*/\n\n\t/* Is lex trying to unget the end-of-file marker? Do nothing if it is.\n\t */\n\tif( !ch )\n\t\treturn;\n\n\tif( is->of ) {\n\t\tif( ungetc( ch, is->of->fp ) == EOF )\n\t\t\terror( \"unget buffer overflow\" );\n\t}\n\telse \n\t\t/* Save extra char here.\n\t\t */\n\t\tis->oldchar = ch;\n\n\t/* Redo counts.\n\t */\n\tif( ch == '\\n' ) {\n\t\tis->lineno--;\n\n\t\t/* Restore previous charno.\n\t\t */\n\t\tis->charno = is->pcharno;\n\t\tis->pcharno = 0;\n\t}\n\tis->charno--;\n\tis->charpos--;\n\tis->bwp--;\n\n\t/* Unget from lex text buffer.\n\t */\n\tif( is->charno > 0 )\n\t\tvips_buf_removec( &lex_text, ch );\n}\n\n/* Test for end-of-input.\n */\ngboolean\nis_EOF( void )\n{\n\tInputState *is = &input_state;\n\n\tif( is->of )\n\t\treturn( feof( is->of->fp ) );\n\telse\n\t\treturn( *is->str == '\\0' );\n}\n\n/* Return the text we have accumulated for the current definition. Remove\n * leading and trailing whitespace and spare semicolons. out needs to be\n * MAX_STRSIZE.\n */\nchar *\ninput_text( char *out )\n{\n\tInputState *is = &input_state;\n\tconst char *buf = is->buf;\n\n\tint start = is->bsp[is->bspsp];\n\tint end = is->bwp;\n\tint len;\n\tint i;\n\n\tfor( i = start; i < end && \n\t\t(isspace( buf[i] ) || buf[i] == ';'); i++ )\n\t\t;\n\tstart = i;\n\tfor( i = end - 1; i > start && \n\t\t(isspace( buf[i] ) || buf[i] == ';'); i-- )\n\t\t;\n\tend = i + 1;\n\n\tlen = end - start;\n\n\tg_assert( len < MAX_STRSIZE - 1 );\n\tim_strncpy( out, buf + start, len + 1 );\n\tout[len] = '\\0';\n\n#ifdef DEBUG_CHARACTER\n\tprintf( \"input_text: level %d, returning \\\"%s\\\"\\n\", \n\t\tis->bspsp, out );\n#endif /*DEBUG_CHARACTER*/\n\n\treturn( out );\n}\n\n/* Reset/push/pop input stacks.\n */\nvoid\ninput_reset( void )\n{\n\tInputState *is = &input_state;\n\n#ifdef DEBUG_CHARACTER\n\tprintf( \"input_reset:\\n\" );\n#endif /*DEBUG_CHARACTER*/\n\n\tis->bwp = 0;\n\tis->bspsp = 0;\n\tis->bsp[0] = 0;\n\tvips_buf_rewind( &lex_text );\n}\n\nvoid\ninput_push( int n )\n{\n\tInputState *is = &input_state;\n\n#ifdef DEBUG_CHARACTER\n\tprintf( \"input_push(%d): going to level %d, %d bytes into buffer\\n\", \n\t\tn, is->bspsp + 1, is->bwp );\n\n\t{\n\t\tconst int len = IM_MIN( is->bwp, 20 );\n\t\tint i;\n\n\t\tfor( i = is->bwp - len; i < is->bwp; i++ )\n\t\t\tif( is->buf[i] == '\\n' )\n\t\t\t\tprintf( \"@\" );\n\t\t\telse if( is->buf[i] == ' ' || is->buf[i] == '\\t' )\n\t\t\t\tprintf( \"_\" );\n\t\t\telse\n\t\t\t\tprintf( \"%c\", is->buf[i] );\n\t\tprintf( \"\\n\" );\n\t\tfor( i = 0; i < len; i++ )\n\t\t\tprintf( \"-\" );\n\t\tprintf( \"^\\n\" );\n\t}\n#endif /*DEBUG_CHARACTER*/\n\n\tis->bspsp += 1;\n\tif( is->bspsp >= MAX_SSTACK )\n\t\terror( \"bstack overflow\" );\n\n\tis->bsp[is->bspsp] = is->bwp;\n}\n\n/* Yuk! We've just done an input_push() to try to grab the RHS of a \n * definition ... unfortunately, due to token readahead, we've probably \n * already read the start of the RHS.\n *\n * Back up the start point to just after the last ch character.\n */\nvoid\ninput_backtoch( char ch )\n{\n\tInputState *is = &input_state;\n\tint i;\n\n\tfor( i = is->bsp[is->bspsp] - 1; i > 0 && is->buf[i] != ch; i-- )\n\t\t;\n\n\tif( is->buf[i] == ch )\n\t\tis->bsp[is->bspsp] = i + 1;\n}\n\n/* Move the last input_push() point back 1 character.\n */\nvoid\ninput_back1( void )\n{\n\tInputState *is = &input_state;\n\n\tif( is->bsp[is->bspsp] > 0 )\n\t\tis->bsp[is->bspsp] -= 1;\n}\n\nvoid\ninput_pop( void )\n{\n\tInputState *is = &input_state;\n\n#ifdef DEBUG_CHARACTER\n\tprintf( \"input_pop: %d bytes into buffer\\n\", input_state.bwp );\n#endif /*DEBUG_CHARACTER*/\n\n\tif( is->bspsp <= 0 )\n\t\terror( \"bstack underflow\" );\n\n\tis->bspsp--;\n}\n\nvoid\nscope_push( void )\n{\n\tif( scope_sp == MAX_SSTACK )\n\t\terror( \"sstack overflow\" );\n\n\tscope_stack_symbol[scope_sp] = current_symbol;\n\tscope_stack_compile[scope_sp] = current_compile;\n\tscope_sp += 1;\n}\n\nvoid\nscope_pop( void )\n{\n\tif( scope_sp <= 0 )\n\t\terror( \"sstack underflow\" );\n\n\tscope_sp -= 1;\n\tcurrent_symbol = scope_stack_symbol[scope_sp];\n\tcurrent_compile = scope_stack_compile[scope_sp];\n}\n\n/* Back to the outermost scope.\n */\nvoid\nscope_pop_all( void )\n{\n\tif( scope_sp > 0 ) {\n\t\tscope_sp = 0;\n\t\tcurrent_symbol = scope_stack_symbol[scope_sp];\n\t\tcurrent_compile = scope_stack_compile[scope_sp];\n\t}\n}\n\n/* Reset/push/pop parser stacks. \n */\nvoid\nscope_reset( void )\n{\n\tscope_sp = 0;\n}\n\n/* End of top level parse. Fix up the symbol.\n */\nvoid *\nparse_toplevel_end( Symbol *sym )\n{\n\tTool *tool;\n\n\ttool = tool_new_sym( current_kit, tool_position, sym );\n\ttool->lineno = last_top_lineno;\n\tsymbol_made( sym );\n\n\treturn( NULL );\n}\n\n/* Built a pattern access definition. Set the various text fragments from the\n * def we are drived from.\n */\nvoid *\nparse_access_end( Symbol *sym, Symbol *main )\n{\n\tIM_SETSTR( sym->expr->compile->rhstext, \n\t\tmain->expr->compile->rhstext ); \n\tIM_SETSTR( sym->expr->compile->prhstext, \n\t\tmain->expr->compile->prhstext ); \n\tIM_SETSTR( sym->expr->compile->text, \n\t\tmain->expr->compile->text ); \n\n\treturn( NULL );\n}\n\n/* Interface to parser. \n */\nstatic gboolean\nparse_input( int ch, Symbol *sym, Toolkit *kit, int pos )\n{\n\tcurrent_kit = kit;\n\tcurrent_symbol = sym;\n\troot_symbol = sym;\n\ttool_position = pos;\n\n\tscope_reset();\n\tinput_reset();\n\n\t/* Signal start nonterminal to parser.\n\t */\n\tip_unput( ch );\n\n\tif( setjmp( parse_error_point ) ) {\n\t\t/* Restore current_compile.\n\t\t */\n\t\tscope_pop_all();\n\n\t\tif( current_compile ) \n\t\t\tcompile_error_set( current_compile );\n\n\t\treturn( FALSE );\n\t}\n\tyyparse();\n\n\t/* All ok.\n\t */\n\treturn( TRUE );\n}\n\n/* Parse the input into a set of symbols at a position in a kit. \n * kit may be NULL for no kit. \n */\ngboolean\nparse_toplevel( Toolkit *kit, int pos )\n{\n\tgboolean result;\n\n\tcurrent_compile = NULL;\n\tresult = parse_input( ',', kit->kitg->root, kit, pos );\n\tiobject_changed( IOBJECT( kit ) );\n\n\treturn( result );\n}\n\n/* Parse a single top-level definition.\n */\ngboolean\nparse_onedef( Toolkit *kit, int pos )\n{\n\tgboolean result;\n\n\tcurrent_compile = NULL;\n\tresult = parse_input( '^', kit->kitg->root, kit, pos );\n\tiobject_changed( IOBJECT( kit ) );\n\n\treturn( result );\n}\n\n/* Parse new text into \"expr\". If params is set, str should be \"a b = a+b\"\n * (ie. include params), if not, then just rhs (eg. \"a+b\").\n */\ngboolean\nparse_rhs( Expr *expr, ParseRhsSyntax syntax )\n{\n\tstatic const char start_ch_table[] = {\n\t\t'&',\t\t/* PARSE_RHS */\n\t\t'*',\t\t/* PARSE_PARAMS */\t\t\n\t\t'@'\t\t/* PARSE_SUPER */\n\t};\n\n\tchar start_ch = start_ch_table[(int) syntax];\n\tCompile *compile = compile_new_local( expr );\n\n\tcurrent_compile = compile;\n\tif( !parse_input( start_ch, expr->sym, NULL, -1 ) ) {\n\t\tcurrent_compile = NULL;\n\t\treturn( FALSE );\n\t}\n\tcurrent_compile = NULL;\n\n#ifdef DEBUG\n\tprintf( \"parse_rhs:\\n\" );\n\tdump_tree( compile->tree );\n#endif /*DEBUG*/\n\n\t/* Resolve any dynamic refs.\n\t */\n\texpr_resolve( expr );\n\n\t/* Compile.\n\t */\n\tif( compile_object( compile ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Free any stuff the lexer might have allocated. \n */\nvoid\nfree_lex( int yychar )\n{\n\tswitch( yychar ) {\n\tcase TK_CONST:\n\t\ttree_const_destroy( &yylval.yy_const );\n\t\tbreak;\n\n\tcase TK_IDENT:\n\tcase TK_TAG:\n\t\tIM_FREE( yylval.yy_name );\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n}\n\n/* Do we have a string of the form \"IDENT = ..\"? Use the lexer to look along\n * the string checking components, return the IDENT if we do, NULL otherwise.  \n */\nchar *\nparse_test_define( void )\n{\n\textern int yylex( void );\n\tint yychar;\n\tchar *ident;\n\n\tident = NULL;\n\n\tif( setjmp( parse_error_point ) ) {\n\t\t/* Here for yyerror in lex. \n\t\t */\n\t\tIM_FREE( ident );\n\n\t\treturn( NULL ); \n\t}\n\n\tif( (yychar = yylex()) != TK_IDENT ) {\n\t\tfree_lex( yychar );\n\n\t\treturn( NULL ); \n\t}\n\tident = yylval.yy_name;\n\n\tif( (yychar = yylex()) != '=' ) {\n\t\tfree_lex( yychar );\n\t\tIM_FREE( ident ); \n\n\t\treturn( NULL ); \n\t}\n\n\treturn( ident );\n}\n\n/* Do we have a string like \"Workspaces.untitled.A1 = ..\"? Check for the\n * symbols as we see them, make the last one and return it. Used by --set.\n */\nSymbol *\nparse_set_symbol( void )\n{\n\tint yychar;\n\textern int yylex( void );\n\tCompile *compile = symbol_root->expr->compile;\n\tchar *ident;\n\tSymbol *sym;\n\n\tident = NULL;\n\n\tif( setjmp( parse_error_point ) ) {\n\t\t/* Here for yyerror in lex. \n\t\t */\n\t\tIM_FREE( ident );\n\t\treturn( NULL ); \n\t}\n\n\tdo {\n\t\tif( (yychar = yylex()) != TK_IDENT && yychar != TK_TAG ) {\n\t\t\tfree_lex( yychar );\n\t\t\tyyerror( _( \"identifier expected\" ) );\n\t\t}\n\t\tident = yylval.yy_name;\n\n\t\tswitch( (yychar = yylex()) ) {\n\t\tcase '.':\n\t\t\t/* There's a dot, so we expect another identifier to \n\t\t\t * come. Look up this one and move to that context.\n\t\t\t */\n\t\t\tif( !(sym = compile_lookup( compile, ident )) ) \n\t\t\t\tnip2yyerror( _( \"'%s' does not exist\" ), \n\t\t\t\t\tident );\n\t\t\tif( !sym->expr || \n\t\t\t\t!sym->expr->compile )\n\t\t\t\tnip2yyerror( _( \"'%s' has no members\" ), \n\t\t\t\t\tident );\n\t\t\tcompile = sym->expr->compile;\n\t\t\tIM_FREE( ident );\n\t\t\tbreak;\n\n\t\tcase '=':\n\t\t\t/* This is the final identifier: create the symbol in\n\t\t\t * this context.\n\t\t\t */\n\t\t\tsym = symbol_new_defining( compile, ident );\n\t\t\tIM_FREE( ident );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tfree_lex( yychar );\n\t\t\tyyerror( _( \"'.' or '=' expected\" ) ); \n\t\t}\n\t} while( yychar != '=' );\n\n\treturn( sym );\n}\n"
  },
  {
    "path": "src/parser.h",
    "content": "/* Global variables from parse.y.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n/* Our input stream can be attached to either a string or a FILE. \n * Keep track of the state of play here.\n */\ntypedef struct {\n\tiOpenFile *of;\t\t/* Non-NULL if we read from a file */\n\tchar *str;\t\t/* Non-NULL if we read from a string */\n\tchar *strpos;\t\t/* Position in string */\n\n\tchar buf[MAX_STRSIZE];\t/* Accumulate text of each definition here */\n\tint bwp;\t\t/* Write point in the above */\n\tint bsp[MAX_SSTACK];\t/* Start point stack */\n\tint bspsp;\t\t/* Stack pointer */\n\n\tint lineno;\t\t/* Current line number */\n\tint charno;\t\t/* Character in line */\n\tint pcharno;\t\t/* Characters in previous line */\n\tint charpos;\t\t/* Characters read by lex so far */\n\n\tint oldchar;            /* unget buffer, -1 for no unget */\n} InputState;\n\nextern InputState input_state;\n\n/* Function declarations for parse.y.\n */\nvoid nip2yyerror( const char *sub, ... )\n\t__attribute__((format(printf, 1, 2)));\nvoid yyerror( const char *msg ); \n#ifdef YYLENG_IS_YY_SIZE_T\n/* Assume yy_size_t is size_t.\n */\nextern size_t yyleng;\n#else\nextern int yyleng;\t\t\t/* lex stuff */\n#endif\n\n/* Lex gathers tokens here for workspace.c\n */\nextern VipsBuf lex_text;\n\n/* Attach input for lex.\n */\nvoid attach_input_file( iOpenFile *of );\nvoid attach_input_string( const char *str );\nint ip_input( void );\nvoid ip_unput( int ch );\nvoid ip_unget( void );\ngboolean is_EOF( void );\n\n/* Parse stuff.\n */\n\n/* Order and number important ... see table in parse_rhs()\n */\ntypedef enum {\n\tPARSE_RHS = 0,\t\t/* eg. \"a + b\" */\n\tPARSE_PARAMS,\t\t/* eg. \"a b = a + b\" */\n\tPARSE_SUPER \t\t/* eg. \"fred c d\" */\n} ParseRhsSyntax;\n\nextern jmp_buf parse_error_point;\n\ngboolean parse_toplevel( Toolkit *kit, int pos );\ngboolean parse_onedef( Toolkit *kit, int pos );\ngboolean parse_rhs( Expr *expr, ParseRhsSyntax syntax );\n\nvoid free_lex( int yychar );\nchar *parse_test_define( void );\nSymbol *parse_set_symbol( void );\n"
  },
  {
    "path": "src/path.c",
    "content": "/* Search paths for files.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* just load .defs/.wses from \".\"\n#define DEBUG_LOCAL\n */\n\n/* show path searches\n#define DEBUG_SEARCH\n */\n\n/* show path rewrites\n#define DEBUG_REWRITE\n */\n\n#include \"ip.h\"\n\n/* Default search paths if prefs fail.\n */\nGSList *path_start_default = NULL;\nGSList *path_search_default = NULL;\nconst char *path_tmp_default = NULL;\n\n/* We rewrite paths to try to handle files referenced in workspaces in \n * directories that move.\n *\n * For example, suppose we have workspace.ws in /some/directory which loads\n * image.v in that directory. The workspace will include a line like \n * (Image_file \"/some/directory/image\"). Now if directory is moved to\n * /other/directory and workspace.ws reloaded, we want to rewrite the string\n * \"/some/directory/image.v\" to \"/other/directory/image.v\". \n *\n * Also consider picking ICC profiles in export/import: we want to avoid\n * putting the path into the ws file, we need to go back to \"$VIPSHOME\" again.\n *\n * Rewrite rules can be \"locked\". For example, we don't want the rewrite from\n * \"/home/john\" to \"$HOME\" to ever be removed. \n */\n\ntypedef struct _Rewrite {\n\tchar *old;\n\tchar *new;\n\tgboolean lock;\n} Rewrite; \n\nstatic GSList *rewrite_list = NULL;\n\nstatic void\npath_rewrite_free( Rewrite *rewrite )\n{\n\trewrite_list = g_slist_remove( rewrite_list, rewrite );\n\n\tIM_FREE( rewrite->old ); \n\tIM_FREE( rewrite->new ); \n\tIM_FREE( rewrite ); \n}\n\nvoid\npath_rewrite_free_all( void )\n{\n\twhile( rewrite_list ) { \n\t\tRewrite *rewrite = (Rewrite *) rewrite_list->data; \n\n\t\tIM_FREEF( path_rewrite_free, rewrite );\n\t}\n}\n\nstatic Rewrite *\npath_rewrite_new( const char *old, const char *new, gboolean lock )\n{\n\tRewrite *rewrite;\n\n\trewrite = g_new( Rewrite, 1 );\n\trewrite->old = g_strdup( old );\n\trewrite->new = g_strdup( new );\n\trewrite->lock = lock;\n\trewrite_list = g_slist_prepend( rewrite_list, rewrite );\n\n\treturn( rewrite ); \n}\n\nstatic gint\npath_rewrite_sort_fn( Rewrite *a, Rewrite *b )\n{\n        return( strlen( b->old ) - strlen( a->old ) );\n}\n\nstatic Rewrite *\npath_rewrite_lookup( const char *old )\n{\n\tGSList *p;\n\tRewrite *rewrite;\n\n\tfor( p = rewrite_list; p; p = p->next ) {\n\t\trewrite = (Rewrite *) p->data; \n\n\t\tif( strcmp( old, rewrite->old ) == 0 ) \n\t\t\treturn( rewrite );\n\t}\n\n\treturn( NULL );\n}\n\n/* Add a new rewrite pair to the rewrite list. @new can be NULL, meaning\n * remove a rewrite rule.\n */\nvoid\npath_rewrite_add( const char *old, const char *new, gboolean lock )\n{\n\tchar old_buf[FILENAME_MAX + 1];\n\tchar new_buf[FILENAME_MAX + 1];\n\n\tRewrite *rewrite;\n\n#ifdef DEBUG_REWRITE\n\tprintf( \"path_rewrite_add: old = %s, new = %s, lock = %d\\n\", \n\t\told, new, lock );\n#endif /*DEBUG_REWRITE*/\n\n\tg_return_if_fail( old );\n\n\t/* We want the old path in long form, with a trailing '/'. The\n\t * trailing '/' will stop us rewriting filenames.\n\t *\n\t * If we keep all @old paths in long form we can avoid rewrite loops.\n\t */\n\tim_strncpy( old_buf, old, FILENAME_MAX );\n\tstrcat( old_buf, G_DIR_SEPARATOR_S );\n\tpath_expand( old_buf );\n\told = old_buf;\n\n\tif( new ) {\n\t\t/* We must keep the new path in short (unexpanded) form, \n\t\t * obviously.\n\t\t */\n\t\tim_strncpy( new_buf, new, FILENAME_MAX );\n\t\tstrcat( new_buf, G_DIR_SEPARATOR_S );\n\t\tnew = new_buf;\n\t}\n\n\t/* If old is a prefix of new we will get endless expansion.\n\t */\n\tif( new &&\n\t\tis_prefix( old, new ) )\n\t\treturn; \n\n\tif( (rewrite = path_rewrite_lookup( old )) ) {\n\t\tif( !rewrite->lock &&\n\t\t\t(!new ||\n\t\t\t strcmp( old, new ) == 0) ) {\n#ifdef DEBUG_REWRITE\n\t\t\tprintf( \"path_rewrite_add: removing\\n\" );\n#endif /*DEBUG_REWRITE*/\n\n\t\t\tIM_FREEF( path_rewrite_free, rewrite );\n\t\t}\n\t\telse if( !rewrite->lock &&\n\t\t\tnew ) {\n#ifdef DEBUG_REWRITE\n\t\t\tprintf( \"path_rewrite_add: updating\\n\" );\n#endif /*DEBUG_REWRITE*/\n\n\t\t\tIM_SETSTR( rewrite->new, new );\n\t\t}\n\t\telse {\n#ifdef DEBUG_REWRITE\n\t\t\tprintf( \"path_rewrite_add: rewrite rule locked\\n\" );\n#endif /*DEBUG_REWRITE*/\n\t\t}\n\t}\n\telse if( new &&\n\t\tstrcmp( old, new ) != 0 ) {\n#ifdef DEBUG_REWRITE\n\t\tprintf( \"path_rewrite_add: adding\\n\" );\n#endif /*DEBUG_REWRITE*/\n\n\t\t(void) path_rewrite_new( old, new, lock );\n\t}\n\n\t/* Keep longest old first, in case one old is a prefix of \n\t * another.\n\t */\n\trewrite_list = g_slist_sort( rewrite_list, \n\t\t(GCompareFunc) path_rewrite_sort_fn );\n\n#ifdef DEBUG_REWRITE\n{\n\tGSList *p;\n\n\tprintf( \"path_rewrite_add: state:\\n\" );\n\n\tfor( p = rewrite_list; p; p = p->next ) {\n\t\trewrite = (Rewrite *) p->data; \n\n\t\tprintf( \"\\told = %s, new = %s\\n\", rewrite->old, rewrite->new );\n\t}\n}\n#endif /*DEBUG_REWRITE*/\n}\n\n/* Rewrite a string using the rewrite list. buf must be FILENAME_MAX\n * characters.\n */\nvoid\npath_rewrite( char *buf )\n{\n\tGSList *p;\n\tgboolean changed;\n\n#ifdef DEBUG_REWRITE\n\tprintf( \"path_rewrite: %s\\n\", buf );\n#endif /*DEBUG_REWRITE*/\n\n\tdo { \n\t\tchanged = FALSE;\n\n\t\tfor( p = rewrite_list; p; p = p->next ) {\n\t\t\tRewrite *rewrite = (Rewrite *) p->data; \n\n\t\t\tif( is_prefix( rewrite->old, buf ) ) {\n\t\t\t\tint olen = strlen( rewrite->old );\n\t\t\t\tint nlen = strlen( rewrite->new );\n\t\t\t\tint blen = strlen( buf );\n\n\t\t\t\tif( blen - olen + nlen > FILENAME_MAX - 3 )\n\t\t\t\t\tbreak;\n\n\t\t\t\tmemmove( buf + nlen, buf + olen, \n\t\t\t\t\tblen - olen + 1 );\n\t\t\t\tmemcpy( buf, rewrite->new, nlen );\n\n\t\t\t\tchanged = TRUE;\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} while( changed );\n\n#ifdef DEBUG_REWRITE\n\tprintf( \"\\t-> %s\\n\", buf );\n#endif /*DEBUG_REWRITE*/\n}\n\n/* The inverse: rewrite in long form ready for file ops.\n */\nvoid\npath_expand( char *path )\n{\n\tchar buf[FILENAME_MAX];\n\n\texpand_variables( path, buf );\n\tnativeize_path( buf );\n\tabsoluteize_path( buf );\n\tcanonicalize_path( buf );\n\tim_strncpy( path, buf, FILENAME_MAX );\n}\n\n/* Rewite a path to compact form. @path must be FILENAME_MAX characters.\n *\n * Examples:\n *\n * \t/home/john/../somefile \t\t-> $HOME/../somefile\n * \t/home/./john/../somefile \t-> $HOME/../somefile\n * \tfred\t\t\t\t-> ./fred\n */\nvoid\npath_compact( char *path )\n{\n\tpath_expand( path );\n\tpath_rewrite( path );\n}\n\n/* Turn a search path (eg. \"/pics/lr:/pics/hr\") into a list of directory names.\n */\nGSList *\npath_parse( const char *path )\n{\n\tGSList *op = NULL;\n\tconst char *p;\n\tconst char *e;\n\tint len;\n\tchar name[FILENAME_MAX + 1];\n\n\tfor( p = path; *p; p = e ) {\n\t\t/* Find the start of the next component, or the NULL\n\t\t * character.\n\t\t */\n\t\tif( !(e = strchr( p, G_SEARCHPATH_SEPARATOR )) )\n\t\t\te = p + strlen( p );\n\t\tlen = e - p + 1;\n\n\t\t/* Copy to our buffer, turn to string.\n\t\t */\n\t\tim_strncpy( name, p, IM_MIN( len, FILENAME_MAX ) );\n\n\t\t/* Add to path list.\n\t\t */\n\t\top = g_slist_append( op, im_strdupn( name ) );\n\n\t\t/* Skip G_SEARCHPATH_SEPARATOR.\n\t\t */\n\t\tif( *e == G_SEARCHPATH_SEPARATOR )\n\t\t\te++;\n\t}\n\n\treturn( op );\n}\n\n/* Free a path. path_free() is reserved n OS X :(\n */\nvoid\npath_free2( GSList *path )\n{\n\tslist_map( path, (SListMapFn) im_free, NULL );\n\tg_slist_free( path );\n}\n\n/* Sub-fn of below. Add length of this string + 1 (for ':').\n */\nstatic int\npath_add_component( const char *str, int c )\n{\n\treturn( c + strlen( str ) + 1 );\n}\n\n/* Sub-fn of below. Copy string to buffer, append ':', return new end.\n */\nstatic char *\npath_add_string( const char *str, char *buf )\n{\n\tstrcpy( buf, str );\n\tstrcat( buf, G_SEARCHPATH_SEPARATOR_S );\n\n\treturn( buf + strlen( buf ) );\n}\n\n/* Turn a list of directory names into a search path.\n */\nchar *\npath_unparse( GSList *path )\n{\t\n\tint len = GPOINTER_TO_INT( slist_fold( path, 0, \n\t\t (SListFoldFn) path_add_component, NULL ) );\n\tchar *buf = imalloc( NULL, len + 1 );\n\n\t/* Build new string.\n\t */\n\tslist_fold( path, buf, (SListFoldFn) path_add_string, NULL );\n\n\t/* Fix '\\0' to remove trailing G_SEARCHPATH_SEPARATOR.\n\t */\n\tif( len > 0 )\n\t\tbuf[len - 1] = '\\0';\n\n\treturn( buf );\n}\n\n/* Track this stuff during a file search.\n */\ntypedef struct _Search {\n\t/* Pattern we search for, and it's compiled form. This does not\n\t * include any directory components. \n\t */\n\tchar *basename;\n\tGPatternSpec *wild;\n\n\t/* Directory offset. If the original pattern is a relative path, eg.\n\t * \"poop/x*.v\", we search every directory on path for a subdirectory\n\t * called \"poop\" and then search all files within that.\n\t */\n\tchar *dirname; \n\n\t/* User function to call for every matching file.\n\t */\n\tpath_map_fn fn;\n\tvoid *a;\n\n\t/* Files we've previously offered to the user function: we remove\n\t * duplicates. So \"path1/wombat.def\" hides \"path2/wombat.def\".\n\t */\n\tGSList *previous;\n} Search;\n\nstatic void\npath_search_free( Search *search )\n{\n\tIM_FREEF( g_free, search->basename );\n\tIM_FREEF( g_free, search->dirname );\n\tIM_FREEF( slist_free_all, search->previous );\n\tIM_FREEF( g_pattern_spec_free, search->wild );\n}\n\nstatic gboolean\npath_search_init( Search *search, const char *patt, path_map_fn fn, void *a )\n{\n\tsearch->basename = g_path_get_basename( patt );\n\tsearch->dirname = g_path_get_dirname( patt );\n\tsearch->wild = NULL;\n\tsearch->fn = fn;\n\tsearch->a = a;\n\tsearch->previous = NULL;\n\n\tif( !(search->wild = g_pattern_spec_new( search->basename )) ) {\n\t\tpath_search_free( search );\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic void *\npath_str_eq( const char *s1, const char *s2 )\n{\n        if( strcmp( s1, s2 ) == 0 )\n                return( (void *) s1 );\n        else\n                return( NULL );\n}\n\n/* Test for string matches pattern. If the match is successful, call a user \n * function.\n */\nstatic void *\npath_search_match( Search *search, const char *dir_name, const char *name )\n{\n\tif( g_pattern_match_string( search->wild, name ) &&\n\t\t!slist_map( search->previous, \n\t\t\t(SListMapFn) path_str_eq, (gpointer) name ) ) {\n\t\tchar buf[FILENAME_MAX + 10];\n\t\tvoid *result;\n\n\t\t/* Add to exclusion list.\n\t\t */\n\t\tsearch->previous = \n\t\t\tg_slist_prepend( search->previous, g_strdup( name ) );\n\n\t\tim_snprintf( buf, FILENAME_MAX, \n\t\t\t\"%s\" G_DIR_SEPARATOR_S \"%s\", dir_name, name );\n\n\t\tpath_compact( buf );\n\n#ifdef DEBUG_SEARCH\n\t\tprintf( \"path_search_match: matched \\\"%s\\\"\\n\", buf );\n#endif /*DEBUG_SEARCH*/\n\n\t\tif( (result = search->fn( buf, search->a, NULL, NULL )) )\n\t\t\treturn( result );\n\t}\n\n\treturn( NULL );\n}\n\n/* Scan a directory, calling a function for every entry. Abort scan if \n * function returns non-NULL.\n */\nstatic void *\npath_scan_dir( const char *dir_name, Search *search )\n{\n\tchar buf[FILENAME_MAX];\n\tGDir *dir;\n\tconst char *name;\n\tvoid *result;\n\n\t/* Add the pattern offset, if any. It's '.' for no offset.\n\t */\n\tim_snprintf( buf, FILENAME_MAX, \n\t\t\"%s\" G_DIR_SEPARATOR_S \"%s\", dir_name, search->dirname );\n\n\tif( !(dir = (GDir *) callv_string_filename( \n\t\t(callv_string_fn) g_dir_open, buf, NULL, NULL, NULL )) ) \n\t\treturn( NULL );\n\n\twhile( (name = g_dir_read_name( dir )) ) \n\t\tif( (result = path_search_match( search, buf, name )) ) {\n\t\t\tg_dir_close( dir );\n\t\t\treturn( result );\n\t\t}\n\n\tg_dir_close( dir );\n\n\treturn( NULL );\n}\n\n/* Scan a search path, applying a function to every file name which matches a\n * pattern. If the user function returns NULL, keep looking, otherwise return\n * its result. We return NULL on error, or if the user function returns NULL\n * for all filenames which match. \n *\n * Remove duplicates: if fred.wombat is in the first and second dirs on the\n * path, only apply to the first occurence.\n\n \tFIXME ... speed up with a hash and a (date based) cache at some point\n\n */\nvoid *\npath_map( GSList *path, const char *patt, path_map_fn fn, void *a )\n{\n\tSearch search;\n\tvoid *result;\n\n#ifdef DEBUG_SEARCH\n\tprintf( \"path_map: searching for \\\"%s\\\"\\n\", patt );\n#endif /*DEBUG_SEARCH*/\n\n\tif( !path_search_init( &search, patt, fn, a ) )\n\t\treturn( NULL );\n\n\tresult = slist_map( path, (SListMapFn) path_scan_dir, &search );\n\n\tpath_search_free( &search );\n\n\treturn( result );\n}\n\n/* As above, but scan a single directory.\n */\nvoid *\npath_map_dir( const char *dir, const char *patt, path_map_fn fn, void *a )\n{\n\tSearch search;\n\tvoid *result;\n\n#ifdef DEBUG_SEARCH\n\tprintf( \"path_map_dir: searching for \\\"%s\\\"\\n\", patt );\n#endif /*DEBUG_SEARCH*/\n\n\tif( !path_search_init( &search, patt, fn, a ) )\n\t\treturn( NULL );\n\n\tif( !(result = path_scan_dir( dir, &search )) ) {\n\t\t/* Not found? Maybe - error message anyway.\n\t\t */\n\t\terror_top( _( \"Not found.\" ) );\n\t\terror_sub( _( \"File \\\"%s\\\" not found.\" ), patt );\n\t}\n\n\tpath_search_free( &search );\n\n\treturn( result );\n}\n\n/* Search for a file on the search path. \n */\nchar *\npath_find_file( const char *filename )\n{\n\tchar *fname;\n\n#ifdef DEBUG_SEARCH\n\tprintf( \"path_find_file: \\\"%s\\\"\\n\", filename );\n#endif /*DEBUG_SEARCH*/\n\n\t/* Try file name exactly.\n\t */\n\tif( existsf( \"%s\", filename ) )\n\t\treturn( im_strdupn( filename ) );\n\n\t/* Search everywhere.\n\t */\n\tif( (fname = path_map( PATH_SEARCH, filename,\n\t\t(path_map_fn) im_strdupn, NULL )) )\n\t\treturn( fname );\n\t\n\terror_top( _( \"Not found.\" ) );\n\terror_sub( _( \"File \\\"%s\\\" not found on path\" ), filename );\n\n\treturn( NULL );\n}\n\nvoid\npath_init( void )\n{\n\tchar buf[FILENAME_MAX];\n\n\tpath_rewrite_add( get_prefix(), \"$VIPSHOME\", TRUE );\n\tpath_rewrite_add( g_get_home_dir(), \"$HOME\", TRUE );\n\tpath_rewrite_add( get_savedir(), \"$SAVEDIR\", TRUE );\n\n\t/* You might think we could add a rule to swap '.' for \n\t * g_get_current_dir(), but that would then make workspaces depend on\n\t * a certain value of cwd before they could work.\n\t */\n\n\t/* And the expanded form too.\n\t */\n\texpand_variables( get_savedir(), buf );\n\tpath_rewrite_add( buf, \"$SAVEDIR\", TRUE );\n\n#ifdef DEBUG_LOCAL\n\tprintf( \"path_init: loading start from \\\".\\\" only\\n\" );\n\tpath_start_default = path_parse( \".\" );\n\tpath_search_default = path_parse( \".\" );\n\tpath_tmp_default = im_strdup( NULL, \".\" );\n#else /*!DEBUG_LOCAL*/\n\tim_snprintf( buf, FILENAME_MAX,\n\t\t\"%s\" G_DIR_SEPARATOR_S \"start\" G_SEARCHPATH_SEPARATOR_S\n\t\t\"$VIPSHOME\" G_DIR_SEPARATOR_S \"share\" G_DIR_SEPARATOR_S\n\t\t\"$PACKAGE\" G_DIR_SEPARATOR_S \"start\",\n\t\tget_savedir() );\n\tpath_start_default = path_parse( buf );\n\n\tim_snprintf( buf, FILENAME_MAX,\n\t\t\"%s\" G_DIR_SEPARATOR_S \"data\" G_SEARCHPATH_SEPARATOR_S\n\t\t\"$VIPSHOME\" G_DIR_SEPARATOR_S \"share\" G_DIR_SEPARATOR_S \n\t\t\"$PACKAGE\" G_DIR_SEPARATOR_S \"data\" G_SEARCHPATH_SEPARATOR_S \n\t\t\".\",\n\t\tget_savedir() );\n\tpath_search_default = path_parse( buf );\n\n\tim_snprintf( buf, FILENAME_MAX, \n\t\t\"%s\" G_DIR_SEPARATOR_S \"tmp\", get_savedir() );\n\tpath_tmp_default = im_strdup( NULL, buf );\n#endif /*DEBUG_LOCAL*/\n}\n"
  },
  {
    "path": "src/path.h",
    "content": "/* Declarations supporting search.c\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\nextern GSList *path_search_default;\nextern GSList *path_start_default;\nextern const char *path_tmp_default;\n\n/* Type of path_map functions.\n */\ntypedef void *(*path_map_fn)( const char *, void *, void *, void * );\n\nvoid path_rewrite_free_all( void );\nvoid path_rewrite_add( const char *old, const char *new, gboolean lock );\nvoid path_rewrite( char *buf );\nvoid path_compact( char *path );\nvoid path_expand( char *path );\nchar *path_rewrite_file( const char *patt );\n\nGSList *path_parse( const char *path );\nchar *path_unparse( GSList *path );\nvoid path_free2( GSList *path );\nvoid *path_map( GSList *path, const char *patt, path_map_fn fn, void *a );\nvoid *path_map_dir( const char *dir, const char *patt, \n\tpath_map_fn fn, void *a );\nchar *path_find_file( const char *patt );\n\nvoid path_init( void );\n"
  },
  {
    "path": "src/pathname.c",
    "content": "/* an input pathname ... put/get methods\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic void\npathname_dispose( GObject *gobject )\n{\n\tPathname *pathname = PATHNAME( gobject );\n\n#ifdef DEBUG\n\tprintf( \"pathname_dispose\\n\" );\n#endif /*DEBUG*/\n\n\tIM_FREE( pathname->value );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic View *\npathname_view_new( Model *model, View *parent )\n{\n\treturn( pathnameview_new() );\n}\n\nstatic void *\npathname_update_model( Heapmodel *heapmodel )\n{\n#ifdef DEBUG\n\tprintf( \"pathname_update_model\\n\" );\n#endif /*DEBUG*/\n\n\tif( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) )\n\t\treturn( heapmodel );\n\n\treturn( NULL );\n}\n\n/* Members of pathname we automate.\n */\nstatic ClassmodelMember pathname_members[] = {\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_CAPTION, \"caption\", N_( \"Caption\" ),\n\t\tG_STRUCT_OFFSET( iObject, caption ) },\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_VALUE, \"value\", N_( \"Value\" ),\n\t\tG_STRUCT_OFFSET( Pathname, value ) }\n};\n\nstatic void\npathname_class_init( PathnameClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tHeapmodelClass *heapmodel_class = (HeapmodelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->dispose = pathname_dispose;\n\n\tmodel_class->view_new = pathname_view_new;\n\n\theapmodel_class->update_model = pathname_update_model;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n\n\tclassmodel_class->members = pathname_members;\n\tclassmodel_class->n_members = IM_NUMBER( pathname_members );\n}\n\nstatic void\npathname_init( Pathname *pathname )\n{\n\t/* Overridden later. Just something sensible.\n\t */\n\tpathname->value = NULL;\n\tIM_SETSTR( pathname->value, \"no-file\" );\n\n\tiobject_set( IOBJECT( pathname ), CLASS_PATHNAME, NULL );\n}\n\nGType\npathname_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( PathnameClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) pathname_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Pathname ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) pathname_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"Pathname\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/pathname.h",
    "content": "/* a pathname in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_PATHNAME (pathname_get_type())\n#define PATHNAME( obj ) (GTK_CHECK_CAST( (obj), TYPE_PATHNAME, Pathname ))\n#define PATHNAME_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_PATHNAME, PathnameClass ))\n#define IS_PATHNAME( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PATHNAME ))\n#define IS_PATHNAME_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PATHNAME ))\n\ntypedef struct _Pathname {\n\tClassmodel model;\n\n\tchar *value;\n} Pathname;\n\ntypedef struct _PathnameClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} PathnameClass;\n\nGType pathname_get_type( void );\n"
  },
  {
    "path": "src/pathnameview.c",
    "content": "/* run the display for an arrow in a workspace \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GraphicviewClass *parent_class = NULL;\n\nstatic void\npathnameview_link( View *view, Model *model, View *parent )\n{\n\tPathnameview *pathnameview = PATHNAMEVIEW( view );\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\tif( GRAPHICVIEW( view )->sview )\n\t\tgtk_size_group_add_widget( GRAPHICVIEW( view )->sview->group,   \n\t\t\tpathnameview->label );\n}\n\nstatic void \npathnameview_refresh( vObject *vobject )\n{\n\tPathnameview *pathnameview = PATHNAMEVIEW( vobject );\n\tPathname *pathname = PATHNAME( VOBJECT( vobject )->iobject );\n\n#ifdef DEBUG\n\tprintf( \"pathnameview_refresh: \" );\n\trow_name_print( HEAPMODEL( pathname )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( vobject->iobject->caption )\n\t\tset_glabel( pathnameview->label, _( \"%s:\" ), \n\t\t\tvobject->iobject->caption );\n\tif( pathname->value ) \n\t\tgtk_button_set_label( GTK_BUTTON( pathnameview->button ), \n\t\t\tim_skip_dir( pathname->value ) );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\npathnameview_class_init( PathnameviewClass *class )\n{\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = pathnameview_refresh;\n\n\tview_class->link = pathnameview_link;\n}\n\nstatic void\npathnameview_edit_ok( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( iwnd );\n\tPathname *pathname = PATHNAME( client );\n\tchar *fname;\n\n\tif( (fname = filesel_get_filename( filesel )) ) {\n\t\tIM_SETSTR( pathname->value, fname );\n\t\tclassmodel_update( CLASSMODEL( pathname ) );\n\t\tsymbol_recalculate_all();\n\n\t\tg_free( fname );\n\n\t\tnfn( sys, IWINDOW_YES );\n\t}\n\telse\n\t\tnfn( sys, IWINDOW_ERROR );\n}\n\nstatic void\npathnameview_clicked_cb( GtkWidget *widget, Pathnameview *pathnameview )\n{\n\tPathname *pathname = PATHNAME( VOBJECT( pathnameview )->iobject );\n\tGtkWidget *filesel = filesel_new();\n\n\tiwindow_set_title( IWINDOW( filesel ), \n\t\t\"%s\", IOBJECT( pathname )->caption );\n\tfilesel_set_flags( FILESEL( filesel ), TRUE, FALSE );\n\tfilesel_set_filetype( FILESEL( filesel ), filesel_type_any, 0 );\n\tiwindow_set_parent( IWINDOW( filesel ), widget );\n\tidialog_set_iobject( IDIALOG( filesel ), IOBJECT( pathname ) );\n\tfilesel_set_done( FILESEL( filesel ), pathnameview_edit_ok, pathname );\n\tiwindow_build( IWINDOW( filesel ) );\n\tfilesel_set_filename( FILESEL( filesel ), pathname->value );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\nstatic void\npathnameview_init( Pathnameview *pathnameview )\n{\n\tGtkWidget *hbox;\n\n#ifdef DEBUG\n\tprintf( \"pathnameview_init\\n\" );\n#endif /*DEBUG*/\n\n\thbox = gtk_hbox_new( FALSE, 12 );\n        gtk_box_pack_start( GTK_BOX( pathnameview ), hbox, TRUE, FALSE, 0 );\n\n        pathnameview->label = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( pathnameview->label ), 0, 0.5 );\n        gtk_misc_set_padding( GTK_MISC( pathnameview->label ), 2, 7 );\n\tgtk_box_pack_start( GTK_BOX( hbox ), \n\t\tpathnameview->label, FALSE, FALSE, 2 );\n\n\tpathnameview->button = gtk_button_new_with_label( \"\" );\n        gtk_box_pack_start( GTK_BOX( hbox ), pathnameview->button, \n\t\tTRUE, TRUE, 0 );\n        gtk_signal_connect( GTK_OBJECT( pathnameview->button ), \"clicked\",\n                GTK_SIGNAL_FUNC( pathnameview_clicked_cb ), pathnameview );\n        set_tooltip( pathnameview->button, _( \"Select a new file name\" ) );\n\n        gtk_widget_show_all( GTK_WIDGET( hbox ) );\n}\n\nGtkType\npathnameview_get_type( void )\n{\n\tstatic GtkType pathnameview_type = 0;\n\n\tif( !pathnameview_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Pathnameview\",\n\t\t\tsizeof( Pathnameview ),\n\t\t\tsizeof( PathnameviewClass ),\n\t\t\t(GtkClassInitFunc) pathnameview_class_init,\n\t\t\t(GtkObjectInitFunc) pathnameview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tpathnameview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info );\n\t}\n\n\treturn( pathnameview_type );\n}\n\nView *\npathnameview_new( void )\n{\n\tPathnameview *pathnameview = gtk_type_new( TYPE_PATHNAMEVIEW );\n\n\treturn( VIEW( pathnameview ) );\n}\n"
  },
  {
    "path": "src/pathnameview.h",
    "content": "/* a pathname view in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_PATHNAMEVIEW (pathnameview_get_type())\n#define PATHNAMEVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_PATHNAMEVIEW, Pathnameview ))\n#define PATHNAMEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_PATHNAMEVIEW, PathnameviewClass ))\n#define IS_PATHNAMEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PATHNAMEVIEW ))\n#define IS_PATHNAMEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PATHNAMEVIEW ))\n\ntypedef struct _Pathnameview {\n\tGraphicview parent_object;\n\n\tGtkWidget *label;\n\tGtkWidget *button;\n} Pathnameview;\n\ntypedef struct _PathnameviewClass {\n\tGraphicviewClass parent_class;\n\n\t/* My methods.\n\t */\n} PathnameviewClass;\n\nGtkType pathnameview_get_type( void );\nView *pathnameview_new( void );\n"
  },
  {
    "path": "src/plot.c",
    "content": "/* an input plot \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic void\nplot_free_columns( Plot *plot )\n{\n\tint i;\n\n\tfor( i = 0; i < plot->columns; i++ ) {\n\t\tIM_FREE( plot->xcolumn[i] );\n\t\tIM_FREE( plot->ycolumn[i] );\n\t}\n\tIM_FREE( plot->xcolumn );\n\tIM_FREE( plot->ycolumn );\n\tplot->columns = 0;\n\tplot->rows = 0;\n}\n\nstatic void\nplot_finalize( GObject *gobject )\n{\n\tPlot *plot;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_PLOT( gobject ) );\n\n\tplot = PLOT( gobject );\n\n#ifdef DEBUG\n\tprintf( \"plot_finalize\\n\" );\n#endif /*DEBUG*/\n\n\t/* My instance finalize stuff.\n\t */\n\timage_value_destroy( &plot->value );\n\tplot_free_columns( plot );\n\tvips_buf_destroy( &plot->caption_buffer );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nchar *\nplot_f2c( PlotFormat format )\n{\n\tswitch( format ) {\n\tcase PLOT_FORMAT_YYYY: return( _( \"YYYY\" ) );\n\tcase PLOT_FORMAT_XYYY: return( _( \"XYYY\" ) );\n\tcase PLOT_FORMAT_XYXY: return( _( \"XYXY\" ) );\n\n\tdefault:\n\t\tg_assert( 0 );\n\t\t\n\t\t/* Keep gcc happy.\n\t\t */\n\t\treturn( 0 );\n\t}\n}\n\nchar *\nplot_s2c( PlotStyle style )\n{\n\tswitch( style ) {\n\tcase PLOT_STYLE_POINT:\treturn( _( \"Point\" ) );\n\tcase PLOT_STYLE_LINE:\treturn( _( \"Line\" ) );\n\tcase PLOT_STYLE_SPLINE:\treturn( _( \"Spline\" ) );\n\tcase PLOT_STYLE_BAR:\treturn( _( \"Bar\" ) );\n\n\tdefault:\n\t\tg_assert( 0 );\n\t\t\n\t\t/* Keep gcc happy.\n\t\t */\n\t\treturn( 0 );\n\t}\n}\n\nstatic const char *\nplot_generate_caption( iObject *iobject )\n{\n\tPlot *plot = PLOT( iobject );\n\tVipsBuf *buf = &plot->caption_buffer;\n\n\tvips_buf_rewind( buf );\n\timage_value_caption( &plot->value, buf );\n\tvips_buf_appendf( buf, \", %d series, %d points\", \n\t\t\tplot->columns, plot->rows );\n\tvips_buf_appendf( buf, \", xrange [%g, %g]\", plot->xmin, plot->xmax );\n\tvips_buf_appendf( buf, \", yrange [%g, %g]\", plot->ymin, plot->ymax );\n\n\treturn( vips_buf_all( buf ) );\n}\n\n/* Unpack all data formats to XYXYXY.\n *\n * \tFIXME ... could save mem by reusing columns of Xes in YYYY and XYYY\n * \tcases\n */\nstatic gboolean\nplot_unpack( Plot *plot, DOUBLEMASK *mask )\n{\n\tint rows, columns;\n\tint r, c;\n\tdouble xmin, xmax;\n\tdouble ymin, ymax;\n\n\trows = mask->ysize;\n\tswitch( plot->format ) {\n\tcase PLOT_FORMAT_YYYY:\n\t\tcolumns = mask->xsize;\n\t\tbreak;\n\n\tcase PLOT_FORMAT_XYYY:\n\t\tif( mask->xsize < 2 ) {\n\t\t\terror_top( _( \"Bad value.\" ) );\n\t\t\terror_sub( _( \"More than one column \"\n\t\t\t\t\"needed or XY plots\" ) );\n\t\t\treturn( FALSE );\n\t\t}\n\t\tcolumns = mask->xsize - 1;\n\t\tbreak;\n\n\tcase PLOT_FORMAT_XYXY:\n\t\tif( (mask->xsize & 1) != 0 ) {\n\t\t\terror_top( _( \"Bad value.\" ) );\n\t\t\terror_sub( _( \"Even number of columns only for \"\n\t\t\t\t\"XY format plots\" ) );\n\t\t\treturn( FALSE );\n\t\t}\n\t\tcolumns = mask->xsize / 2;\n\t\tbreak;\n\n\tdefault:\n\t\tcolumns = 1;\n\t\tg_assert( 0 );\n\t}\n\n\tif( plot->columns != columns || plot->rows != rows ) {\n\t\tplot_free_columns( plot );\n\n\t\tplot->xcolumn = IM_ARRAY( NULL, columns, double * );\n\t\tplot->ycolumn = IM_ARRAY( NULL, columns, double * );\n\n\t\tif( !plot->xcolumn || !plot->ycolumn ) {\n\t\t\tplot_free_columns( plot );\n\t\t\treturn( FALSE );\n\t\t}\n\t\tplot->columns = columns;\n\t\tplot->rows = rows;\n\n\t\tfor( c = 0; c < columns; c++ ) {\n\t\t\tplot->xcolumn[c] = NULL;\n\t\t\tplot->ycolumn[c] = NULL;\n\t\t}\n\n\t\tfor( c = 0; c < columns; c++ ) {\n\t\t\tplot->xcolumn[c] = IM_ARRAY( NULL, rows, double );\n\t\t\tplot->ycolumn[c] = IM_ARRAY( NULL, rows, double );\n\t\t\tif( !plot->xcolumn[c] || !plot->ycolumn[c] ) {\n\t\t\t\tplot_free_columns( plot );\n\t\t\t\treturn( FALSE );\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch( plot->format ) {\n\tcase PLOT_FORMAT_YYYY:\n\t\tfor( c = 0; c < columns; c++ )\n\t\t\tfor( r = 0; r < rows; r++ ) {\n\t\t\t\tplot->xcolumn[c][r] = r;\n\t\t\t\tplot->ycolumn[c][r] = \n\t\t\t\t\tmask->coeff[c + r * mask->xsize];\n\t\t\t}\n\t\tbreak;\n\n\tcase PLOT_FORMAT_XYYY:\n\t\tfor( c = 0; c < columns; c++ )\n\t\t\tfor( r = 0; r < rows; r++ ) {\n\t\t\t\tplot->xcolumn[c][r] = \n\t\t\t\t\tmask->coeff[r * mask->xsize];\n\t\t\t\tplot->ycolumn[c][r] = \n\t\t\t\t\tmask->coeff[c + 1 + r * mask->xsize];\n\t\t\t}\n\t\tbreak;\n\n\tcase PLOT_FORMAT_XYXY:\n\t\tfor( c = 0; c < columns; c++ )\n\t\t\tfor( r = 0; r < rows; r++ ) {\n\t\t\t\tplot->xcolumn[c][r] = \n\t\t\t\t\tmask->coeff[c * 2 + r * mask->xsize];\n\t\t\t\tplot->ycolumn[c][r] = \n\t\t\t\t\tmask->coeff[c * 2 + 1 + \n\t\t\t\t\t\tr * mask->xsize];\n\t\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( 0 );\n\t}\n\n\txmin = plot->xcolumn[0][0];\n\txmax = plot->xcolumn[0][0];\n\tymin = plot->ycolumn[0][0];\n\tymax = plot->ycolumn[0][0];\n\n\tfor( c = 0; c < columns; c++ )\n\t\tfor( r = 0; r < rows; r++ ) {\n\t\t\tif( plot->xcolumn[c][r] > xmax )\n\t\t\t\txmax = plot->xcolumn[c][r];\n\t\t\tif( plot->xcolumn[c][r] < xmin )\n\t\t\t\txmin = plot->xcolumn[c][r];\n\t\t\tif( plot->ycolumn[c][r] > ymax )\n\t\t\t\tymax = plot->ycolumn[c][r];\n\t\t\tif( plot->ycolumn[c][r] < ymin )\n\t\t\t\tymin = plot->ycolumn[c][r];\n\t\t}\n\n\tif( plot->xmin == PLOT_RANGE_UNSET )\n\t\tplot->xmin = xmin;\n\tif( plot->xmax == PLOT_RANGE_UNSET )\n\t\tplot->xmax = xmax;\n\tif( plot->ymin == PLOT_RANGE_UNSET )\n\t\tplot->ymin = ymin;\n\tif( plot->ymax == PLOT_RANGE_UNSET )\n\t\tplot->ymax = ymax;\n\n\treturn( TRUE );\n}\n\n#ifdef HAVE_LIBGOFFICE\nstatic View *\nplot_view_new( Model *model, View *parent )\n{\n\treturn( plotview_new() );\n\treturn( NULL );\n}\n#endif /*HAVE_LIBGOFFICE*/\n\nstatic void\nplot_edit( GtkWidget *parent, Model *model )\n{\n#ifdef HAVE_LIBGOFFICE\n        Plot *plot = PLOT( model );\n\tPlotwindow *plotwindow;\n\n\tplotwindow = plotwindow_new( plot, parent );\n\n\tgtk_widget_show( GTK_WIDGET( plotwindow ) );\n#endif /*HAVE_LIBGOFFICE*/\n}\n\nstatic xmlNode *\nplot_save( Model *model, xmlNode *xnode )\n{\n        Plot *plot = PLOT( model );\n\txmlNode *xthis;\n\n\tif( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )\n\t\treturn( NULL );\n\n\tif( !set_iprop( xthis, \"plot_left\", plot->left ) ||\n\t\t!set_iprop( xthis, \"plot_top\", plot->top ) ||\n\t\t!set_iprop( xthis, \"plot_mag\", plot->mag ) ||\n\t\t!set_sprop( xthis, \"show_status\", \n\t\t\tbool_to_char( plot->show_status ) ) )\n\t\treturn( NULL );\n\n\treturn( xthis );\n}\n\nstatic gboolean\nplot_load( Model *model, \n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n        Plot *plot = PLOT( model );\n\n\tg_assert( IS_RHS( parent ) );\n\n\t(void) get_iprop( xnode, \"plot_left\", &plot->left );\n\t(void) get_iprop( xnode, \"plot_top\", &plot->top );\n\t(void) get_iprop( xnode, \"plot_mag\", &plot->mag );\n\t(void) get_bprop( xnode, \"show_status\", &plot->show_status );\n\n\treturn( MODEL_CLASS( parent_class )->load( model, \n\t\tstate, parent, xnode ) );\n}\n\n/* Members of plot we automate.\n */\nstatic ClassmodelMember plot_options[] = {\n\t{ CLASSMODEL_MEMBER_ENUM, NULL, PLOT_FORMAT_LAST - 1,\n\t\t\"format\", \"format\", N_( \"Format\" ),\n\t\tG_STRUCT_OFFSET( Plot, format ) },\n\t{ CLASSMODEL_MEMBER_ENUM, NULL, PLOT_STYLE_LAST - 1,\n\t\t\"style\", \"style\", N_( \"Style\" ),\n\t\tG_STRUCT_OFFSET( Plot, style ) },\n\t{ CLASSMODEL_MEMBER_DOUBLE, NULL, 0,\n\t\t\"xmin\", \"xmin\", N_( \"Xmin\" ),\n\t\tG_STRUCT_OFFSET( Plot, xmin ) },\n\t{ CLASSMODEL_MEMBER_DOUBLE, NULL, 0,\n\t\t\"xmax\", \"xmax\", N_( \"Xmax\" ),\n\t\tG_STRUCT_OFFSET( Plot, xmax ) },\n\t{ CLASSMODEL_MEMBER_DOUBLE, NULL, 0,\n\t\t\"ymin\", \"ymin\", N_( \"Ymin\" ),\n\t\tG_STRUCT_OFFSET( Plot, ymin ) },\n\t{ CLASSMODEL_MEMBER_DOUBLE, NULL, 0,\n\t\t\"ymax\", \"ymax\", N_( \"Ymax\" ),\n\t\tG_STRUCT_OFFSET( Plot, ymax ) },\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_CAPTION, \"caption\", N_( \"Caption\" ),\n\t\tG_STRUCT_OFFSET( Plot, caption ) },\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_XCAPTION, \"xcaption\", N_( \"X Axis Caption\" ),\n\t\tG_STRUCT_OFFSET( Plot, xcaption ) },\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_YCAPTION, \"ycaption\", N_( \"Y Axis Caption\" ),\n\t\tG_STRUCT_OFFSET( Plot, ycaption ) },\n\t{ CLASSMODEL_MEMBER_STRING_LIST, NULL, 0,\n\t\tMEMBER_SERIES_CAPTIONS, \"series_captions\", \n\t\t\tN_( \"Series Captions\" ),\n\t\tG_STRUCT_OFFSET( Plot, series_captions ) }\n\n};\n\nstatic ClassmodelMember plot_members[] = {\n\t{ CLASSMODEL_MEMBER_OPTIONS, &plot_options, IM_NUMBER( plot_options ), \n\t\tMEMBER_OPTIONS, NULL, N_( \"Options\" ),\n\t\t0 },\n\t{ CLASSMODEL_MEMBER_IMAGE, NULL, 0,\n\t\tMEMBER_VALUE, \"value\", N_( \"Value\" ),\n\t\tG_STRUCT_OFFSET( Plot, value ) }\n};\n\n/* Come here after we've read in new values from the heap.\n */\nstatic gboolean\nplot_class_get( Classmodel *classmodel, PElement *root )\n{\n\tPlot *plot = PLOT( classmodel );\n\tImageValue *value = &plot->value;\n\tIMAGE *im = imageinfo_get( FALSE, value->ii );\n\tImageinfo *ii2;\n\tIMAGE *t;\n\tDOUBLEMASK *mask;\n\tint (*fn)(VipsImage *, VipsImage *);\n\n\t/* nx1 or 1xm images only ... use Bands for columns.\n\t */\n\tif( im->Xsize != 1 && im->Ysize != 1 ) {\n\t\terror_top( _( \"Bad value.\" ) );\n\t\terror_sub( _( \"1xn or nx1 images only for Plot\" ) );\n\t\treturn( FALSE );\n\t}\n\n\t/* Don't ref this and it'll be removed on the next GC.\n\t */\n\tif( !(ii2 = imageinfo_new_temp( main_imageinfogroup, \n\t\treduce_context->heap, NULL, \"p\" )) ) \n\t\treturn( FALSE );\n\tt = imageinfo_get( FALSE, ii2 );\n\n\t/* Rotate so that our mask will be in the correct orientation.\n\t */\n\tif( im->Ysize == 1 )\n\t\tfn = im_rot90;\n\telse\n\t\tfn = im_copy;\n\tif( fn( im, t ) ) {\n\t\terror_top( _( \"Bad value.\" ) );\n\t\terror_sub( _( \"Unable to prepare image.\" ) );\n\t\terror_vips();\n\n\t\treturn( FALSE );\n\t}\n\n\t/* Unpack the image to a dmask, then unpack the dmask into a set of XY\n\t * columns.\n\t *\n\t * \tFIXME ... yuk!\n\t */\n\tif( !(mask = im_vips2mask( t, \"plot_class_get\" )) ) {\n\t\terror_top( _( \"Bad value.\" ) );\n\t\terror_sub( _( \"1xn or nx1 images only\" ) );\n\t\terror_vips();\n\n\t\treturn( FALSE );\n\t}\n\tif( !plot_unpack( plot, mask ) ) {\n\t\tim_free_dmask( mask );\n\t\treturn( FALSE );\n\t}\n\tim_free_dmask( mask );\n\n\treturn( TRUE );\n}\n\nstatic void\nplot_reset( Classmodel *classmodel )\n{\n\tPlot *plot = PLOT( classmodel );\n\n\timage_value_destroy( &plot->value );\n\tplot->format = PLOT_FORMAT_YYYY;\n\tplot->style = PLOT_STYLE_LINE;\n\tplot->xmin = PLOT_RANGE_UNSET;\n\tplot->xmax = PLOT_RANGE_UNSET;\n\tplot->ymin = PLOT_RANGE_UNSET;\n\tplot->ymax = PLOT_RANGE_UNSET;\n\tIM_SETSTR( plot->caption, NULL ); \n\tIM_SETSTR( plot->xcaption, NULL ); \n\tIM_SETSTR( plot->ycaption, NULL ); \n\tIM_FREEF( slist_free_all, plot->series_captions );\n}\n\nstatic gboolean\nplot_graphic_save( Classmodel *classmodel, \n\tGtkWidget *parent, const char *filename )\n{\n\tPlot *plot = PLOT( classmodel );\n\tImageValue *value = &plot->value;\n\tchar buf[FILENAME_MAX];\n\n\texpand_variables( filename, buf );\n\tfilesel_add_mode( buf );\n\n\tif( value->ii )\n\t\tif( !imageinfo_write( value->ii, buf ) )\n\t\t\treturn( FALSE );\n\n\tmainw_recent_add( &mainw_recent_image, filename );\n\n\treturn( TRUE );\n}\n\nstatic void\nplot_class_init( PlotClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->finalize = plot_finalize;\n\n\tiobject_class->generate_caption = plot_generate_caption;\n\n#ifdef HAVE_LIBGOFFICE\n\tmodel_class->view_new = plot_view_new;\n#endif /*HAVE_LIBGOFFICE*/\n\tmodel_class->edit = plot_edit;\n\tmodel_class->save = plot_save;\n\tmodel_class->load = plot_load;\n\n\tclassmodel_class->class_get = plot_class_get;\n\tclassmodel_class->members = plot_members;\n\tclassmodel_class->n_members = IM_NUMBER( plot_members );\n\tclassmodel_class->reset = plot_reset;\n\n\tclassmodel_class->graphic_save = plot_graphic_save;\n\tclassmodel_class->filetype = filesel_type_image;\n\tclassmodel_class->filetype_pref = \"IMAGE_FILE_TYPE\";\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\nplot_init( Plot *plot )\n{\n#ifdef DEBUG\n\tprintf( \"plot_init\\n\" );\n#endif /*DEBUG*/\n\n\timage_value_init( &plot->value, CLASSMODEL( plot ) );\n\n\tplot->xcolumn = NULL;\n\tplot->ycolumn = NULL;\n\tplot->rows = 0;\n\tplot->columns = 0;\n\n\tplot->show_status = FALSE;\n\tplot->mag = 100;\n\tplot->left = 0;\n\tplot->top = 0;\n\n\tvips_buf_init_dynamic( &plot->caption_buffer, MAX_LINELENGTH );\n\n\tiobject_set( IOBJECT( plot ), CLASS_PLOT, NULL );\n\n\tplot_reset( CLASSMODEL( plot ) );\n}\n\nGtkType\nplot_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( PlotClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) plot_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Plot ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) plot_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"Plot\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\n#ifdef HAVE_LIBGOFFICE\n\n/* Make a GOColor from an RGB triple. Different versions of goffice have\n * different ways of doing this :(\n */\n#ifdef GO_COLOR_FROM_RGB\n  #define RGB( R, G, B ) GO_COLOR_FROM_RGB( R, G, B )\n#else\n  #define RGB( R, G, B ) RGB_TO_RGBA( RGB_TO_UINT( R, G, B ), 0xff )\n#endif\n\n/* Choose line colours with this. RGB first, then mostly random. We can't use\n * goffice's default colours because we really want the first three to be: red,\n * green, blue.\n */\n\nstatic GOColor default_colour[] = {\n\tRGB( 255, 0, 0 ),\n\tRGB( 0, 255, 0 ),\n\tRGB( 0, 0, 255 ),\n\tRGB( 100, 0, 102 ),\n\tRGB( 17, 0, 102 ),\n\tRGB( 0, 0, 180 ),\n\tRGB( 0, 53, 255 ),\n\tRGB( 0, 104, 234 ),\n\tRGB( 0, 150, 188 ),\n\tRGB( 0, 205, 170 ),\n\tRGB( 0, 255, 139 ),\n\tRGB( 0, 255, 55 ),\n\tRGB( 40, 255, 40 ),\n\tRGB( 106, 255, 74 ),\n\tRGB( 155, 255, 48 ),\n\tRGB( 209, 255, 21 ),\n\tRGB( 239, 255, 7 ),\n\tRGB( 255, 176, 0 ),\n\tRGB( 255, 110, 0 ),\n\tRGB( 255, 50, 0 ),\n\tRGB( 196, 0, 0 )\n};\n\n/* Build a GogPlot from a Plot.\n */\nGogPlot *\nplot_new_gplot( Plot *plot )\n{\n\tGogPlot *gplot;\n\tint i;\n\n\tif( plot->style == PLOT_STYLE_BAR )\n\t\tgplot = gog_plot_new_by_name( \"GogHistogramPlot\" );\n\telse\n\t\tgplot = gog_plot_new_by_name( \"GogXYPlot\" );\n\n\tswitch( plot->style ) {\n\tcase PLOT_STYLE_POINT:\n\t\tg_object_set( gplot, \"default-style-has-lines\", FALSE, NULL );\n\t\tbreak;\n\n\tcase PLOT_STYLE_LINE:\n\t\tg_object_set( gplot, \"default-style-has-markers\", FALSE, NULL );\n\t\tbreak;\n\n\tcase PLOT_STYLE_SPLINE:\n\t\tg_object_set( gplot, \"default-style-has-markers\", FALSE, NULL );\n\t\tg_object_set( gplot, \"use-splines\", TRUE, NULL );\n\t\tbreak;\n\n\tcase PLOT_STYLE_BAR:\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\tfor( i = 0; i < plot->columns; i++ ) {\n\t\tGogSeries *series;\n\t\tGOData *data;\n\t\tGError *error;\n\t\tchar *caption;\n\n                series = gog_plot_new_series( gplot );\n\t\tdata = go_data_vector_val_new( plot->xcolumn[i], plot->rows, \n\t\t\tNULL );\n\t\tgog_series_set_dim( series, 0, data, &error );\n\t\tdata = go_data_vector_val_new( plot->ycolumn[i], plot->rows, \n\t\t\tNULL );\n\t\tgog_series_set_dim( series, 1, data, &error );\n\n\t\tif( (caption = (char *) \n\t\t\tg_slist_nth_data( plot->series_captions, i )) ) \n\t\t\tcaption = g_strdup( caption );\n\t\telse \n\t\t\tcaption = g_strdup_printf( \"Band %d\", i ); \n\t\tdata = go_data_scalar_str_new( caption, TRUE );\n\t\tgog_series_set_name( series, (GODataScalar *) data, &error );\n\n\t\tif( i < IM_NUMBER( default_colour ) ) {\n\t\t\tGOStyle *style;\n\n\t\t\tstyle = go_styled_object_get_style( \n\t\t\t\tGO_STYLED_OBJECT( series ) );\n\n\t\t\tstyle->line.color = default_colour[i];\n\t\t\tstyle->line.auto_color = FALSE;\n\n\t\t\tgo_marker_set_fill_color( style->marker.mark,\n\t\t\t\tdefault_colour[i] );\n\t\t\tstyle->marker.auto_fill_color = FALSE;\n\n\t\t\t/* Could match fill, but black everywhere looks nicer.\n\t\t\t */\n\t\t\tgo_marker_set_outline_color( style->marker.mark,\n\t\t\t\tRGB( 0, 0, 0 ) );\n\t\t\tstyle->marker.auto_outline_color = FALSE;\n\n\t\t\tgog_object_request_update( GOG_OBJECT( series ) );\n\t\t}\n\t}\n\n\treturn( gplot );\n}\n\nstatic void\nplot_grid_add( GogAxis *axis )\n{\n\tGogGridLine *ggl;\n\n\tif( !gog_object_get_child_by_name( GOG_OBJECT( axis ), \"MajorGrid\" ) ) {\n\t\tggl = g_object_new( GOG_TYPE_GRID_LINE, \n\t\t\t\"is-minor\", FALSE, NULL );\n\t\tgog_object_add_by_name( GOG_OBJECT( axis ), \n\t\t\t\"MajorGrid\", GOG_OBJECT( ggl ) );\n\t}\n\n\tif( !gog_object_get_child_by_name( GOG_OBJECT( axis ), \"MinorGrid\" ) ) {\n\t\tggl = g_object_new( GOG_TYPE_GRID_LINE, \n\t\t\t\"is-minor\", TRUE, NULL );\n\t\tgog_object_add_by_name( GOG_OBJECT( axis ), \n\t\t\t\"MinorGrid\", GOG_OBJECT( ggl ) );\n\t}\n\n\tg_object_set( axis, \"pos\", GOG_AXIS_CROSS, NULL );\n}\n\nstatic void\nplot_set_title( GogObject *thing, const char *role, const char *text )\n{\n\tGogObject *title;\n\n\ttitle = gog_object_get_child_by_name( thing, role );\n\tif( text && !title ) {\n\t\ttitle = g_object_new( GOG_TYPE_LABEL, NULL );\n\t\tgog_object_add_by_name( thing, role, title );\n\t}\n\telse if( !text && title ) {\n\t\tgog_object_clear_parent( title );\n\t\tUNREF( title ); \n\t}\n\n\tif( text && title ) {\n\t\tGOData *data;\n\n\t\tdata = go_data_scalar_str_new( text, FALSE );\n\t\tgog_dataset_set_dim( GOG_DATASET( title ), 0, data, NULL );\n\t}\n}\n\nvoid\nplot_style_main( Plot *plot, GogChart *gchart )\n{\n\tGSList *axes;\n\tGogAxis *axis;\n\tGogObject *legend;\n\n\taxes = gog_chart_get_axes( gchart, GOG_AXIS_X );\n\taxis = GOG_AXIS( axes->data );\n\tg_slist_free( axes );\n\n\tgog_axis_set_bounds( axis, plot->xmin, plot->xmax );\n\tplot_set_title( GOG_OBJECT( axis ), \"Label\", plot->xcaption ); \n\tplot_grid_add( axis ); \n\n\taxes = gog_chart_get_axes( gchart, GOG_AXIS_Y );\n\taxis = GOG_AXIS( axes->data );\n\tg_slist_free( axes );\n\n\tgog_axis_set_bounds( axis, plot->ymin, plot->ymax );\n\tplot_set_title( GOG_OBJECT( axis ), \"Label\", plot->ycaption ); \n\tplot_grid_add( axis ); \n\n\tlegend = gog_object_get_child_by_name( GOG_OBJECT( gchart ), \"Legend\" );\n\tif( plot->columns > 1 &&\n\t\t!legend ) {\n\t\tlegend = g_object_new( GOG_TYPE_LEGEND, NULL );\n\t\tgog_object_add_by_name( GOG_OBJECT( gchart ), \n\t\t\t\"Legend\", GOG_OBJECT( legend ) );\n\t}\n\telse if( plot->columns == 1 &&\n\t\tlegend ) {\n\t\tgog_object_clear_parent( legend );\n\t\tUNREF( legend ); \n\t}\n\n\tplot_set_title( GOG_OBJECT( gchart ), \"Title\", plot->caption ); \n}\n\nvoid\nplot_style_thumbnail( Plot *plot, GogChart *gchart )\n{\n\tGSList *axes;\n\tGogAxis *axis;\n\n\taxes = gog_chart_get_axes( gchart, GOG_AXIS_X );\n\taxis = GOG_AXIS( axes->data );\n\tg_slist_free( axes );\n\n\tg_object_set( axis, \n\t\t\"major-tick-labeled\", FALSE, \n\t\t\"major-tick-size-pts\", 0,\n\t\t\"pos\", GOG_AXIS_CROSS,\n\t\tNULL );\n\tgog_axis_set_bounds( axis, plot->xmin, plot->xmax );\n\n\taxes = gog_chart_get_axes( gchart, GOG_AXIS_Y );\n\taxis = GOG_AXIS( axes->data );\n\tg_slist_free( axes );\n\n\tg_object_set( axis, \n\t\t\"major-tick-labeled\", FALSE, \n\t\t\"major-tick-size-pts\", 0,\n\t\t\"pos\", GOG_AXIS_CROSS,\n\t\tNULL );\n\tgog_axis_set_bounds( axis, plot->ymin, plot->ymax );\n}\n\nImageinfo *\nplot_to_image( Plot *plot, Reduce *rc, double dpi )\n{\n\tGogGraph *ggraph;\n\tGogChart *gchart;\n\tGogPlot *gplot;\n\tGogRenderer *renderer;\n\tGdkPixbuf *pixbuf;\n\tdouble width_in_pts, height_in_pts;\n\tImageinfo *ii;\n\n\tggraph = g_object_new( GOG_TYPE_GRAPH, NULL );\n\n\tgchart = g_object_new( GOG_TYPE_CHART, NULL );\n\tgog_object_add_by_name( GOG_OBJECT( ggraph ), \n\t\t\"Chart\", GOG_OBJECT( gchart ) );\n\n\tgplot = plot_new_gplot( plot );\n\tgog_object_add_by_name( GOG_OBJECT( gchart ), \n\t\t\"Plot\", GOG_OBJECT( gplot ) );\n\n\tplot_style_main( plot, gchart ); \n\n\trenderer = gog_renderer_new( ggraph );\n\n\tgog_graph_force_update( ggraph );\n\n\tgog_graph_get_size( ggraph, &width_in_pts, &height_in_pts);\n\n\tgog_renderer_update( renderer, \n\t\twidth_in_pts * dpi / 72.0, height_in_pts * dpi / 72.0 );\n\n\tpixbuf = gog_renderer_get_pixbuf( renderer );\n\n\tif( !(ii = imageinfo_new_from_pixbuf( main_imageinfogroup, rc->heap, \n\t\tpixbuf )) ) { \n\t\tUNREF( renderer );\n\t\tUNREF( ggraph );\n\n\t\treturn( NULL ); \n\t}\n\n\t/* Don't unref the pixbuf, we don't own it.\n\t */\n\n\tUNREF( renderer );\n\tUNREF( ggraph );\n\n\treturn( ii ); \n}\n\n#endif /*HAVE_LIBGOFFICE*/\n"
  },
  {
    "path": "src/plot.h",
    "content": "/* a plot in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_PLOT (plot_get_type())\n#define PLOT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_PLOT, Plot ))\n#define PLOT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_PLOT, PlotClass))\n#define IS_PLOT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_PLOT ))\n#define IS_PLOT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_PLOT ))\n#define PLOT_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_PLOT, PlotClass ))\n\ntypedef enum {\n\tPLOT_FORMAT_YYYY = 0,\n\tPLOT_FORMAT_XYYY,\n\tPLOT_FORMAT_XYXY,\n\tPLOT_FORMAT_LAST\n} PlotFormat;\n\ntypedef enum {\n\tPLOT_STYLE_POINT = 0,\n\tPLOT_STYLE_LINE,\n\tPLOT_STYLE_SPLINE,\n\tPLOT_STYLE_BAR,\n\tPLOT_STYLE_LAST\n} PlotStyle;\n\n/* Magic number for 'range value unset' (ie. should auto-range).\n */\n#define PLOT_RANGE_UNSET (-999999)\n\nstruct _Plot {\n\tClassmodel model;\n\n\t/* Base class fields.\n\t */\n\tImageValue value;\n\tPlotFormat format;\n\tPlotStyle style;\n\tchar *caption; \n\tchar *xcaption; \n\tchar *ycaption; \n\tGSList *series_captions;\n\tdouble xmin;\n\tdouble xmax;\n\tdouble ymin;\n\tdouble ymax;\n\n\t/* Unpack image to a set of xy columns here.\n\t */\n\tdouble **xcolumn;\n\tdouble **ycolumn;\n\tint rows;\n\tint columns;\n\n\t/* Save x/y/mag/status here. Init plot windows from this, save and\n\t * load from workspaces.\n\t */\n\tgboolean show_status;\n\tint mag;\n\tint left, top;\n\n\t/* Private ... build iobject caption here.\n\t */\n\tVipsBuf caption_buffer;\n};\n\ntypedef struct _PlotClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} PlotClass;\n\nGType plot_get_type( void );\n\nchar *plot_f2c( PlotFormat format );\nchar *plot_s2c( PlotStyle style );\n\n#ifdef HAVE_LIBGOFFICE\nGogPlot *plot_new_gplot( Plot *plot );\nvoid plot_style_main( Plot *plot, GogChart *gchart );\nvoid plot_style_thumbnail( Plot *plot, GogChart *gchart );\nImageinfo *plot_to_image( Plot *plot, Reduce *rc, double dpi );\n#endif /*HAVE_LIBGOFFICE*/\n\n"
  },
  {
    "path": "src/plotmodel.c",
    "content": "/* the model parts of a plot window .. all the window components watch this\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic iObjectClass *parent_class = NULL;\n\nstatic void\nplotmodel_dispose( GObject *gobject )\n{\n\tPlotmodel *plotmodel;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_PLOTMODEL( gobject ) );\n\n\tplotmodel = PLOTMODEL( gobject );\n\n#ifdef DEBUG\n\tprintf( \"plotmodel_dispose %p: \", plotmodel );\n\tiobject_print( IOBJECT( plotmodel ) );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\tFREESID( plotmodel->changed_sid, plotmodel->plot );\n\tFREESID( plotmodel->destroy_sid, plotmodel->plot );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\nplotmodel_finalize( GObject *gobject )\n{\n#ifdef DEBUG\n\tPlotmodel *plotmodel = PLOTMODEL( gobject );\n\n\tprintf( \"plotmodel_finalize: %p\\n\", plotmodel );\n#endif /*DEBUG*/\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\nplotmodel_changed( iObject *iobject )\n{\n\tPlotmodel *plotmodel = PLOTMODEL( iobject );\n\n#ifdef DEBUG\n\tprintf( \"plotmodel_changed:\\n\" );\n#endif /*DEBUG*/\n\n\tprefs_set( \"DISPLAY_STATUS\", \n\t\t\"%s\", bool_to_char( plotmodel->show_status ) );\n\n\tIOBJECT_CLASS( parent_class )->changed( iobject );\n}\n\nstatic void\nplotmodel_class_init( PlotmodelClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = plotmodel_dispose;\n\tgobject_class->finalize = plotmodel_finalize;\n\n\tiobject_class->changed = plotmodel_changed;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n}\n\nstatic void\nplotmodel_init( Plotmodel *plotmodel )\n{\n#ifdef DEBUG\n\tprintf( \"plotmodel_init: %p\\n\", plotmodel );\n#endif /*DEBUG*/\n\n\tplotmodel->changed_sid = 0;\n\tplotmodel->destroy_sid = 0;\n\tplotmodel->width = -1;\n\tplotmodel->height = -1;\n\tplotmodel->mag = 100;\n\tplotmodel->show_status = DISPLAY_STATUS;\n}\n\nGType\nplotmodel_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( PlotmodelClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) plotmodel_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Plotmodel ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) plotmodel_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_IOBJECT, \n\t\t\t\"Plotmodel\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\nplotmodel_plot_destroy_cb( Plot *plot, Plotmodel *plotmodel )\n{\n\tplotmodel->plot = NULL;\n\tplotmodel->destroy_sid = 0;\n\tplotmodel->changed_sid = 0;\n}\n\nstatic void\nplotmodel_plot_changed_cb( Plot *plot, Plotmodel *plotmodel )\n{\n\tiobject_changed( IOBJECT( plotmodel ) );\n}\n\nstatic void\nplotmodel_link( Plotmodel *plotmodel, Plot *plot )\n{\n\t/* Don't need to listen for \"destroy\": our enclosing Floatwindow does\n\t * that.\n\t */\n\tplotmodel->plot = plot;\n\tplotmodel->destroy_sid = g_signal_connect( \n\t\tG_OBJECT( plot ), \"destroy\", \n\t\tG_CALLBACK( plotmodel_plot_destroy_cb ), plotmodel );\n\tplotmodel->changed_sid = g_signal_connect( \n\t\tG_OBJECT( plot ), \"changed\", \n\t\tG_CALLBACK( plotmodel_plot_changed_cb ), plotmodel );\n}\n\nPlotmodel *\nplotmodel_new( Plot *plot )\n{\n\tPlotmodel *plotmodel = g_object_new( TYPE_PLOTMODEL, NULL );\n\n\tplotmodel_link( plotmodel, plot );\n\n\treturn( plotmodel );\n}\n\nvoid\nplotmodel_set_mag( Plotmodel *plotmodel, int mag )\n{\n\t/* Don't let mag get too large or small. GtkPlotCanvas does not\n\t * display large magnifications at all well.\n\t */\n\tmag = IM_CLIP( 100, mag, 800 );\n\n\tif( plotmodel->mag != mag ) {\n#ifdef DEBUG\n\t\tprintf( \"plotmodel_set_mag: %d\\n\", mag );\n#endif /*DEBUG*/\n\n\t\tplotmodel->mag = mag;\n\n\t\t/* Invaidate width so the canvas is regenerated.\n\t\t */\n\t\tplotmodel->width = -1;\n\n\t\tiobject_changed( IOBJECT( plotmodel ) );\n\t}\n}\n\nvoid\nplotmodel_set_status( Plotmodel *plotmodel, gboolean show_status )\n{\n\tif( plotmodel->show_status != show_status ) {\n#ifdef DEBUG\n\t\tprintf( \"plotmodel_set_status: %d\\n\", show_status );\n#endif /*DEBUG*/\n\n\t\tplotmodel->show_status = show_status;\n\n\t\tiobject_changed( IOBJECT( plotmodel ) );\n\t}\n}\n"
  },
  {
    "path": "src/plotmodel.h",
    "content": "/* the model parts of a plot window .. all the window components watch this\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_PLOTMODEL (plotmodel_get_type())\n#define PLOTMODEL( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_PLOTMODEL, Plotmodel ))\n#define PLOTMODEL_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_PLOTMODEL, PlotmodelClass ))\n#define IS_PLOTMODEL( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PLOTMODEL ))\n#define IS_PLOTMODEL_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PLOTMODEL ))\n\nstruct _Plotmodel {\n\tiObject parent_class;\n\n\t/* The class model we watch.\n\t */\n\tPlot *plot;\n\tguint changed_sid;\n\tguint destroy_sid;\n\n\t/* The last canvas size we set ... stop resize loops with these.\n\t */\n\tint width;\n\tint height;\n\n\t/* Viewer state.\n\t */\n\tint mag;\n\tgboolean show_status;\n};\n\ntypedef struct _PlotmodelClass {\n\tiObjectClass parent_class;\n\n\t/* My methods.\n\t */\n} PlotmodelClass;\n\nGtkType plotmodel_get_type( void );\nPlotmodel *plotmodel_new( Plot *plot );\nvoid plotmodel_set_mag( Plotmodel *plotmodel, int mag );\nvoid plotmodel_set_status( Plotmodel *plotmodel, gboolean show_status );\n"
  },
  {
    "path": "src/plotpresent.c",
    "content": "/* a plot widget, plus some navigation stuff\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG_EVENT\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n#ifdef HAVE_LIBGOFFICE\n\nstatic GtkBinClass *parent_class = NULL;\n\nenum {\n\tSIG_MOUSE_MOVE,\t\t/* mose drag, axies cods */\n\tSIG_LAST\n};\n\nstatic guint plotpresent_signals[SIG_LAST] = { 0 };\n\nstatic void\nplotpresent_mouse_move( Plotpresent *plotpresent, double x, double y )\n{\n\tg_signal_emit( G_OBJECT( plotpresent ), \n\t\tplotpresent_signals[SIG_MOUSE_MOVE], 0, x, y );\n}\n\nstatic void\nplotpresent_destroy( GtkObject *object )\n{\n\tPlotpresent *plotpresent;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_PLOTPRESENT( object ) );\n\n\tplotpresent = PLOTPRESENT( object );\n\n#ifdef DEBUG\n\tprintf( \"plotpresent_destroy: %p\\n\", plotpresent );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\tUNREF( plotpresent->grend );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\nplotpresent_size_request( GtkWidget *widget, GtkRequisition *requisition )\n{\n\tGtkBin *bin = GTK_BIN( widget );\n\n\tif( bin->child && GTK_WIDGET_VISIBLE( bin->child ) ) \n\t\tgtk_widget_size_request( bin->child, requisition );\n}\n\nstatic void\nplotpresent_size_allocate( GtkWidget *widget, GtkAllocation *allocation )\n{\n\tGtkBin *bin = GTK_BIN( widget );\n\n\tif( bin->child && GTK_WIDGET_VISIBLE( bin->child ) ) \n\t\tgtk_widget_size_allocate( bin->child, allocation );\n}\n\n/* Spot mouse motion events, to update status bar.\n */\nstatic gboolean\nplotpresent_motion_notify_event( GtkWidget *widget, GdkEventMotion *event ) \n{\n\tPlotpresent *plotpresent = PLOTPRESENT( widget );\n\tGtkAllocation *allocation = \n\t\t&GTK_WIDGET( plotpresent->canvas )->allocation;\n\n\tGogView *view;\n\tGSList *axes;\n\tGogAxis *x_axis;\n\tGogAxis *y_axis;\n\tGogChartMap *map;\n\n#ifdef DEBUG_EVENT\n\tprintf( \"plotpresent_motion_notify_event: %p\\n\", plotpresent );\n\tprintf( \"event->x = %g, event->y = %g\\n\", event->x, event->y );\n#endif /*DEBUG_EVENT*/\n\n\tgog_renderer_update( plotpresent->grend, \n\t\tallocation->width, allocation->height );\n\n\tg_object_get( G_OBJECT( plotpresent->grend ), \"view\", &view, NULL );\n\tview = gog_view_find_child_view( view, \n\t\tGOG_OBJECT( plotpresent->gplot ) );\n\n\taxes = gog_chart_get_axes( plotpresent->gchart, GOG_AXIS_X );\n\tx_axis = GOG_AXIS( axes->data );\n\tg_slist_free( axes );\n\n\taxes = gog_chart_get_axes( plotpresent->gchart, GOG_AXIS_Y );\n\ty_axis = GOG_AXIS( axes->data );\n\tg_slist_free( axes );\n\n\tmap = gog_chart_map_new( plotpresent->gchart, &(view->allocation),\n\t\tx_axis, y_axis, NULL, FALSE );\n\n\tif( gog_chart_map_is_valid( map ) &&\n\t\tevent->x >= view->allocation.x && \n\t\tevent->x < view->allocation.x + view->allocation.w &&\n\t\tevent->y >= view->allocation.y && \n\t\tevent->y < view->allocation.y + view->allocation.h ) {\n\t\tGogAxisMap *x_map;\n\t\tGogAxisMap *y_map;\n\t\tdouble x;\n\t\tdouble y;\n\n\t\tx_map = gog_chart_map_get_axis_map( map, 0 );\n\t\ty_map = gog_chart_map_get_axis_map( map, 1 );\n\t\tx = gog_axis_map_from_view( x_map, event->x );\n\t\ty = gog_axis_map_from_view( y_map, event->y );\n\n\t\tplotpresent_mouse_move( plotpresent, x, y );\n\t}\n\n        gog_chart_map_free( map );\n\n\treturn( FALSE );\n}\n\nstatic void\nplotpresent_class_init( PlotpresentClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tGtkWidgetClass *widget_class = (GtkWidgetClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = plotpresent_destroy;\n\n        widget_class->size_request = plotpresent_size_request;\n\twidget_class->size_allocate = plotpresent_size_allocate;\n\n\twidget_class->motion_notify_event = plotpresent_motion_notify_event;\n\n\t/* Create signals.\n\t */\n\tplotpresent_signals[SIG_MOUSE_MOVE] = g_signal_new( \"mouse_move\",\n\t\tG_OBJECT_CLASS_TYPE( class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( PlotpresentClass, mouse_move ),\n\t\tNULL, NULL,\n\t\tnip_VOID__DOUBLE_DOUBLE,\n\t\tG_TYPE_NONE, 2,\n\t\tG_TYPE_DOUBLE, G_TYPE_DOUBLE );\n\n\t/* Init methods.\n\t */\n}\n\nstatic void\nplotpresent_init( Plotpresent *plotpresent )\n{\n#ifdef DEBUG\n\tprintf( \"plotpresent_init: %p\\n\", plotpresent );\n#endif /*DEBUG*/\n\n\tplotpresent->gplot = NULL;\n\n\tplotpresent->canvas = go_graph_widget_new( NULL );\n        gtk_container_add( GTK_CONTAINER( plotpresent ), plotpresent->canvas );\n\tgtk_widget_show( GTK_WIDGET( plotpresent->canvas ) );\n\n\tplotpresent->ggraph = go_graph_widget_get_graph( \n\t\tGO_GRAPH_WIDGET( plotpresent->canvas ) );\n\tplotpresent->gchart = go_graph_widget_get_chart( \n\t\tGO_GRAPH_WIDGET( plotpresent->canvas ) );\n\tgtk_widget_add_events( plotpresent->canvas,\n\t\tGDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK );\n\n\t/* You'd think we could set up the axies too, but we can't get them\n\t * from the chart until it's realized. Wait for the first refresh.\n\t */\n\n\tplotpresent->grend = gog_renderer_new( plotpresent->ggraph );\n}\n\nGType\nplotpresent_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( PlotpresentClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) plotpresent_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Plotpresent ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) plotpresent_init,\n\t\t};\n\n\t\ttype = g_type_register_static( GTK_TYPE_BIN, \n\t\t\t\"Plotpresent\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\nplotpresent_build_plot( Plotpresent *plotpresent )\n{\n\tPlotmodel *plotmodel = plotpresent->plotmodel;\n\tPlot *plot = plotmodel->plot;\n\n#ifdef DEBUG\n\tprintf( \"plotpresent_build_plot: %p\\n\", plotpresent );\n#endif /*DEBUG*/\n\n\tGOG_UNREF( plotpresent->gplot );\n\n\tplotpresent->gplot = plot_new_gplot( plot );\n\tgog_object_add_by_name( GOG_OBJECT( plotpresent->gchart ), \n\t\t\"Plot\", GOG_OBJECT( plotpresent->gplot ) );\n\n\tplot_style_main( plot, plotpresent->gchart ); \n}\n\nstatic void\nplotpresent_changed_cb( Plotmodel *plotmodel, Plotpresent *plotpresent )\n{\n\tPlot *plot = plotmodel->plot;\n\n#ifdef DEBUG\n\tprintf( \"plotpresent_changed_cb: %p\\n\", plotpresent );\n#endif /*DEBUG*/\n\n\t/* Can refresh before model build.\n\t */\n\tif( plot->rows == 0 || \n\t\tplot->columns == 0 )\n\t\treturn;\n\n\t/* Rebuild plot and data.\n\t */\n\tplotpresent_build_plot( plotpresent );\n}\n\nstatic void\nplotpresent_link( Plotpresent *plotpresent, Plotmodel *plotmodel )\n{\n\t/* All the model parts for our set of views.\n\t */\n\tplotpresent->plotmodel = plotmodel;\n\tg_signal_connect( G_OBJECT( plotmodel ), \"changed\", \n\t\tG_CALLBACK( plotpresent_changed_cb ), plotpresent );\n}\n\nPlotpresent *\nplotpresent_new( Plotmodel *plotmodel )\n{\n\tPlotpresent *plotpresent = gtk_type_new( TYPE_PLOTPRESENT );\n\n\tplotpresent_link( plotpresent, plotmodel );\n\n\treturn( plotpresent );\n}\n\n#endif /*HAVE_LIBGOFFICE*/\n"
  },
  {
    "path": "src/plotpresent.h",
    "content": "/* a plot widget, plus some navigation stuff\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_PLOTPRESENT (plotpresent_get_type())\n#define PLOTPRESENT( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_PLOTPRESENT, Plotpresent ))\n#define PLOTPRESENT_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_PLOTPRESENT, PlotpresentClass ))\n#define IS_PLOTPRESENT( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PLOTPRESENT ))\n#define IS_PLOTPRESENT_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PLOTPRESENT ))\n\nstruct _Plotpresent {\n\tGtkBin parent_class;\n\n\t/* Context.\n\t */\n\tPlotmodel *plotmodel;\t\t/* Keep model parts of widgets here */\n\n\t/* Widgets.\n\t */\n\tGtkWidget *canvas;\n\n#ifdef HAVE_LIBGOFFICE\n\tGogRenderer *grend;\n\tGogChart *gchart;\n\tGogGraph *ggraph;\n        GogPlot *gplot;\n#endif /*HAVE_LIBGOFFICE*/\n};\n\ntypedef struct _PlotpresentClass {\n\tGtkBinClass parent_class;\n\n\t/* My methods.\n\t */\n\n\t/* A mouse movement within the plot area. xy are in axies coordinates.\n\t */\n\tvoid (*mouse_move)( Plotpresent *, double, double );\n} PlotpresentClass;\n\nGtkType plotpresent_get_type( void );\nPlotpresent *plotpresent_new( Plotmodel *plotmodel );\n\n"
  },
  {
    "path": "src/plotstatus.c",
    "content": "/* widgets for the status bar\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GtkFrameClass *parent_class = NULL;\n\n/* The popup menu.\n */\nstatic GtkWidget *plotstatus_menu = NULL;\n\nstatic void\nplotstatus_columns_destroy( Plotstatus *plotstatus )\n{\n\tint i;\n\n\tfor( i = 0; i < plotstatus->columns; i++ ) \n\t\tDESTROY_GTK( plotstatus->label[i] );\n\n\tIM_FREE( plotstatus->label );\n\n\tplotstatus->columns = 0;\n}\n\nstatic void\nplotstatus_destroy( GtkObject *object )\n{\n\tPlotstatus *plotstatus;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_PLOTSTATUS( object ) );\n\n\tplotstatus = PLOTSTATUS( object );\n\n#ifdef DEBUG\n\tprintf( \"plotstatus_destroy\\n\" );\n#endif /*DEBUG*/\n\n\tplotstatus_columns_destroy( plotstatus );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\n/* Hide this plotstatus.\n */\nstatic void\nplotstatus_hide_cb( GtkWidget *menu, GtkWidget *host, Plotstatus *plotstatus )\n{\n\tplotmodel_set_status( plotstatus->plotmodel, FALSE );\n}\n\nstatic void\nplotstatus_class_init( PlotstatusClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\n\tGtkWidget *pane;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = plotstatus_destroy;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\n\tpane = plotstatus_menu = popup_build( _( \"Status bar menu\" ) );\n\tpopup_add_but( pane, GTK_STOCK_CLOSE, \n\t\tPOPUP_FUNC( plotstatus_hide_cb ) );\n}\n\nstatic void\nplotstatus_init( Plotstatus *plotstatus )\n{\n\tGtkWidget *vb, *hb;\n\tGtkWidget *eb;\n\n\tplotstatus->plotmodel = NULL;\n\tplotstatus->label = NULL;\n\tplotstatus->columns = 0;\n\n        gtk_frame_set_shadow_type( GTK_FRAME( plotstatus ), GTK_SHADOW_OUT );\n\n\teb = gtk_event_box_new();\n        gtk_container_add( GTK_CONTAINER( plotstatus ), eb );\n        popup_attach( eb, plotstatus_menu, plotstatus );\n\n\tvb = gtk_vbox_new( FALSE, 0 );\n        gtk_container_set_border_width( GTK_CONTAINER( vb ), 1 );\n        gtk_container_add( GTK_CONTAINER( eb ), vb );\n\n\tplotstatus->top = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( plotstatus->top ), 0.0, 0.5 );\n        gtk_box_pack_start( GTK_BOX( vb ), plotstatus->top, TRUE, TRUE, 0 );\n\n\thb = gtk_hbox_new( FALSE, 5 );\n        gtk_box_pack_start( GTK_BOX( vb ), hb, TRUE, TRUE, 0 );\n\n\tplotstatus->pos = gtk_label_new( \"\" );\n\tset_fixed( plotstatus->pos, strlen( \"(8888888,8888888)\" ) );\n        gtk_misc_set_alignment( GTK_MISC( plotstatus->pos ), 0.0, 0.5 );\n        gtk_box_pack_start( GTK_BOX( hb ), plotstatus->pos, FALSE, FALSE, 0 );\n\n\tplotstatus->hb = gtk_hbox_new( FALSE, 5 );\n        gtk_box_pack_start( GTK_BOX( hb ), plotstatus->hb, TRUE, TRUE, 0 );\n\n\tplotstatus->mag = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( plotstatus->mag ), 0.0, 0.5 );\n        gtk_box_pack_end( GTK_BOX( hb ), plotstatus->mag, FALSE, FALSE, 0 );\n\n\tgtk_widget_show_all( eb );\n}\n\nGtkType\nplotstatus_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Plotstatus\",\n\t\t\tsizeof( Plotstatus ),\n\t\t\tsizeof( PlotstatusClass ),\n\t\t\t(GtkClassInitFunc) plotstatus_class_init,\n\t\t\t(GtkObjectInitFunc) plotstatus_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( GTK_TYPE_FRAME, &info );\n\t}\n\n\treturn( type );\n}\n\n/* Model has changed: rebuild everything.\n */\nstatic void\nplotstatus_refresh( Plotstatus *plotstatus )\n{\n\tPlotmodel *plotmodel = plotstatus->plotmodel;\n\tPlot *plot = plotmodel->plot;\n\n#ifdef DEBUG\n\tprintf( \"plotstatus_refresh: %p\\n\", plotstatus );\n\tprintf( \"  show_status = %d\\n\", plotmodel->show_status );\n#endif /*DEBUG*/\n\n\twidget_visible( GTK_WIDGET( plotstatus ), plotmodel->show_status );\n\n\t/* If we're hidden, no need to do any more.\n\t */\n\tif( !plotmodel->show_status )\n\t\treturn;\n\n\tset_glabel( plotstatus->mag, \"%s %d%%\", \n\t\t_( \"Magnification\" ), plotmodel->mag );\n\n\tset_gcaption( plotstatus->top, \"%s\", IOBJECT( plot )->caption );\n\n\tif( plotstatus->columns != plot->columns ) {\n\t\t/* Bands/fmt has changed ... rebuild band display widgets.\n\t\t */\n\t\tint columns;\n\t\tint i;\n\n\t\t/* Don't display more than 8 series ... it'll make the window\n\t\t * too large.\n\n\t\t \tFIXME ... not very kewl\n\n\t\t */\n\t\tplotstatus_columns_destroy( plotstatus );\n\t\tcolumns = IM_MIN( 8, plot->columns ); \n\t\tif( !(plotstatus->label = \n\t\t\tIM_ARRAY( NULL, columns, GtkWidget * )) )\n\t\t\treturn;\n\t\tfor( i = 0; i < columns; i++ )\n\t\t\tplotstatus->label[i] = NULL;\n\t\tplotstatus->columns = columns;\n\n\t\tfor( i = 0; i < columns; i++ ) {\n\t\t\tGtkWidget *label;\n\n\t\t\tplotstatus->label[i] = label = gtk_label_new( \"\" );\n\t\t\tgtk_misc_set_alignment( GTK_MISC( label ), \n\t\t\t\t0.0, 0.5 );\n\t\t\tset_fixed( label, 8 );\n\t\t\tgtk_box_pack_start( GTK_BOX( plotstatus->hb ), \n\t\t\t\tlabel, FALSE, FALSE, 0 );\n\t\t\tgtk_widget_show( label );\n\t\t}\n\t}\n}\n\nstatic void\nplotstatus_changed_cb( Plotmodel *plotmodel, Plotstatus *plotstatus )\n{\n\tplotstatus_refresh( plotstatus );\n}\n\nPlotstatus *\nplotstatus_new( Plotmodel *plotmodel )\n{\n\tPlotstatus *plotstatus = gtk_type_new( TYPE_PLOTSTATUS );\n\n\tplotstatus->plotmodel = plotmodel;\n\tg_signal_connect( G_OBJECT( plotmodel ), \"changed\", \n\t\tG_CALLBACK( plotstatus_changed_cb ), plotstatus );\n\n\treturn( plotstatus );\n}\n\n/* Find nearest x, display that y.\n */\nstatic void\nplotstatus_series_update( GtkWidget *widget, \n\tPlot *plot, int column, double x, double y )\n{\n\tdouble *xcolumn = plot->xcolumn[column];\n\tdouble *ycolumn = plot->ycolumn[column];\n\tint i;\n\tint best;\n\tgdouble best_score;\n\n\tbest = 0;\n\tbest_score = IM_ABS( x - xcolumn[0] );\n\tfor( i = 1; i < plot->rows; i++ ) {\n\t\tdouble score = IM_ABS( x - xcolumn[i] );\n\n\t\tif( score < best_score ) {\n\t\t\tbest_score = score;\n\t\t\tbest = i;\n\t\t}\n\t}\n\n\tset_glabel( widget, \"%g\", ycolumn[best] );\n}\n\nvoid \nplotstatus_mouse( Plotstatus *plotstatus, double x, double y )\n{\n\tPlotmodel *plotmodel = plotstatus->plotmodel;\n\tPlot *plot = plotmodel->plot;\n\tint i;\n\n\tset_glabel( plotstatus->pos, \"(%05g, %05g)\", x, y ); \n\n\tg_assert( plotstatus->columns <= plot->columns );\n\n\tfor( i = 0; i < plotstatus->columns; i++ ) \n\t\tplotstatus_series_update( plotstatus->label[i], \n\t\t\tplot, i, x, y );\n}\n"
  },
  {
    "path": "src/plotstatus.h",
    "content": "/* display plot info and mouse posn\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_PLOTSTATUS (plotstatus_get_type())\n#define PLOTSTATUS( obj ) (GTK_CHECK_CAST( (obj), TYPE_PLOTSTATUS, Plotstatus ))\n#define PLOTSTATUS_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_PLOTSTATUS, PlotstatusClass ))\n#define IS_PLOTSTATUS( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PLOTSTATUS ))\n#define IS_PLOTSTATUS_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PLOTSTATUS ))\n\nstruct _Plotstatus {\n\tGtkFrame parent_class;\n\n\tPlotmodel *plotmodel;\n\n\tGtkWidget *top;\t\t/* Top label */\n\tGtkWidget *pos;\t\t/* Position */\n\tGtkWidget *hb;\t\t/* Band element hbox */\n\tGtkWidget *mag;\t\t/* Magnification display */\n\n\tGtkWidget **label;\t/* A label for displaying each series */\n\tint columns;\t\t/* Last number of columns we saw */\n};\n\ntypedef struct _PlotstatusClass {\n\tGtkFrameClass parent_class;\n\n\t/* My methods.\n\t */\n} PlotstatusClass;\n\nGtkType plotstatus_get_type( void );\nPlotstatus *plotstatus_new( Plotmodel *plotmodel );\nvoid plotstatus_mouse( Plotstatus *plotstatus, double x, double y );\n"
  },
  {
    "path": "src/plotview.c",
    "content": "/* run the display for a plotview in a workspace \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG_GEO\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n#ifdef HAVE_LIBGOFFICE\n\nstatic GraphicviewClass *parent_class = NULL;\n\nstatic void\nplotview_destroy( GtkObject *object )\n{\n    \tPlotview *plotview;\n\n    \tg_return_if_fail( object != NULL );\n    \tg_return_if_fail( IS_PLOTVIEW( object ) );\n\n#ifdef DEBUG\n    \tprintf( \"plotview_destroy\\n\" );\n#endif /*DEBUG*/\n\n    \tplotview = PLOTVIEW( object );\n\n\tGOG_UNREF( plotview->gplot );\n\n    \tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\nplotview_refresh( vObject *vobject )\n{\n    \tPlotview *plotview = PLOTVIEW( vobject );\n    \tPlot *plot = PLOT( VOBJECT( plotview )->iobject );\n\n\n#ifdef DEBUG\n    \tprintf( \"plotview_refresh\\n\" );\n#endif /*DEBUG*/\n\n\t/* Can't refresh before model build.\n\t */\n\tif( plot->rows == 0 || \n\t\tplot->columns == 0 )\n\t\treturn;\n\n\tset_gcaption( plotview->label, \"%s\", NN( IOBJECT( plot )->caption ) );\n\n\tGOG_UNREF( plotview->gplot );\n\n\tplotview->gplot = plot_new_gplot( plot );\n\tgog_object_add_by_name( GOG_OBJECT( plotview->gchart ), \n\t\t\"Plot\", GOG_OBJECT( plotview->gplot ) );\n\n\tplot_style_thumbnail( plot, plotview->gchart ); \n\n\tgtk_widget_show_all( plotview->canvas );\n\n    \tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\nplotview_link( View *view, Model *model, View *parent )\n{\n\tPlotview *plotview = PLOTVIEW( view );\n\tRowview *rview = ROWVIEW( parent->parent );\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\trowview_menu_attach( rview, GTK_WIDGET( plotview->box ) );\n}\n\nstatic void\nplotview_class_init( PlotviewClass *class )\n{\n    \tGtkObjectClass *object_class = (GtkObjectClass *) class;\n    \tvObjectClass *vobject_class = (vObjectClass *) class;\n    \tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n    \tobject_class->destroy = plotview_destroy;\n\n    \tvobject_class->refresh = plotview_refresh;\n\n\tview_class->link = plotview_link;\n}\n\nstatic void\nplotview_tooltip_generate( GtkWidget *widget, VipsBuf *buf, Plotview *plotview )\n{\n\tPlot *plot = PLOT( VOBJECT( plotview )->iobject );\n\tIMAGE *im;\n\n\tvips_buf_rewind( buf );\n\tvips_buf_appends( buf, vips_buf_all( &plot->caption_buffer ) );\n\n\tvips_buf_appendf( buf, \", %s, %s\", \n\t\tplot_f2c( plot->format ), plot_s2c( plot->style ) );\n\n\tif( (im = imageinfo_get( FALSE, plot->value.ii )) ) {\n\t\tvips_buf_appends( buf, \", \" );\n\t\tvips_buf_appendi( buf, im );\n\t}\n}\n\nstatic void \nplotview_doubleclick_one_cb( GtkWidget *widget, GdkEvent *event, \n\tPlotview *plotview )\n{\n\tHeapmodel *heapmodel = HEAPMODEL( VOBJECT( plotview )->iobject );\n\tRow *row = heapmodel->row;\n\n\trow_select_modifier( row, event->button.state );\n}\n\nstatic void \nplotview_doubleclick_two_cb( GtkWidget *widget, GdkEvent *event, \n\tPlotview *plotview )\n{\n\tPlot *plot = PLOT( VOBJECT( plotview )->iobject );\n\n\tmodel_edit( widget, MODEL( plot ) );\n}\n\nstatic void\nplotview_init( Plotview *plotview )\n{\n\tGtkWidget *eb;\n\n#ifdef DEBUG\n    \tprintf( \"plotview_init\\n\" );\n#endif /*DEBUG*/\n\n        eb = gtk_event_box_new();\n        gtk_box_pack_start( GTK_BOX( plotview ), \n\t\teb, FALSE, FALSE, 0 );\n\tgtk_widget_show( eb );\n\tgtk_widget_set_name( eb, \"caption_widget\" );\n        set_tooltip_generate( eb,\n\t\t(TooltipGenerateFn) plotview_tooltip_generate, plotview, NULL );\n\tdoubleclick_add( eb, FALSE,\n\t\tDOUBLECLICK_FUNC( plotview_doubleclick_one_cb ), plotview,\n\t\tDOUBLECLICK_FUNC( plotview_doubleclick_two_cb ), plotview );\n\n\tplotview->box = gtk_vbox_new( FALSE, 0 );\n        gtk_container_add( GTK_CONTAINER( eb ), plotview->box );\n        gtk_widget_show( plotview->box );\n\n\tplotview->canvas = go_graph_widget_new( NULL );\n        gtk_box_pack_start( GTK_BOX( plotview->box ), \n\t\tplotview->canvas, FALSE, FALSE, 0 );\n\tplotview->gchart = go_graph_widget_get_chart( \n\t\tGO_GRAPH_WIDGET( plotview->canvas ) );\n\tgtk_widget_set_size_request( GTK_WIDGET( plotview->canvas ), \n\t\tDISPLAY_THUMBNAIL, DISPLAY_THUMBNAIL );\n\n\tplotview->gplot = NULL;\n\n\tplotview->label = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( plotview->label ), 0, 0.5 );\n        gtk_misc_set_padding( GTK_MISC( plotview->label ), 2, 0 );\n        gtk_box_pack_end( GTK_BOX( plotview->box ), \n\t\tGTK_WIDGET( plotview->label ), FALSE, FALSE, 0 );\n\tgtk_widget_show( GTK_WIDGET( plotview->label ) );\n}\n\nGtkType\nplotview_get_type( void )\n{\n    \tstatic GtkType type = 0;\n\n    \tif( !type ) {\n    \t\tstatic const GtkTypeInfo info = {\n    \t\t\t\"Plotview\",\n    \t\t\tsizeof( Plotview ),\n    \t\t\tsizeof( PlotviewClass ),\n    \t\t\t(GtkClassInitFunc) plotview_class_init,\n    \t\t\t(GtkObjectInitFunc) plotview_init,\n    \t\t\t/* reserved_1 */ NULL,\n    \t\t\t/* reserved_2 */ NULL,\n    \t\t\t(GtkClassInitFunc) NULL,\n    \t\t};\n\n    \t\ttype = gtk_type_unique( TYPE_GRAPHICVIEW, &info );\n    \t}\n\n    \treturn( type );\n}\n\nView *\nplotview_new( void )\n{\n    \tPlotview *plotview = gtk_type_new( TYPE_PLOTVIEW );\n\n    \treturn( VIEW( plotview ) );\n}\n\n#endif /*HAVE_LIBGOFFICE*/\n"
  },
  {
    "path": "src/plotview.h",
    "content": "/* a plotview in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_PLOTVIEW (plotview_get_type())\n#define PLOTVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_PLOTVIEW, Plotview ))\n#define PLOTVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_PLOTVIEW, PlotviewClass ))\n#define IS_PLOTVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PLOTVIEW ))\n#define IS_PLOTVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PLOTVIEW ))\n\ntypedef struct _Plotview {\n\tGraphicview parent_object;\n\n\tGtkWidget *box;\n\tGtkWidget *label;\n\tGtkWidget *canvas;\n\n\tGogChart *gchart;\n        GogPlot *gplot;\n} Plotview;\n\ntypedef struct _PlotviewClass {\n\tGraphicviewClass parent_class;\n\n\t/* My methods.\n\t */\n} PlotviewClass;\n\nGtkType plotview_get_type( void );\nView *plotview_new( void );\n"
  },
  {
    "path": "src/plotwindow.c",
    "content": "/* a plotpresent / plotmodel in a floating window\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic FloatwindowClass *parent_class = NULL;\n\nstatic void\nplotwindow_destroy( GtkObject *object )\n{\n\tPlotwindow *plotwindow;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_PLOTWINDOW( object ) );\n\n\tplotwindow = PLOTWINDOW( object );\n\n#ifdef DEBUG\n\tprintf( \"plotwindow_destroy: %p\\n\", plotwindow );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\tUNREF( plotwindow->plotmodel );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\nplotwindow_class_init( PlotwindowClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = plotwindow_destroy;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n}\n\nstatic void\nplotwindow_init( Plotwindow *plotwindow )\n{\n#ifdef DEBUG\n\tprintf( \"plotwindow_init: %p\\n\", plotwindow );\n#endif /*DEBUG*/\n\n\tplotwindow->plotmodel = NULL;\n}\n\nGtkType\nplotwindow_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Plotwindow\",\n\t\t\tsizeof( Plotwindow ),\n\t\t\tsizeof( PlotwindowClass ),\n\t\t\t(GtkClassInitFunc) plotwindow_class_init,\n\t\t\t(GtkObjectInitFunc) plotwindow_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_FLOATWINDOW, &info );\n\t}\n\n\treturn( type );\n}\n\nstatic void\nplotwindow_refresh_title( Plotwindow *plotwindow )\n{\n\tPlotmodel *plotmodel = plotwindow->plotmodel;\n\tPlot *plot = plotmodel->plot;\n\tRow *row = HEAPMODEL( plot )->row;\n\tWorkspace *ws = row_get_workspace( row );\n\n#ifdef DEBUG\n\tprintf( \"plotwindow_refresh_title\\n\" );\n#endif /*DEBUG*/\n\n\t/* Can come here during ws destroy.\n\t */\n\tif( ws ) {\n\t\tVipsBuf buf;\n\t\tchar txt[512];\n\n\t\tvips_buf_init_static( &buf, txt, 512 );\n\t\trow_qualified_name_relative( ws->sym, row, &buf );\n\t\tiwindow_set_title( IWINDOW( plotwindow ), \"%s\", \n\t\t\tvips_buf_all( &buf ) );\n\t}\n}\n\n/* The model has changed ... update our menus and titlebar.\n */\nstatic void\nplotwindow_changed_cb( Plotmodel *plotmodel, Plotwindow *plotwindow )\n{\n\tiWindow *iwnd = IWINDOW( plotwindow );\n\n\tGtkAction *action;\n\n\tplotwindow_refresh_title( plotwindow );\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\"Status\" );\n\tgtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),\n\t\tplotmodel->show_status );\n}\n\nstatic void\nplotwindow_mouse_move_cb( Plotpresent *plotpresent, \n\tdouble x, double y, Plotwindow *plotwindow )\n{\n\tplotstatus_mouse( plotwindow->plotstatus, x, y );\n}\n\nstatic void\nplotwindow_show_status_action_cb( GtkToggleAction *action, \n\tPlotwindow *plotwindow )\n{\n\tplotmodel_set_status( plotwindow->plotmodel, \n\t\tgtk_toggle_action_get_active( action ) );\n}\n\nstatic void\nplotwindow_export_done_cb( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n#ifdef HAVE_LIBGOFFICE\n#ifdef HAVE_LIBGSF\n\tFilesel *filesel = FILESEL( iwnd );\n\tPlotwindow *plotwindow = (Plotwindow *) client;\n\tPlotpresent *plotpresent = plotwindow->plotpresent;\n\tGogGraph *ggraph = plotpresent->ggraph;\n\n\tchar *filename; \n\tchar buf[FILENAME_MAX];\n\tchar *extension;\n\tGOImageFormat format;\n\tGsfOutput *output;\n\tGError *err = NULL;\n\tgboolean result;\n\n\tif( !(filename = filesel_get_filename( filesel )) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\texpand_variables( filename, buf );\n\tif( !(output = gsf_output_stdio_new( buf, &err )) ) {\n\t\terror_top( _( \"Unable to write.\" ) );\n\t\tif( err )\n\t\t\terror_sub( \"%s\", err->message );\n\t\tIM_FREEF( g_error_free, err );\n\t\tg_free( filename ); \n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tif( (extension = strrchr( buf, '.' )) )\n\t\textension += 1;\n\telse\t\n\t\textension = buf;\n\tformat = go_image_get_format_from_name( extension ); \n\n\tg_free( filename ); \n\n\tresult = gog_graph_export_image( ggraph, format, output, 72, 72 );\n\n\tUNREF( output );\n\n\tnfn( sys, result ? IWINDOW_YES : IWINDOW_ERROR );\n#endif /*HAVE_LIBGSF*/\n#endif /*HAVE_LIBGOFFICE*/\n}\n\nstatic void\nplotwindow_export_action_cb( GtkAction *action, Plotwindow *plotwindow )\n{\n\tFilesel *filesel = FILESEL( filesel_new() );\n\n\tiwindow_set_title( IWINDOW( filesel ), \n\t\t\"%s\", _( \"Export Plot As\" ) ); \n\tfilesel_set_flags( filesel, TRUE, TRUE );\n\tfilesel_set_filetype( filesel, filesel_type_image, IMAGE_FILE_TYPE ); \n\tiwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( plotwindow ) );\n\tfilesel_set_done( filesel, plotwindow_export_done_cb, plotwindow );\n\tiwindow_build( IWINDOW( filesel ) );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\nstatic GtkToggleActionEntry plotwindow_toggle_actions[] = {\n\t{ \"Status\",\n\t\tNULL, N_( \"_Status\" ), NULL,\n\t\tN_( \"Show status bar\" ),\n\t\tG_CALLBACK( plotwindow_show_status_action_cb ), TRUE }\n};\n\nstatic GtkActionEntry plotwindow_actions[] = {\n\t{ \"Export\", \n\t\tGTK_STOCK_SAVE_AS, N_( \"Export Plot\" ), NULL,\n\t\tN_( \"Export plot to file\" ), \n\t\tG_CALLBACK( plotwindow_export_action_cb ) }\n};\n\nstatic const char *plotwindow_menubar_ui_description =\n\"<ui>\"\n\"  <menubar name='PlotwindowMenubar'>\"\n\"    <menu action='FileMenu'>\"\n\"      <menuitem action='Export'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Close'/>\"\n\"      <menuitem action='Quit'/>\"\n\"    </menu>\"\n\"    <menu action='ViewMenu'>\"\n\"      <menuitem action='Status'/>\"\n\"    </menu>\"\n\"    <menu action='HelpMenu'>\"\n\"      <menuitem action='Guide'/>\"\n\"      <menuitem action='About'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Homepage'/>\"\n\"    </menu>\"\n\"  </menubar>\"\n\"</ui>\";\n\nstatic void\nplotwindow_build( Plotwindow *plotwindow, GtkWidget *vbox, Plot *plot )\n{\n\tiWindow *iwnd = IWINDOW( plotwindow );\n\n\tGError *error;\n\tGtkWidget *mbar;\n\tGtkWidget *frame;\n\tGList *focus_chain;\n\n\tint w, h; \n\n\t/* Make our model.\n\t */\n\tplotwindow->plotmodel = plotmodel_new( plot );\n\tg_object_ref( G_OBJECT( plotwindow->plotmodel ) );\n\tiobject_sink( IOBJECT( plotwindow->plotmodel ) );\n\tg_signal_connect( G_OBJECT( plotwindow->plotmodel ), \"changed\", \n\t\tG_CALLBACK( plotwindow_changed_cb ), plotwindow );\n\n        /* Make main menu bar\n         */\n\tgtk_action_group_add_actions( iwnd->action_group, \n\t\tplotwindow_actions, G_N_ELEMENTS( plotwindow_actions ), \n\t\tGTK_WINDOW( plotwindow ) );\n\tgtk_action_group_add_toggle_actions( iwnd->action_group,\n\t\tplotwindow_toggle_actions, \n\t\t\tG_N_ELEMENTS( plotwindow_toggle_actions ), \n\t\tGTK_WINDOW( plotwindow ) );\n\n\terror = NULL;\n\tif( !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager,\n\t\t\tplotwindow_menubar_ui_description, -1, &error ) ) {\n\t\tg_message( \"building menus failed: %s\", error->message );\n\t\tg_error_free( error );\n\t\texit( EXIT_FAILURE );\n\t}\n\n\tmbar = gtk_ui_manager_get_widget( iwnd->ui_manager, \n\t\t\"/PlotwindowMenubar\" );\n\tgtk_box_pack_start( GTK_BOX( vbox ), mbar, FALSE, FALSE, 0 );\n        gtk_widget_show( mbar );\n\n\t/* Status bar. Show/hide set on first refresh.\n\t */\n\tplotwindow->plotstatus = plotstatus_new( plotwindow->plotmodel );\n\tgtk_box_pack_start( GTK_BOX( vbox ), \n\t\tGTK_WIDGET( plotwindow->plotstatus ), FALSE, FALSE, 0 );\n\n\t/* Plot area. \n\t */\n\tframe = gtk_frame_new( NULL );\n\tgtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_OUT );\n\tgtk_widget_show( frame );\n\tgtk_box_pack_start( GTK_BOX( vbox ), \n\t\tGTK_WIDGET( frame ), TRUE, TRUE, 0 );\n\n#ifdef HAVE_LIBGOFFICE\n\tplotwindow->plotpresent = plotpresent_new( plotwindow->plotmodel );\n#endif /*HAVE_LIBGOFFICE*/\n\tgtk_container_add( GTK_CONTAINER( frame ), \n\t\tGTK_WIDGET( plotwindow->plotpresent )  );\n\tgtk_widget_show( GTK_WIDGET( plotwindow->plotpresent ) );\n\tg_signal_connect( G_OBJECT( plotwindow->plotpresent ), \"mouse_move\", \n\t\tG_CALLBACK( plotwindow_mouse_move_cb ), plotwindow );\n\n\t/* Initial window size.\n\t */\n\tif( MODEL( plot )->window_width == -1 ) {\n\t\tw = IM_MIN( IMAGE_WINDOW_WIDTH, 500 );\n\t\th = IM_MIN( IMAGE_WINDOW_HEIGHT, 500 );\n\t\tgtk_window_set_default_size( GTK_WINDOW( plotwindow ), w, h );\n\t}\n\n\t/* Override the focus_chain ... we want the imagedisplay first.\n\t */\n\tfocus_chain = NULL;\n\tfocus_chain = g_list_append( focus_chain, plotwindow->plotpresent );\n\tgtk_container_set_focus_chain( GTK_CONTAINER( vbox ), focus_chain );\n\tgtk_widget_grab_focus( GTK_WIDGET( plotwindow->plotpresent ) );\n}\n\nstatic void\nplotwindow_popdown( iWindow *iwnd, void *client,\n\tiWindowNotifyFn nfn, void *sys )\n{\n\tPlotwindow *plotwindow = PLOTWINDOW( iwnd );\n\tPlotmodel *plotmodel = plotwindow->plotmodel;\n\tPlot *plot = plotmodel->plot;\n\n\t/* We have to note position/size in popdown rather than destroy, since\n\t * the widgets have to all still be extant.\n\t */\n\tplot->show_status = plotmodel->show_status;\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nplotwindow_link( Plotwindow *plotwindow, Plot *plot, GtkWidget *parent )\n{\n\tiwindow_set_build( IWINDOW( plotwindow ), \n\t\t(iWindowBuildFn) plotwindow_build, plot, NULL, NULL );\n\tiwindow_set_parent( IWINDOW( plotwindow ), parent );\n\tiwindow_set_popdown( IWINDOW( plotwindow ), plotwindow_popdown, NULL );\n\tfloatwindow_link( FLOATWINDOW( plotwindow ), MODEL( plot ) );\n\tiwindow_build( IWINDOW( plotwindow ) );\n\n\t/* Initial \"changed\" on the model to get all views to init.\n\t */\n\tiobject_changed( IOBJECT( plotwindow->plotmodel ) );\n}\n\nPlotwindow *\nplotwindow_new( Plot *plot, GtkWidget *parent )\n{\n\tPlotwindow *plotwindow = gtk_type_new( TYPE_PLOTWINDOW );\n\n\tplotwindow_link( plotwindow, plot, parent );\n\n\treturn( plotwindow );\n}\n"
  },
  {
    "path": "src/plotwindow.h",
    "content": "/* a plotpresent in a floating window \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_PLOTWINDOW (plotwindow_get_type())\n#define PLOTWINDOW( obj ) (GTK_CHECK_CAST( (obj), TYPE_PLOTWINDOW, Plotwindow ))\n#define PLOTWINDOW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_PLOTWINDOW, PlotwindowClass ))\n#define IS_PLOTWINDOW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PLOTWINDOW ))\n#define IS_PLOTWINDOW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PLOTWINDOW ))\n\nstruct _Plotwindow {\n\tFloatwindow parent_class;\n\n\t/* The model we watch.\n\t */\n\tPlotmodel *plotmodel;\n\n\t/* Widgets.\n\t */\n\tPlotstatus *plotstatus;\n\tPlotpresent *plotpresent;\n};\n\ntypedef struct _PlotwindowClass {\n\tFloatwindowClass parent_class;\n\n\t/* My methods.\n\t */\n} PlotwindowClass;\n\nGtkType plotwindow_get_type( void );\nPlotwindow *plotwindow_new( Plot *plot, GtkWidget *parent );\n"
  },
  {
    "path": "src/popupbutton.c",
    "content": "/* a button that displays a popup menu\n *\n * quick hack from totem-plugin-viewer.c\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk \n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GtkToggleButtonClass *popupbutton_parent_class = NULL;\n\nstatic void\npopupbutton_class_init( PopupbuttonClass *class )\n{\n\tpopupbutton_parent_class = g_type_class_peek_parent( class );\n}\n\nstatic void\npopupbutton_init( Popupbutton *popupbutton )\n{\n\tpopupbutton->menu = NULL;\n}\n\nGType\npopupbutton_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( PopupbuttonClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) popupbutton_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Popupbutton ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) popupbutton_init,\n\t\t};\n\n\t\ttype = g_type_register_static( GTK_TYPE_TOGGLE_BUTTON, \n\t\t\t\"Popupbutton\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\npopupbutton_position_func( GtkMenu *menu, \n\tgint *x, gint *y, gboolean *push_in, GtkWidget *button )\n{\n\tGtkRequisition menu_req;\n\tGtkTextDirection direction;\n\tGtkAllocation allocation;\n\n\tgtk_widget_size_request( GTK_WIDGET( menu ), &menu_req );\n\n\tdirection = gtk_widget_get_direction( button );\n\n\tgdk_window_get_origin( gtk_widget_get_window( button ), x, y );\n\tgtk_widget_get_allocation( button, &allocation );\n\t*x += allocation.x;\n\t*y += allocation.y;\n\n\tif( direction == GTK_TEXT_DIR_LTR )\n\t\t*x += VIPS_MAX( allocation.width - menu_req.width, 0 );\n\telse if( menu_req.width > allocation.width )\n\t\t*x -= menu_req.width - allocation.width;\n\n\t*y += allocation.height;\n\n\t*push_in = FALSE;\n}\n\nstatic void\npopupbutton_over_arrow( Popupbutton *popupbutton, GdkEventButton *event )\n{\n\tGtkWidget *menu = popupbutton->menu;\n\n\tgtk_menu_popup( GTK_MENU( menu ), NULL, NULL, \n\t\t(GtkMenuPositionFunc) popupbutton_position_func,\n\t\tpopupbutton,\n\t\tevent ? event->button : 0,\n\t\tevent ? event->time : gtk_get_current_event_time() );\n}\n\nstatic void\npopupbutton_toggled_cb( Popupbutton *popupbutton )\n{\n\tGtkWidget *menu = popupbutton->menu;\n\n\tif( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( popupbutton ) ) && \n\t\t!gtk_widget_get_visible( menu ) ) {\n\t\t/* We get here only when the menu is activated by a key\n\t\t * press, so that we can select the first menu item.\n\t\t */\n\t\tpopupbutton_over_arrow( popupbutton, NULL );\n\t\tgtk_menu_shell_select_first( GTK_MENU_SHELL( menu ), FALSE );\n\t}\n}\n\nstatic gboolean\npopupbutton_button_press_event_cb( Popupbutton *popupbutton,\n\tGdkEventButton *event )\n{\n\tif( event->button == 1 ) {\n\t\tGtkWidget *menu = popupbutton->menu;\n\n\t\tif( !gtk_widget_get_visible( menu ) ) {\n\t\t\tpopupbutton_over_arrow( popupbutton, event );\n\t\t\tgtk_toggle_button_set_active( \n\t\t\t\tGTK_TOGGLE_BUTTON( popupbutton ), TRUE );\n\t\t} \n\t\telse {\n\t\t\tgtk_menu_popdown( GTK_MENU( menu ) );\n\t\t\tgtk_toggle_button_set_active( \n\t\t\t\tGTK_TOGGLE_BUTTON( popupbutton ), FALSE );\n\t\t}\n\n\t\treturn TRUE;\n\t}\n\n\treturn FALSE;\n}\n\nPopupbutton *\npopupbutton_new( void )\n{\n\tPopupbutton *popupbutton;\n\tGtkWidget *image;\n\n\tpopupbutton = g_object_new( TYPE_POPUPBUTTON, NULL );\n\n\timage = gtk_image_new_from_stock( GTK_STOCK_EXECUTE, \n\t\tGTK_ICON_SIZE_MENU );\n\tgtk_container_add( GTK_CONTAINER( popupbutton ), image );\n\tgtk_widget_show( image );\n\n\tg_signal_connect( popupbutton, \"toggled\",\n\t\tG_CALLBACK( popupbutton_toggled_cb ), NULL );\n\tg_signal_connect( popupbutton, \"button-press-event\",\n\t\tG_CALLBACK( popupbutton_button_press_event_cb ), NULL );\n\n\treturn( popupbutton );\n}\n\nstatic void\npopupbutton_menu_unmap_cb( GtkWidget *menu,\n\t\t     Popupbutton *popupbutton )\n{\n\tgtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( popupbutton ), FALSE );\n}\n\nvoid\npopupbutton_set_menu( Popupbutton *popupbutton, GtkWidget *menu )\n{\n\tg_assert( !popupbutton->menu );\n\n\tpopupbutton->menu = menu;\n\n\tg_signal_connect( menu, \"unmap\",\n\t\tG_CALLBACK( popupbutton_menu_unmap_cb ), popupbutton );\n}\n"
  },
  {
    "path": "src/popupbutton.h",
    "content": "/* a button that displays a popup menu\n *\n * quick hack from totem-plugin-viewer.c\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_POPUPBUTTON (popupbutton_get_type())\n#define POPUPBUTTON( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_POPUPBUTTON, Popupbutton ))\n#define POPUPBUTTON_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_POPUPBUTTON, PopupbuttonClass ))\n#define IS_POPUPBUTTON( obj ) (GTK_CHECK_TYPE( (obj), TYPE_POPUPBUTTON ))\n#define IS_POPUPBUTTON_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_POPUPBUTTON ))\n\ntypedef struct _Popupbutton {\n\tGtkToggleButton parent_object;\n\n\tGtkWidget *menu;\n} Popupbutton;\n\ntypedef struct _PopupbuttonClass {\n\tGtkToggleButtonClass parent_class;\n\n} PopupbuttonClass;\n\nGtkType popupbutton_get_type( void );\nPopupbutton *popupbutton_new( void );\nvoid popupbutton_set_menu( Popupbutton *Popupbutton, GtkWidget *menu );\n"
  },
  {
    "path": "src/predicate.c",
    "content": "/* Symbol classifiers.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* Is it one of the system members? Hidden in menus and class display. We\n * can't safely use is_super()/is_this() (they are fast), because we can get\n * called during build (before they are working). Use strcmp() instead.\n */\ngboolean\nis_system( Symbol *sym )\n{\n\tSymbol *parent = symbol_get_parent( sym );\n\n\t/* Something like $$lambda1 and friends.\n\t */\n\tif( sym->generated )\n\t\treturn( TRUE );\n\n\tif( strcmp( IOBJECT( sym )->name, MEMBER_CHECK ) == 0 ||\n\t\tstrcmp( IOBJECT( sym )->name, MEMBER_NAME ) == 0 ||\n\t\tstrcmp( IOBJECT( sym )->name, MEMBER_THIS ) == 0 ||\n\t\tIOBJECT( sym )->name[0] == '_' )\n\t\treturn( TRUE );\n\n\tif( parent &&\n\t\t!is_scope( parent ) &&\n\t\tstrcmp( IOBJECT( sym )->name, IOBJECT( parent )->name ) == 0 )\n\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\n/* Something like \"a = Separator;\"\n */\ngboolean\nis_separator( Symbol *sym )\n{\n\tif( sym->expr && \n\t\tsym->expr->compile && \n\t\tsym->expr->compile->tree && \n\t\tsym->expr->compile->tree->type == NODE_LEAF ) {\n\t\tSymbol *leaf = sym->expr->compile->tree->leaf;\n\n\t\treturn( strcmp( IOBJECT( leaf )->name, CLASS_SEPARATOR ) == 0 );\n\t}\n\n\treturn( FALSE );\n}\n\n/* Is a symbol a class.\n */\ngboolean\nis_class( Compile *compile )\n{\n\treturn( compile->is_klass );\n}\n\n/* Is a sym the super member of some class.\n */\ngboolean\nis_super( Symbol *sym )\n{\n\tSymbol *parent = symbol_get_parent( sym );\n\tCompile *parent_compile = parent->expr->compile;\n\n\treturn( parent_compile && \n\t\tis_class( parent_compile ) && \n\t\tsym == parent_compile->super );\n}\n\n/* Is a sym the this member of some class.\n */\ngboolean\nis_this( Symbol *sym )\n{\n\tSymbol *parent = symbol_get_parent( sym );\n\tCompile *parent_compile = parent->expr->compile;\n\n\treturn( is_class( parent_compile ) && sym == parent_compile->this );\n}\n\n/* Is sym a member of an enclosing class of compile.\n */\ngboolean\nis_member_enclosing( Compile *compile, Symbol *sym )\n{\n\tfor( compile = compile_get_parent( compile ); compile; \n\t\tcompile = compile_get_parent( compile ) ) \n\t\tif( is_class( compile ) && compile->sym != sym &&\n\t\t\tICONTAINER( sym )->parent == ICONTAINER( compile ) ) \n\t\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\n/* Is a symbol a compile-time scope (eg. workspace)\n */\ngboolean\nis_scope( Symbol *sym )\n{\n\treturn( sym->type == SYM_ROOT || \n\t\tsym->type == SYM_WORKSPACE || \n\t\tsym->type == SYM_WORKSPACEROOT || \n\t\t!symbol_get_parent( sym ) );\n}\n\n/* Is a symbol a top-level definition. Tops are symbols whose parents are \n * SYM_ROOT, SYM_WORKSPACE and friends.\n */\ngboolean\nis_top( Symbol *sym )\n{\n\tif( is_scope( sym ) || is_scope( symbol_get_parent( sym ) ) )\n\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\n/* Is a symbol a member of a class? Params don't count.\n */\ngboolean\nis_member( Symbol *sym )\n{\n \treturn( is_value( sym ) && \n\t\tis_class( COMPILE( ICONTAINER( sym )->parent ) ) ); \n}\n\n/* Is a compile a member function (not a sub-class)?\n */\ngboolean\nis_memberfunc( Compile *compile )\n{\n \treturn( is_class( compile_get_parent( compile ) ) && \n\t\t!is_class( compile ) );\n}\n\n/* Something that ought to have a value.\n */\ngboolean\nis_value( Symbol *sym )\n{\n \treturn( sym->type == SYM_VALUE && sym->expr );\n}\n\n/* Is sym an ancestor of context?\n */\ngboolean\nis_ancestor( Symbol *context, Symbol *sym )\n{\n\tif( context == sym )\n\t\treturn( TRUE );\n\n\tif( context == symbol_root ) \n\t\treturn( FALSE );\n\n\treturn( is_ancestor( symbol_get_parent( context ), sym ) );\n}\n\ngboolean \nis_menuable( Symbol *sym )\n{\n\t/* In a hidden kit?\n\t */\n\tif( sym->tool && IOBJECT( sym->tool->kit )->name[0] == '_' )\n\t\treturn( FALSE );\n\n\t/* A hidden item?\n\t */\n\tif( IOBJECT( sym )->name[0] == '_' )\n\t\treturn( FALSE );\n\n\t/* We also hide all supers, system things \n\t */\n\tif( !is_value( sym ) || !sym->expr->compile || is_system( sym ) ||\n\t\tstrcmp( IOBJECT( sym )->name, MEMBER_SUPER ) == 0 )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n"
  },
  {
    "path": "src/predicate.h",
    "content": "/* Declarations for predicate.c\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\ngboolean is_system( Symbol *sym );\ngboolean is_separator( Symbol *sym );\ngboolean is_member( Symbol *sym );\ngboolean is_class( Compile *compile );\ngboolean is_super( Symbol *sym );\ngboolean is_this( Symbol *sym );\ngboolean is_member_enclosing( Compile *compile, Symbol *sym );\ngboolean is_top( Symbol *sym );\ngboolean is_scope( Symbol *sym );\ngboolean is_memberfunc( Compile *compile );\ngboolean is_value( Symbol *sym );\ngboolean is_ancestor( Symbol *context, Symbol *sym );\ngboolean is_menuable( Symbol *sym );\n"
  },
  {
    "path": "src/prefcolumnview.c",
    "content": "/* a view of a column\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\nstatic void \nprefcolumnview_refresh( vObject *vobject )\n{\n\tPrefcolumnview *pcview = PREFCOLUMNVIEW( vobject );\n\tColumn *col = COLUMN( VOBJECT( pcview )->iobject );\n\tchar buf[256];\n\tchar buf2[256];\n\n\tescape_markup( IOBJECT( col )->caption, buf2, 256 );\n\tim_snprintf( buf, 256, \"<b>%s</b>\", buf2 );\n\tgtk_label_set_markup( GTK_LABEL( pcview->lab ), buf );\n\n\t/* Closed columns are hidden.\n\t */\n\twidget_visible( GTK_WIDGET( pcview ), col->open );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\nprefcolumnview_child_add( View *parent, View *child )\n{\n\tPrefcolumnview *pcview = PREFCOLUMNVIEW( parent );\n\tSubcolumnview *sview = SUBCOLUMNVIEW( child );\n\n\tVIEW_CLASS( parent_class )->child_add( parent, child );\n\n\tgtk_box_pack_end( GTK_BOX( pcview ), GTK_WIDGET( sview ), \n\t\tFALSE, FALSE, 0 );\n}\n\nstatic void\nprefcolumnview_class_init( PrefcolumnviewClass *class )\n{\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = prefcolumnview_refresh;\n\n\tview_class->child_add = prefcolumnview_child_add;\n}\n\nstatic void\nprefcolumnview_init( Prefcolumnview *pcview )\n{\n        pcview->lab = gtk_label_new( \"\" );\n        gtk_box_pack_start( GTK_BOX( pcview ), pcview->lab, FALSE, FALSE, 2 );\n\tgtk_misc_set_padding( GTK_MISC( pcview->lab ), 2, 6 );\n\tgtk_misc_set_alignment( GTK_MISC( pcview->lab ), 0, 0.5 );\n\n        gtk_widget_show_all( GTK_WIDGET( pcview ) );\n}\n\nGtkType\nprefcolumnview_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Prefcolumnview\",\n\t\t\tsizeof( Prefcolumnview ),\n\t\t\tsizeof( PrefcolumnviewClass ),\n\t\t\t(GtkClassInitFunc) prefcolumnview_class_init,\n\t\t\t(GtkObjectInitFunc) prefcolumnview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_VIEW, &info );\n\t}\n\n\treturn( type );\n}\n\nView *\nprefcolumnview_new( void )\n{\n\tPrefcolumnview *pcview = gtk_type_new( TYPE_PREFCOLUMNVIEW );\n\n\treturn( VIEW( pcview ) );\n}\n\n"
  },
  {
    "path": "src/prefcolumnview.h",
    "content": "/* view of a column in a preferences window\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_PREFCOLUMNVIEW (prefcolumnview_get_type())\n#define PREFCOLUMNVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_PREFCOLUMNVIEW, Prefcolumnview ))\n#define PREFCOLUMNVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_PREFCOLUMNVIEW, PrefcolumnviewClass ))\n#define IS_PREFCOLUMNVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PREFCOLUMNVIEW ))\n#define IS_PREFCOLUMNVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PREFCOLUMNVIEW ))\n\nstruct _Prefcolumnview {\n\tView view;\n\n        /* Display parts.\n         */\n        GtkWidget *lab;               \t/* Prefcolumnview name label */\n};\n\ntypedef struct _PrefcolumnviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} PrefcolumnviewClass;\n\nGtkType prefcolumnview_get_type( void );\nView *prefcolumnview_new( void );\n"
  },
  {
    "path": "src/prefs.c",
    "content": "/* preferences dialog\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* \n#define DEBUG\n */\n\nstatic iDialogClass *parent_class = NULL;\n\nstatic void\nprefs_destroy( GtkObject *object )\n{\n\tPrefs *prefs = PREFS( object );\n\n#ifdef DEBUG\n\tprintf( \"prefs_destroy\\n\" );\n#endif /*DEBUG*/\n\n\tif( prefs->ws ) {\n\t\tWorkspacegroup *wsg = workspace_get_workspacegroup( prefs->ws );\n\t\tFilemodel *filemodel = FILEMODEL( wsg );\n\n\t\t/* Force a recalc, in case we've changed the autorecalc \n\t\t * settings. Also does a scan on any widgets.\n\t\t */\n\t\tsymbol_recalculate_all_force( TRUE );\n\n\t\tif( filemodel->modified &&\n\t\t\tfilemodel_top_save( filemodel, filemodel->filename ) ) \n\t\t\tfilemodel_set_modified( filemodel, FALSE );\n\t}\n\n\t/* My instance destroy stuff.\n\t */\n\tFREESID( prefs->destroy_sid, prefs->ws );\n\tIM_FREE( prefs->caption_filter );\n\tprefs->ws = NULL;\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\nprefs_build( GtkWidget *widget )\n{\n\tPrefs *prefs = PREFS( widget );\n\tGtkWidget *work;\n\n#ifdef DEBUG\n\tprintf( \"prefs_build: %p\\n\", prefs );\n#endif /*DEBUG*/\n\n\t/* Call all builds in superclasses.\n\t */\n\tIWINDOW_CLASS( parent_class )->build( widget );\n\n\twork = IDIALOG( prefs )->work;\n\n\tprefs->pwview = PREFWORKSPACEVIEW( prefworkspaceview_new() );\n\tprefworkspaceview_set_caption_filter( prefs->pwview, \n\t\tprefs->caption_filter );\n\tview_link( VIEW( prefs->pwview ), MODEL( prefs->ws ), NULL );\n\n\tif( prefs->caption_filter ) {\n\t\tgtk_box_pack_start( GTK_BOX( work ), \n\t\t\tGTK_WIDGET( prefs->pwview ), TRUE, TRUE, 0 );\n\n\t\tgtk_widget_show( GTK_WIDGET( prefs->pwview ) );\n\t}\n\telse {\n\t\t/* No caption_filter set, so this is probably a big prefs\n\t\t * window. Build a scrolledwindow for the content.\n\t\t */\n\t\tGtkWidget *window;\n\n\t\twindow = gtk_scrolled_window_new( NULL, NULL );\n\t\tgtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( window ), \n\t\t\tGTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );\n\t\tgtk_scrolled_window_add_with_viewport( \n\t\t\tGTK_SCROLLED_WINDOW( window ), \n\t\t\tGTK_WIDGET( prefs->pwview ) );\n\t\tgtk_viewport_set_shadow_type( \n\t\t\tGTK_VIEWPORT( GTK_BIN( window )->child ), \n\t\t\tGTK_SHADOW_NONE );\n\t\tgtk_box_pack_start( GTK_BOX( work ), \n\t\t\tGTK_WIDGET( window ), TRUE, TRUE, 0 );\n\n\t\tgtk_widget_show( GTK_WIDGET( prefs->pwview ) );\n\t\tgtk_widget_show( window );\n\t}\n}\n\nstatic void\nprefs_class_init( PrefsClass *class )\n{\n\tGtkObjectClass *gobject_class = (GtkObjectClass *) class;\n\tiWindowClass *iwindow_class = (iWindowClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->destroy = prefs_destroy;\n\n\tiwindow_class->build = prefs_build;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n}\n\nstatic void\nprefs_init( Prefs *prefs )\n{\n\tprefs->ws = NULL;\n\tprefs->destroy_sid = 0;\n}\n\nGType\nprefs_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( PrefsClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) prefs_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Prefs ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) prefs_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_IDIALOG, \n\t\t\t\"Prefs\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\nprefs_workspace_destroy_cb( Workspace *ws, Prefs *prefs )\n{\n\tprefs->destroy_sid = 0;\n\tprefs->ws = NULL;\n\n\tiwindow_kill( IWINDOW( prefs ) );\n}\n\nstatic void\nprefs_link( Prefs *prefs, Workspace *ws )\n{\n\tg_assert( !prefs->ws );\n\n\tprefs->ws = ws;\n\tprefs->ws->mode = WORKSPACE_MODE_NOEDIT;\n\tprefs->destroy_sid = g_signal_connect( ws, \"destroy\",\n\t\tG_CALLBACK( prefs_workspace_destroy_cb ), prefs );\n}\n\nstatic gint \nprefs_column_compare( Column *a, Column *b )\n{\n\treturn( b->y - a->y );\n}\n\nPrefs *\nprefs_new( const char *caption_filter )\n{\n\tSymbol *wsr_sym = main_workspaceroot->sym;\n\tSymbol *ws_sym = SYMBOL( icontainer_child_lookup( \n\t\tICONTAINER( wsr_sym->expr->compile ), \"Preferences\" ) );\n\tPrefs *prefs;\n\n\tif( !ws_sym ) {\n\t\t/* Probably failed to load prefs on startup for some reason.\n\t\t */\n\t\terror_top( _( \"Unable to display preferences.\" ) );\n\t\terror_sub( _( \"No preferences workspace was found. \"\n\t\t\t\"Preferences probably failed to load when \"\n\t\t\t\"%s started.\" ),\n\t\t\tPACKAGE );\n\t\treturn( NULL );\n\t}\n\n\ticontainer_custom_sort( ICONTAINER( ws_sym->ws ),\n\t\t(GCompareFunc) prefs_column_compare );\n\tprefs = PREFS( g_object_new( TYPE_PREFS, NULL ) );\n\tIM_SETSTR( prefs->caption_filter, caption_filter );\n\tprefs_link( prefs, ws_sym->ws );\n\n\treturn( prefs );\n}\n\ngboolean\nprefs_set( const char *name, const char *fmt, ... )\n{\n\tWatch *watch;\n\n\tif( main_watchgroup &&\n\t\t(watch = watch_find( main_watchgroup, name )) ) {\n\t\tva_list args;\n\n\t\tva_start( args, fmt );\n\t\twatch_vset( watch, fmt, args );\n\t\tva_end( args );\n\t}\n\n\treturn( TRUE );\n}\n"
  },
  {
    "path": "src/prefs.h",
    "content": "/* Declarations for the preferences dialog.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_PREFS (prefs_get_type())\n#define PREFS( obj ) (GTK_CHECK_CAST( (obj), TYPE_PREFS, Prefs ))\n#define PREFS_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_PREFS, PrefsClass ))\n#define IS_PREFS( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PREFS ))\n#define IS_PREFS_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PREFS ))\n\ntypedef struct _Prefs {\n\tiDialog parent_object;\n\n\t/* Workspace we display.\n\t */\n\tWorkspace *ws;\n\tguint destroy_sid;\n\n\tPrefworkspaceview *pwview;\n\n\t/* (optionally) filter prefs with this.\n\t */\n\tchar *caption_filter;\n} Prefs;\n\ntypedef struct _PrefsClass {\n\tiWindowClass parent_class;\n\n\t/* My methods.\n\t */\n} PrefsClass;\n\nGType prefs_get_type( void );\nPrefs *prefs_new( const char *caption_filter );\ngboolean prefs_set( const char *name, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\n"
  },
  {
    "path": "src/prefworkspaceview.c",
    "content": "/* a prefworkspaceview button in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n/* Define to trace button press events.\n#define EVENT\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\nstatic void\nprefworkspaceview_destroy( GtkObject *object )\n{\n\tPrefworkspaceview *pwview;\n\n#ifdef DEBUG\n\tprintf( \"prefworkspaceview_destroy\\n\" );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_PREFWORKSPACEVIEW( object ) );\n\n\tpwview = PREFWORKSPACEVIEW( object );\n\n\t/* Instance destroy.\n\t */\n\tIM_FREE( pwview->caption_filter );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\nprefworkspaceview_child_add( View *parent, View *child )\n{\n\tPrefworkspaceview *pwview = PREFWORKSPACEVIEW( parent );\n\n\tVIEW_CLASS( parent_class )->child_add( parent, child );\n\n\tgtk_box_pack_end( GTK_BOX( pwview ),\n\t\tGTK_WIDGET( child ), FALSE, FALSE, 0 );\n}\n\n/* Should a child model have a display?\n */\nstatic gboolean\nprefworkspaceview_display( View *parent, Model *child )\n{\n\tPrefworkspaceview *pwview = PREFWORKSPACEVIEW( parent );\n\tColumn *column = COLUMN( child );\n\n\tif( pwview->caption_filter ) \n\t\treturn( strstr( IOBJECT( column )->caption, \n\t\t\tpwview->caption_filter ) != NULL );\n\telse\n\t\treturn( TRUE );\n}\n\nstatic void\nprefworkspaceview_class_init( PrefworkspaceviewClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = prefworkspaceview_destroy;\n\n\tview_class->child_add = prefworkspaceview_child_add;\n\tview_class->display = prefworkspaceview_display;\n}\n\nstatic void\nprefworkspaceview_init( Prefworkspaceview *pwview )\n{\n\tpwview->caption_filter = NULL; \n}\n\nGtkType\nprefworkspaceview_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Prefworkspaceview\",\n\t\t\tsizeof( Prefworkspaceview ),\n\t\t\tsizeof( PrefworkspaceviewClass ),\n\t\t\t(GtkClassInitFunc) prefworkspaceview_class_init,\n\t\t\t(GtkObjectInitFunc) prefworkspaceview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_VIEW, &info );\n\t}\n\n\treturn( type );\n}\n\nView *\nprefworkspaceview_new( void )\n{\n\tPrefworkspaceview *pwview = gtk_type_new( TYPE_PREFWORKSPACEVIEW );\n\n\treturn( VIEW( pwview ) );\n}\n\nvoid \nprefworkspaceview_set_caption_filter( Prefworkspaceview *pwview, \n\tconst char *caption_filter )\n{\n\tIM_SETSTR( pwview->caption_filter, caption_filter );\n\n\t/* caption_filter is a property of the view, not the model, so we have\n\t * to queue a refresh rather than just signalling change.\n\t */\n\tvobject_refresh_queue( VOBJECT( pwview ) );\n}\n"
  },
  {
    "path": "src/prefworkspaceview.h",
    "content": "/* a view of a workspace for the preferences window\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_PREFWORKSPACEVIEW (prefworkspaceview_get_type())\n#define PREFWORKSPACEVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_PREFWORKSPACEVIEW, Prefworkspaceview ))\n#define PREFWORKSPACEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_PREFWORKSPACEVIEW, PrefworkspaceviewClass ))\n#define IS_PREFWORKSPACEVIEW( obj ) \\\n\t(GTK_CHECK_TYPE( (obj), TYPE_PREFWORKSPACEVIEW ))\n#define IS_PREFWORKSPACEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PREFWORKSPACEVIEW ))\n\nstruct _Prefworkspaceview {\n\tView view;\n\n\t/* If set, only display the columns whose caption includes this string \n\t * (eg. \"JPEG\"). Used to display tiny prefs windows for jpeg save etc.\n\t */\n\tchar *caption_filter;\n};\n\ntypedef struct _PrefworkspaceviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} PrefworkspaceviewClass;\n\nGtkType prefworkspaceview_get_type( void );\nView *prefworkspaceview_new( void );\n\nvoid prefworkspaceview_set_caption_filter( Prefworkspaceview *pwview, \n\tconst char *caption_filter );\n"
  },
  {
    "path": "src/preview.c",
    "content": "/* thumbnail widget\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* \n#define DEBUG\n */\n\n/* Number of columns of pixmaps we display.\n */\n#define NUM_COLUMNS (4)\n\nstatic ImagedisplayClass *parent_class = NULL;\n\nstatic void\npreview_destroy( GtkObject *object )\n{\n\tPreview *preview;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_PREVIEW( object ) );\n\n\tpreview = PREVIEW( object );\n\n\tUNREF( preview->conv );\n\tIM_FREE( preview->filename );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\npreview_class_init( PreviewClass *class )\n{\n\tGtkObjectClass *object_class;\n\n\tobject_class = (GtkObjectClass *) class;\n\n\tobject_class->destroy = preview_destroy;\n\n\tparent_class = g_type_class_peek_parent( class );\n}\n\nstatic void\npreview_init( Preview *preview )\n{\n#ifdef DEBUG\n\tprintf( \"preview_init: %p\\n\", preview );\n#endif /*DEBUG*/\n\n\tpreview->filename = NULL;\n\tpreview->conv = conversion_new( NULL );\n\tpreview->conv->tile_size = 16;\n\tgtk_widget_set_size_request( GTK_WIDGET( preview ), 128, 128 );\n\timagedisplay_set_conversion( IMAGEDISPLAY( preview ), preview->conv );\n\timagedisplay_set_shrink_to_fit( IMAGEDISPLAY( preview ), TRUE );\n\tg_object_ref( G_OBJECT( preview->conv ) );\n}\n\nGtkType\npreview_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type)  {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Preview\",\n\t\t\tsizeof( Preview ),\n\t\t\tsizeof( PreviewClass ),\n\t\t\t(GtkClassInitFunc) preview_class_init,\n\t\t\t(GtkObjectInitFunc) preview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_IMAGEDISPLAY, &info );\n\t}\n\n\treturn( type );\n}\n\nPreview *\npreview_new( void )\n{\n\tPreview *preview = (Preview *) gtk_type_new( TYPE_PREVIEW );\n\n\treturn( preview );\n}\n\nstatic void\npreview_set_filename_idle( Preview *preview, char *filename )\n{\n\tImageinfo *ii;\n\n\t/* Make sure our enclosing preview wasn't been killed before this idle\n\t * starts.\n\t */\n\tif( !preview->conv )\n\t\treturn;\n\n\t/* This is the call that can take ages and kill everything.\n\t */\n\tif( !(ii = imageinfo_new_input( main_imageinfogroup, \n\t\tGTK_WIDGET( preview ), NULL, filename )) ) \n\t\treturn;\n\n\t/* So test for alive-ness again.\n\t */\n\tif( preview->conv ) {\n\t\tchar txt[MAX_LINELENGTH];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\tconversion_set_image( preview->conv, ii );\n\t\tIM_SETSTR( preview->filename, filename );\n\n\t\t/* How strange, we need this to get the \n\t\t * background to clear fully.\n\t\t */\n\t\tgtk_widget_queue_draw( GTK_WIDGET( preview ) );\n\n\t\tget_image_info( &buf, IOBJECT( preview->conv->ii )->name );\n\t\tset_tooltip( GTK_WIDGET( preview ), \n\t\t\t\"%s\", vips_buf_all( &buf ) );\n\t}\n\n\tMANAGED_UNREF( ii );\n}\n\ntypedef struct _UpdateProxy {\n\tPreview *preview;\n\tchar *filename;\n} UpdateProxy;\n\nstatic gboolean\npreview_set_filename_idle_cb( UpdateProxy *proxy )\n{\n\tpreview_set_filename_idle( proxy->preview, proxy->filename );\n\n\tUNREF( proxy->preview );\n\tg_free( proxy );\n\n\t/* Don't run again.\n\t */\n\treturn( FALSE );\n}\n\n/* We can't load in-line, it can take ages and trigger progress callbacks,\n * which in turn, could kill our enclosing widget.\n *\n * Instead, we do the load in a idle callback and update the preview at the\n * end, if it's still valid.\n */\nvoid\npreview_set_filename( Preview *preview, char *filename )\n{\n\tUpdateProxy *proxy = g_new( UpdateProxy, 1 );\n\n\t/* We are going to put the preview into the idle queue. It must remain\n\t * valid until the idle handler is handled, so we ref.\n\t */\n\tg_object_ref( preview );\n\n\tproxy->preview = preview;\n\tproxy->filename = g_strdup( filename );\n\n\tg_idle_add( (GSourceFunc) preview_set_filename_idle_cb, proxy );\n}\n"
  },
  {
    "path": "src/preview.h",
    "content": "/* thumbnail widget\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_PREVIEW (preview_get_type())\n#define PREVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_PREVIEW, Preview ))\n#define PREVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_PREVIEW, PreviewClass ))\n#define IS_PREVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PREVIEW ))\n#define IS_PREVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PREVIEW ))\n\nstruct _Preview {\n\tImagedisplay parent;\n\n\tchar *filename;\t\t\t/* The file we are trying to display */\n\tConversion *conv;\t\t/* Hold a ref to the convert object */\n};\n\ntypedef struct _PreviewClass {\n\tImagedisplayClass parent_class;\n\n\t/* My methods.\n\t */\n} PreviewClass;\n\nGtkType preview_get_type( void );\nPreview *preview_new( void );\nvoid preview_set_filename( Preview *preview, char *filename );\n"
  },
  {
    "path": "src/program.c",
    "content": "/* program window\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n#define DEBUG_TREE\n */\n\n#include \"ip.h\"\n\n/* Keep tools/kits in a treestore. Also pointers to managed objects.\n */\nenum {\n\tNAME_COLUMN,\t\t\t/* Kit or tool name */\n\tTOOL_POINTER_COLUMN,\t\t/* Pointer to tool */\n\tKIT_POINTER_COLUMN,\t\t/* Pointer to kit (if no tool) */\n\tN_COLUMNS\n};\n\nstatic iWindowClass *parent_class = NULL;\n\nstatic GSList *program_all = NULL;\n\nstatic GtkWidget *program_menu = NULL;\n\nstatic Model *\nprogram_get_selected( Program *program )\n{\n\tModel *model;\n\n\tif( program->tool )\n\t\tmodel = MODEL( program->tool );\n\telse if( program->kit )\n\t\tmodel = MODEL( program->kit );\n\telse \n\t\tmodel = NULL;\n\n\treturn( model );\n}\n\nstatic void\nprogram_info( Program *program, VipsBuf *buf )\n{\n\tModel *model = program_get_selected( program );\n\n\tvips_buf_appendf( buf, _( \"Edit window\" ) );\n\tvips_buf_appendf( buf, \"\\n\" );\n\tvips_buf_appendf( buf, \"dirty = \\\"%s\\\"\\n\", bool_to_char( program->dirty ) );\n\tvips_buf_appendf( buf, \"\\n\" );\n\n\tif( model ) {\n\t\tiobject_info( IOBJECT( model ), buf );\n\t\tvips_buf_appendf( buf, \"\\n\" );\n\t}\n}\n\ngboolean\nmy_strcmp( const char *a, const char *b )\n{\n\tif( a == b )\n\t\treturn( 0 );\n\tif( !a )\n\t\treturn( -1 );\n\tif( !b )\n\t\treturn( -1 );\n\n\treturn( strcmp( a, b ) );\n}\n\n/* Remove this and any subsequent nodes at this level.\n */\nstatic void\nprogram_refresh_trim( Program *program, GtkTreePath *path )\n{\n\tGtkTreeIter iter;\n\n\twhile( gtk_tree_model_get_iter( GTK_TREE_MODEL( program->store ), \n\t\t&iter, path ) ) {\n#ifdef DEBUG_TREE\n\t\tprintf( \"program_refresh_trim: removing %s\\n\",\n\t\t\tgtk_tree_path_to_string ( path ) );\n#endif /*DEBUG_TREE*/\n\n\t\tgtk_tree_store_remove( program->store, &iter );\n\t}\n}\n\nstatic void\nprogram_refresh_update( Program *program, GtkTreePath *path,\n\tconst char *name, Tool *tool, Toolkit *kit )\n{\n\tGtkTreeIter iter;\n\n\t/* Update, or append if there's nothing to update.\n\t */\n\tif( gtk_tree_model_get_iter( GTK_TREE_MODEL( program->store ), \n\t\t&iter, path ) ) {\n\t\t/* Node exists.\n \t\t */\n\t\tchar *store_name;\n\t\tTool *store_tool;\n\t\tToolkit *store_kit;\n\n\t\tgtk_tree_model_get( GTK_TREE_MODEL( program->store ), &iter,\n\t\t\tNAME_COLUMN, &store_name,\n\t\t\tTOOL_POINTER_COLUMN, &store_tool,\n\t\t\tKIT_POINTER_COLUMN, &store_kit,\n\t\t\t-1 );\n\n\t\tif( tool != store_tool ||\n\t\t\tkit != store_kit ||\n\t\t\tmy_strcmp( name, store_name ) != 0 ) {\n#ifdef DEBUG_TREE\n\t\t\tprintf( \"program_refresh_update: updating \\\"%s\\\"\\n\",\n\t\t\t\tname );\n#endif /*DEBUG_TREE*/\n\t\t\tgtk_tree_store_set( program->store, \n\t\t\t\t&iter,\n\t\t\t\tNAME_COLUMN, name,\n\t\t\t\tTOOL_POINTER_COLUMN, tool,\n\t\t\t\tKIT_POINTER_COLUMN, kit,\n\t\t\t\t-1 );\n\t\t}\n\n\t\tg_free( store_name );\n\n\t\t/* Make sure tool nodes have no children ... this can happen \n\t\t * after some drags.\n\t\t */\n\t\tif( tool && \n\t\t\tgtk_tree_model_iter_has_child( \n\t\t\t\tGTK_TREE_MODEL( program->store ), &iter ) ) {\n\t\t\tGtkTreePath *child_path;\n\n\t\t\tchild_path = gtk_tree_path_copy( path );\n\t\t\tgtk_tree_path_down( child_path );\n\t\t\tprogram_refresh_trim( program, child_path );\n\t\t\tgtk_tree_path_free( child_path );\n\t\t}\n\t}\n\telse {\n\t\tGtkTreeIter parent_iter;\n\t\tGtkTreeIter *piter;\n\n#ifdef DEBUG_TREE\n\t\tprintf( \"program_refresh_update: creating \\\"%s\\\"\\n\", name );\n#endif /*DEBUG_TREE*/\n \n\t\t/* Get an iter for the parent node, if it exists.\n\t\t */\n\t\tif( gtk_tree_path_get_depth( path ) > 1 ) {\n\t\t\tGtkTreePath *parent_path;\n\t\n\t\t\tparent_path = gtk_tree_path_copy( path );\n\t\t\tgtk_tree_path_up( parent_path );\n\t\t\tgtk_tree_model_get_iter( \n\t\t\t\tGTK_TREE_MODEL( program->store ),\n\t\t\t\t&parent_iter, parent_path );\n\t\t\tgtk_tree_path_free( parent_path );\n\t\t\tpiter = &parent_iter;\n\t\t}\n\t\telse \n\t\t\tpiter = NULL;\n\n\t\tgtk_tree_store_append( program->store, &iter, piter );\n\t\tgtk_tree_store_set( program->store, &iter,\n\t\t\tNAME_COLUMN, name,\n\t\t\tTOOL_POINTER_COLUMN, tool,\n\t\t\tKIT_POINTER_COLUMN, kit,\n\t\t\t-1 );\n\t}\n}\n\nstatic void *\nprogram_refresh_tool( Tool *tool, Program *program, GtkTreePath *path )\n{\n\tif( tool->toolitem )\n\t\tprogram_refresh_update( program, path,\n\t\t\tIOBJECT( tool )->name, tool, tool->kit );\n\telse\n\t\tprogram_refresh_update( program, path,\n\t\t\tIOBJECT( tool )->name, tool, tool->kit );\n\n\tgtk_tree_path_next( path );\n\n\treturn( NULL );\n}\n\nstatic void *\nprogram_refresh_kit( Toolkit *kit, Program *program, GtkTreePath *path )\n{\n\tprogram_refresh_update( program, path,\n\t\tIOBJECT( kit )->name, NULL, kit );\n\n\tgtk_tree_path_down( path );\n\ttoolkit_map( kit, \n\t\t(tool_map_fn) program_refresh_tool, program, path );\n\n\t/* Remove any unused tool nodes.\n\t */\n\tprogram_refresh_trim( program, path );\n\n\tgtk_tree_path_up( path );\n\n\tgtk_tree_path_next( path );\n\n\treturn( NULL );\n}\n\n/* Update the title.\n */\nstatic void\nprogram_title( Program *program )\n{\n\tchar txt[512];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tif( program->kit && FILEMODEL( program->kit )->modified ) \n\t\tvips_buf_appendf( &buf, \"*\" ); \n\tvips_buf_appends( &buf, IOBJECT( program->kitg )->name );\n\tif( program->kit ) \n\t\tvips_buf_appendf( &buf, \" - %s\", IOBJECT( program->kit )->name );\n\tif( program->tool ) {\n\t\tvips_buf_appendf( &buf, \" - %s\", IOBJECT( program->tool )->name );\n\n\t\tif( program->dirty ) {\n\t\t\tvips_buf_appendf( &buf, \" [\" );\n\t\t\tvips_buf_appendf( &buf, _( \"modified\" ) );\n\t\t\tvips_buf_appendf( &buf, \"]\" );\n\t\t}\n\t}\n\n\tiwindow_set_title( IWINDOW( program ), \"%s\", vips_buf_all( &buf ) );\n}\n\ntypedef struct _ProgramRowLookupInfo {\n\tProgram *program;\n\n\tModel *model;\n\tGtkTreeIter *return_iter;\n\tgboolean found;\n} ProgramRowLookupInfo;\n\nstatic gboolean\nprogram_row_lookup_sub( GtkTreeModel *model,\n\tGtkTreePath *path, GtkTreeIter *iter, ProgramRowLookupInfo *info )\n{\n\tTool *tool;\n\tToolkit *kit;\n\n\tgtk_tree_model_get( model, iter,\n\t\tTOOL_POINTER_COLUMN, &tool,\n\t\tKIT_POINTER_COLUMN, &kit,\n\t\t-1 );\n\n\tif( (void *) tool == (void *) info->model || \n\t\t(void *) kit == (void *) info->model ) {\n\t\t*info->return_iter = *iter;\n\t\tinfo->found = TRUE;\n\t\treturn( TRUE );\n\t}\n\n\treturn( FALSE );\n}\n\n/* Point return_iter at the row containing a pointer to the Model.\n */\nstatic gboolean\nprogram_row_lookup( Program *program, Model *model, GtkTreeIter *return_iter )\n{\n\tProgramRowLookupInfo info;\n\n\tinfo.program = program;\n\tinfo.model = model;\n\tinfo.return_iter = return_iter;\n\tinfo.found = FALSE;\n\n\tgtk_tree_model_foreach( GTK_TREE_MODEL( program->store ),\n\t\t(GtkTreeModelForeachFunc) program_row_lookup_sub, &info );\n\n\treturn( info.found );\n}\n\nstatic gboolean\nprogram_refresh_timeout( gpointer user_data )\n{\n\tProgram *program = PROGRAM( user_data ); \n\tiWindow *iwnd = IWINDOW( program );\n\tModel *model = program_get_selected( program );\n\tGtkTreeSelection *select = \n\t\tgtk_tree_view_get_selection( GTK_TREE_VIEW( program->tree ) );\n\n\tGtkTreePath *path;\n\tGtkTreeIter iter;\n        GtkAction *action;\n\n\tprogram->refresh_timeout = 0;\n\n#ifdef DEBUG\n\tprintf( \"program_refresh_timeout\\n\" );\n#endif /*DEBUG*/\n\n\t/* Block insert/delete/select signals.\n\t */\n\tg_signal_handler_block( G_OBJECT( program->store ), \n\t\tprogram->row_deleted_sid );\n\tg_signal_handler_block( G_OBJECT( program->store ), \n\t\tprogram->row_inserted_sid );\n\tg_signal_handler_block( G_OBJECT( select ), \n\t\tprogram->select_changed_sid );\n\n\t/* Rebuild the tree widget.\n\t */\n\tpath = gtk_tree_path_new();\n\tgtk_tree_path_down( path );\n\ttoolkitgroup_map( program->kitg,\n\t\t(toolkit_map_fn) program_refresh_kit, program, path );\n\n\t/* Remove any unused kit nodes.\n\t */\n\tprogram_refresh_trim( program, path );\n\n\tgtk_tree_path_free( path );\n\n\tg_signal_handler_unblock( G_OBJECT( program->store ), \n\t\tprogram->row_inserted_sid );\n\tg_signal_handler_unblock( G_OBJECT( program->store ), \n\t\tprogram->row_deleted_sid );\n\n\t/* Update title bar.\n\t */\n\tprogram_title( program );\n\n\t/* Scroll to current kit or tool.\n\t */\n\tif( model &&\n\t\tprogram_row_lookup( program, model, &iter ) ) {\n\n\t\tpath = gtk_tree_model_get_path( \n\t\t\tGTK_TREE_MODEL( program->store ), &iter );\n\n\t\t/* Only expand tools ... we want to be able to select kits\n\t\t * without expansion.\n\t\t */\n\t\tif( IS_TOOL( model ) )\n\t\t\tgtk_tree_view_expand_to_path( \n\t\t\t\tGTK_TREE_VIEW( program->tree ),\n\t\t\t\tpath );\n\n\t\tgtk_tree_view_set_cursor( GTK_TREE_VIEW( program->tree ),\n\t\t\tpath, NULL,\n\t\t\tFALSE );\n\n\t\tgtk_tree_path_free( path );\n\t}\n\telse \n\t\tgtk_tree_selection_unselect_all( select );\n\n\tg_signal_handler_unblock( G_OBJECT( select ), \n\t\tprogram->select_changed_sid );\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\"DefBrowser\" );\n\tgtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),\n\t\tprogram->rpane->open );\n\n\treturn( FALSE );\n}\n\n/* Schedule an update for all our widgets.\n */\nstatic void\nprogram_refresh( Program *program )\n{\n\tIM_FREEF( g_source_remove, program->refresh_timeout );\n\t\n\t/* 10ms to make sure we run after idle (is this right?)\n\t */\n\tprogram->refresh_timeout = g_timeout_add( 10, \n\t\t(GSourceFunc) program_refresh_timeout, program );\n}\n\n/* Break the tool & kit links.\n */\nstatic void\nprogram_detach( Program *program )\n{\n\tif( program->tool ) {\n\t\tprogram->pos = -1;\n\t\tFREESID( program->tool_destroy_sid, program->tool );\n\t\tprogram->tool = NULL;\n\t}\n\n\tif( program->kit ) {\n\t\tFREESID( program->kit_destroy_sid, program->kit );\n\t\tprogram->kit = NULL;\n\t}\n\n\tprogram_refresh( program );\n}\n\nstatic void\nprogram_find_reset( Program *program )\n{\n\tFREESID( program->find_sym_destroy_sid, program->find_sym );\n\tprogram->find_sym = NULL;\n\tprogram->find_start = 0;\n\tprogram->find_end = 0;\n}\n\nstatic void\nprogram_find_destroy_cb( Symbol *sym, Program *program )\n{\n\tprogram_find_reset( program );\n}\n\nstatic void\nprogram_find_note( Program *program, Symbol *sym, int start, int end )\n{\n\tprogram_find_reset( program );\n\n\tprogram->find_sym = sym;\n\tprogram->find_sym_destroy_sid = \n\t\tg_signal_connect( G_OBJECT( sym ), \"destroy\",\n\t\t\tG_CALLBACK( program_find_destroy_cb ), program );\n\tprogram->find_start = start;\n\tprogram->find_end = end;\n}\n\nstatic gboolean\nprogram_find_pos( Program *program, const char *text, int *start, int *end )\n{\n#ifdef HAVE_GREGEX\n\tif( program->regexp ) {\n\t\tGMatchInfo *match;\n\n\t\tg_regex_match( program->comp, text, 0, &match );\n\t\tif( g_match_info_fetch_pos( match, 0, start, end ) ) {\n\t\t\tg_match_info_free( match );\n\t\t\treturn( TRUE );\n\t\t}\n\t\tg_match_info_free( match );\n\t}\n\telse \n#endif /*HAVE_GREGEX*/\n\tif( program->csens ) {\n\t\tchar *p;\n\n\t\tif( (p = strstr( text, program->search )) ) {\n\t\t\t*start = p - text;\n\t\t\t*end = *start + strlen( program->search );\n\n\t\t\treturn( TRUE );\n\t\t}\n\t}\n\telse {\n\t\tchar *p;\n\n\t\tif( (p = my_strcasestr( text, program->search )) ) {\n\t\t\t*start = p - text;\n\t\t\t*end = *start + strlen( program->search );\n\n\t\t\treturn( TRUE );\n\t\t}\n\t}\n\n\treturn( FALSE );\n}\n\nstatic void *\nprogram_find_tool( Tool *tool, Program *program, gboolean *skipping )\n{\n\tSymbol *sym;\n\n\tif( tool->type != TOOL_SYM )\n\t\treturn( NULL );\n\tsym = tool->sym;\n\n\t/* In search mode? Check if we've found the start point.\n\t */\n\tif( *skipping ) {\n\t\tif( sym == program->find_sym || !program->find_sym )\n\t\t\t*skipping = FALSE;\n\t}\n\n\t/* Reached start point? Check from start onwards.\n\t */\n\tif( !*skipping ) {\n\t\tif( sym->expr && sym->expr->compile && \n\t\t\tprogram->find_start < \n\t\t\t\tstrlen( sym->expr->compile->text ) ) {\n\t\t\tint start, end;\n\n\t\t\tif( program_find_pos( program, \n\t\t\t\tsym->expr->compile->text + program->find_start, \n\t\t\t\t&start, &end ) ) {\n\t\t\t\tprogram_find_note( program, sym, \n\t\t\t\t\tstart + program->find_start, \n\t\t\t\t\tend + program->find_start );\n\t\t\t\treturn( tool );\n\t\t\t}\n\t\t}\n\n\t\tprogram_find_reset( program );\n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\nprogram_find_toolkit( Toolkit *kit, Program *program, gboolean *skipping )\n{\n\treturn( icontainer_map( ICONTAINER( kit ), \n\t\t(icontainer_map_fn) program_find_tool, program, &skipping ) );\n}\n\nstatic gboolean\nprogram_find( Program *program )\n{\n\tgboolean skipping = TRUE;\n\n\tif( toolkitgroup_map( program->kitg,\n\t\t(toolkit_map_fn) program_find_toolkit, program, &skipping ) )\n\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\nstatic void\nprogram_destroy( GtkObject *object )\n{\n\tProgram *program;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_PROGRAM( object ) );\n\n\tprogram = PROGRAM( object );\n\n#ifdef DEBUG\n\tprintf( \"program_destroy\\n\" );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\tprogram_detach( program );\n\tUNREF( program->store );\n\tFREESID( program->kitgroup_changed_sid, program->kitg );\n\tFREESID( program->kitgroup_destroy_sid, program->kitg );\n\n\tIM_FREEF( g_free, program->search );\n#ifdef HAVE_GREGEX\n\tIM_FREEF( g_regex_unref, program->comp );\n#endif /*HAVE_GREGEX*/\n\n\tprogram_find_reset( program );\n\n\tIM_FREEF( g_source_remove, program->refresh_timeout );\n\n\tprogram_all = g_slist_remove( program_all, program );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\nprogram_edit_dia_done_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tTool *tool = TOOL( client );\n\tStringset *ss = STRINGSET( iwnd );\n\tStringsetChild *name = stringset_child_get( ss, _( \"Name\" ) );\n\tStringsetChild *file = stringset_child_get( ss, _( \"Filename\" ) );\n\n\tchar name_text[1024];\n\tchar file_text[1024];\n\n\tif( !get_geditable_string( name->entry, name_text, 1024 ) ||\n\t\t!get_geditable_filename( file->entry, file_text, 1024 ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tif( !tool_new_dia( tool->kit, \n\t\tICONTAINER( tool )->pos, name_text, file_text ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nprogram_edit_dia( Program *program, Tool *tool )\n{\n\tGtkWidget *ss = stringset_new();\n\n\tg_assert( tool && tool->type == TOOL_DIA );\n\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Name\" ), IOBJECT( tool )->name, _( \"Menu item text\" ) );\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Filename\" ), FILEMODEL( tool )->filename, \n\t\t_( \"Load column from this file\" ) );\n\n\tiwindow_set_title( IWINDOW( ss ), _( \"Edit Column Item \\\"%s\\\"\" ), \n\t\tIOBJECT( tool )->name );\n\tidialog_set_callbacks( IDIALOG( ss ), \n\t\tiwindow_true_cb, NULL, NULL, tool );\n\tidialog_add_ok( IDIALOG( ss ), \n\t\tprogram_edit_dia_done_cb, _( \"Set column item\" ) );\n\tiwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( program ) );\n\tidialog_set_iobject( IDIALOG( ss ), IOBJECT( tool ) );\n\tiwindow_build( IWINDOW( ss ) );\n\n\tgtk_widget_show( ss );\n}\n\nstatic void\nprogram_edit_object_cb( GtkWidget *menu, Program *program )\n{\n\tModel *model = program_get_selected( program );\n\n\tif( model && IS_TOOL( model ) && TOOL( model )->type == TOOL_DIA ) \n\t\tprogram_edit_dia( program, program->tool );\n}\n\nstatic gboolean\nprogram_is_saveable( Model *model )\n{\n\tif( !IS_TOOLKIT( model ) ) {\n\t\terror_top( _( \"Unable to save.\" ) );\n\t\terror_sub( _( \"You can only save toolkits, not tools.\" ) );\n\t\treturn( FALSE );\n\t}\n\n\tif( IS_TOOLKIT( model ) && TOOLKIT( model )->pseudo ) {\n\t\terror_top( _( \"Unable to save.\" ) );\n\t\terror_sub( _( \"You can't save auto-generated toolkits.\" ) );\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic void\nprogram_save_object_cb( GtkWidget *menu, Program *program )\n{\n\tModel *model = program_get_selected( program );\n\n\tif( model ) {\n\t\tif( program_is_saveable( model ) ) \n\t\t\tfilemodel_inter_save( IWINDOW( program ), \n\t\t\t\tFILEMODEL( model ) );\n\t\telse \n\t\t\tiwindow_alert( GTK_WIDGET( program ), \n\t\t\t\tGTK_MESSAGE_ERROR );\n\t}\n}\n\nstatic void\nprogram_saveas_object_cb( GtkWidget *menu, Program *program ) \n{\n\tModel *model = program_get_selected( program );\n\n\tif( model ) {\n\t\tif( program_is_saveable( model ) ) \n\t\t\tfilemodel_inter_saveas( IWINDOW( program ), \n\t\t\t\tFILEMODEL( model ) );\n\t\telse\n\t\t\tiwindow_alert( GTK_WIDGET( program ), \n\t\t\t\tGTK_MESSAGE_ERROR );\n\t}\n}\n\nstatic void\nprogram_remove_object_cb( GtkWidget *menu, Program *program ) \n{\n\tModel *model = program_get_selected( program );\n\n\tif( model )\n\t\tmodel_check_destroy( GTK_WIDGET( program ), model, NULL );\n}\n\nstatic void\nprogram_class_init( ProgramClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\n\tGtkWidget *pane;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = program_destroy;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\n\tpane = program_menu = popup_build( _( \"Toolkit menu\" ) );\n\tpopup_add_but( pane, _( \"_Edit\" ), \n\t\tPOPUP_FUNC( program_edit_object_cb ) );\n\tpopup_add_but( pane, GTK_STOCK_SAVE,\n\t\tPOPUP_FUNC( program_save_object_cb ) );\n\tpopup_add_but( pane, GTK_STOCK_SAVE_AS,\n\t\tPOPUP_FUNC( program_saveas_object_cb ) );\n\tmenu_add_sep( pane );\n\tpopup_add_but( pane, GTK_STOCK_DELETE,\n\t\tPOPUP_FUNC( program_remove_object_cb ) );\n}\n\n/* Some kit/tool has changed ... update everything.\n */\nstatic void\nprogram_kitgroup_changed( Model *model, Program *program )\n{\n#ifdef DEBUG\n\tprintf( \"program_kitgroup_changed:\\n\" );\n#endif /*DEBUG*/\n\n\tprogram_refresh( program );\n}\n\nstatic void\nprogram_kitgroup_destroy( Model *model, Program *program )\n{\n#ifdef DEBUG\n\tprintf( \"program_kitgroup_destroy:\\n\" );\n#endif /*DEBUG*/\n\n\t/* Our toolkitgroup has gone! Give up on the world.\n\t */\n\tprogram->kitgroup_changed_sid = 0;\n\tprogram->kitgroup_destroy_sid = 0;\n\n\tiwindow_kill( IWINDOW( program ) );\n}\n\nstatic void\nprogram_init( Program *program )\n{\n\tprogram->kitg = NULL;\n\n\tprogram->text = NULL;\n\tprogram->dirty = FALSE;\n\tprogram->text_hash = 0;\n\tprogram->tree = NULL;\n\tprogram->store = NULL;\n\tprogram->pane_position = PROGRAM_PANE_POSITION;\n\tprogram->rpane_open = FALSE;\n\tprogram->rpane_position = 500;\n\tprogram->refresh_timeout = 0;\n\n\tprogram->kitgroup_changed_sid = 0;\n\tprogram->kitgroup_destroy_sid = 0;\n\n\tprogram->kit = NULL;\n\tprogram->kit_destroy_sid = 0;\n\n\tprogram->tool = NULL;\n\tprogram->pos = -1;\n\tprogram->tool_destroy_sid = 0;\n\n\tprogram->search = NULL;\n\tprogram->csens = FALSE;\n\tprogram->fromtop = TRUE;\n#ifdef HAVE_GREGEX\n\tprogram->regexp = FALSE;\n\tprogram->comp = NULL;\n#endif /*HAVE_GREGEX*/\n}\n\nGtkType\nprogram_get_type( void )\n{\n\tstatic GtkType program_type = 0;\n\n\tif( !program_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Program\",\n\t\t\tsizeof( Program ),\n\t\t\tsizeof( ProgramClass ),\n\t\t\t(GtkClassInitFunc) program_class_init,\n\t\t\t(GtkObjectInitFunc) program_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tprogram_type = gtk_type_unique( TYPE_IWINDOW, &info );\n\t}\n\n\treturn( program_type );\n}\n\n/* The kit we have selected has been destroyed.\n */\nstatic void\nprogram_kit_destroy( Toolkit *kit, Program *program )\n{\n#ifdef DEBUG\n\tprintf( \"program_kit_destroy:\\n\" );\n#endif /*DEBUG*/\n\n\tg_assert( program->kit == kit );\n\n\tprogram_detach( program );\n\tprogram_refresh( program );\n}\n\n/* Is a character one of those allowed in nip2 identifers?\n */\nstatic gboolean\nis_ident( int ch )\n{\n\tif( isalnum( ch ) ||\n\t\tch == '_' ||\n\t\tch == '\\'' )\n\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\nstatic void \nprogram_text_cursor_position( GtkTextBuffer *buffer, GParamSpec *pspec, \n\tProgram *program )\n{\n\tgboolean editable = !program->kit || !program->kit->pseudo;\n\n\tif( program->rpane_open && \n\t\teditable ) {\n\t\t/* Fetch characters left of the cursor while we have stuff\n\t\t * that could be an identifier.\n\t\t */\n\t\tGtkTextIter start;\n\t\tGtkTextIter cursor;\n\t\tGtkTextIter end;\n\t\tchar *line;\n\t\tchar *p, *q, *r;\n\n\t\t/* Get iters for start / cursor / end of line.\n\t\t */\n\t\tgtk_text_buffer_get_iter_at_mark( buffer,\n\t\t\t&cursor, gtk_text_buffer_get_insert( buffer ) );\n\t\tgtk_text_buffer_get_iter_at_line_index( buffer,\n\t\t\t&start, gtk_text_iter_get_line( &cursor ), 0 ); \n\t\tgtk_text_buffer_get_iter_at_line_index( buffer,\n\t\t\t&end, gtk_text_iter_get_line( &cursor ), 0 ); \n\t\tgtk_text_iter_forward_to_line_end( &end );\n\n\t\tline = gtk_text_buffer_get_text( buffer, &start, &end, FALSE );\n\t\tp = line + gtk_text_iter_get_line_index( &cursor );\n\n\t\t/* Search back from the cursor for the first non-identifier\n\t\t * char.\n\t\t */\n\t\tfor( q = p - 1; q >= line && is_ident( *q ); q-- )\n\t\t\t;\n\t\tq += 1;\n\t\tfor( r = p; r < line + strlen( line ) && is_ident( *r ); r++ )\n\t\t\t;\n\t\t*r= '\\0';\n\n\t\tif( strlen( q ) > 1 )\n\t\t\tdefbrowser_set_filter( program->defbrowser, q );\n\n\t\tg_free( line );\n\t}\n}\n\nstatic void\nprogram_text_changed( GtkTextBuffer *buffer, Program *program )\n{\n\tif( !program->dirty ) {\n\t\tprogram->dirty = TRUE;\n\t\tprogram_refresh( program );\n\t}\n}\n\nstatic void\nprogram_set_text( Program *program, const char *text, gboolean editable )\n{\n\tGtkTextView *text_view = GTK_TEXT_VIEW( program->text );\n\tGtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view );\n\tguint text_hash = g_str_hash( text );\n\n\tif( text_hash != program->text_hash ) {\n\t\t/* Stop ::changed from firing, we don't want it to update the\n\t\t * def browser filter.\n\t\t */\n\t\tg_signal_handlers_block_by_func( text_buffer,\n\t\t\tG_CALLBACK( program_text_cursor_position ), program );\n\n\t\ttext_view_set_text( text_view, text, editable );\n\t\tprogram->text_hash = text_hash;\n\n\t\tg_signal_handlers_unblock_by_func( text_buffer,\n\t\t\tG_CALLBACK( program_text_cursor_position ), program );\n\t}\n\n\tprogram->dirty = FALSE;\n}\n\n/* Swap text for text for tool.\n */\nstatic void\nprogram_set_text_tool( Program *program, Tool *tool )\n{\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tswitch( tool->type ) {\n\tcase TOOL_DIA:\n\tcase TOOL_SEP:\n\t\tprogram_set_text( program, \"\", FALSE );\n\t\tbreak;\n\n\tcase TOOL_SYM:\n\t\tswitch( tool->sym->type ) {\n\t\tcase SYM_EXTERNAL:\n\t\t\tcall_usage( &buf, tool->sym->function );\n\t\t\tprogram_set_text( program, \n\t\t\t\tvips_buf_all( &buf ), FALSE );\n\t\t\tbreak;\n\n\t\tcase SYM_BUILTIN:\n\t\t\tbuiltin_usage( &buf, tool->sym->builtin );\n\t\t\tprogram_set_text( program, \n\t\t\t\tvips_buf_all( &buf ), FALSE );\n\t\t\tbreak;\n\n\t\tcase SYM_VALUE:\n\t\t\tprogram_set_text( program, \n\t\t\t\ttool->sym->expr->compile->text, TRUE );\n\t\t\tbreak;\n\t\t\n\t\tdefault:\n\t\t\tg_assert( FALSE );\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n}\n\n/* The sym we are editing has been destroyed.\n */\nstatic void\nprogram_tool_destroy( Tool *tool, Program *program )\n{\n#ifdef DEBUG\n\tprintf( \"program_tool_destroy:\\n\" );\n#endif /*DEBUG*/\n\n\tg_assert( program->tool == tool );\n\n\tprogram_detach( program );\n\tprogram_set_text( program, \"\", TRUE );\n\tprogram_refresh( program );\n}\n\n/* Pick a kit ... but don't touch the text yet. \n */\nstatic void\nprogram_select_kit_sub( Program *program, Toolkit *kit )\n{\n\t/* None? Pick \"untitled\".\n\t */\n\tif( !kit )\n\t\tkit = toolkit_by_name( program->kitg, \"untitled\" );\n\n\tprogram_detach( program );\n\n\tif( kit ) {\n\t\tprogram->kit = kit;\n\t\tprogram->kit_destroy_sid = g_signal_connect( G_OBJECT( kit ), \n\t\t\t\"destroy\", G_CALLBACK( program_kit_destroy ), program );\n\t}\n\n\tprogram_refresh( program );\n}\n\n/* Select a new kit in the tree. \n */\nstatic void\nprogram_select_kit( Program *program, Toolkit *kit )\n{\n\tprogram_select_kit_sub( program, kit );\n\tprogram_set_text( program, \"\", TRUE );\n\tprogram_refresh( program );\n}\n\n/* Select a tool in the tree. \n */\nstatic void\nprogram_select_tool( Program *program, Tool *tool )\n{\n\tprogram_detach( program );\n\n\tif( tool ) {\n\t\tprogram_select_kit_sub( program, tool->kit );\n\n\t\tprogram->tool = tool;\n\t\tprogram->pos = ICONTAINER( tool )->pos;\n\t\tprogram->tool_destroy_sid = g_signal_connect( G_OBJECT( tool ), \n\t\t\t\"destroy\", \n\t\t\tG_CALLBACK( program_tool_destroy ), program );\n\n\t\tprogram_set_text_tool( program, tool );\n\t}\n\n\tprogram_refresh( program );\n}\n\nstatic char *\nprogram_get_text( Program *program )\n{\n\tGtkTextView *text_view = GTK_TEXT_VIEW( program->text );\n\tGtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view );\n\tGtkTextIter start_iter;\n\tGtkTextIter end_iter;\n\tchar *text;\n\n\tgtk_text_buffer_get_start_iter( text_buffer, &start_iter );\n\tgtk_text_buffer_get_end_iter( text_buffer, &end_iter );\n\ttext = gtk_text_buffer_get_text( text_buffer, \n\t\t&start_iter, &end_iter, FALSE ); \n\n\treturn( text );\n}\n\n/* Read and parse the text.\n */\nstatic gboolean\nprogram_parse( Program *program )\n{\n\tchar *txt;\n\tchar buffer[MAX_STRSIZE];\n\tCompile *compile;\n\n\tif( !program->dirty )\n\t\treturn( TRUE );\n\n\t/* Irritatingly, we need to append a ';'. Also, update the hash, so we\n\t * don't set the same text back again if we can help it.\n\t */\n\ttxt = program_get_text( program );\n\tprogram->text_hash = g_str_hash( txt );\n\tim_snprintf( buffer, MAX_STRSIZE, \"%s;\", txt );\n\tIM_FREEF( g_free, txt );\n\n\tif( strspn( buffer, WHITESPACE \";\" ) == strlen( buffer ) ) \n\t\treturn( TRUE );\n\n\t/* Make sure we've got a kit.\n\t */\n\tif( !program->kit )\n\t\tprogram_select_kit_sub( program, program->kit );\n\tcompile = program->kit->kitg->root->expr->compile;\n\n#ifdef DEBUG\n\tprintf( \"program_parse: parsing to kit \\\"%s\\\", pos %d\\n\",\n\t\tIOBJECT( program->kit )->name, program->pos  );\n#endif /*DEBUG*/\n\n\t/* ... and parse the new text into it.\n\t */\n\tattach_input_string( buffer );\n\tif( !parse_onedef( program->kit, program->pos ) ) {\n\t\ttext_view_select_text( GTK_TEXT_VIEW( program->text ), \n\t\t\tinput_state.charpos - yyleng, input_state.charpos );\n\t\treturn( FALSE );\n\t}\n\n\tprogram->dirty = FALSE;\n\tif( program->kit )\n\t\tfilemodel_set_modified( FILEMODEL( program->kit ), TRUE );\n\n\t/* Reselect last_sym, the last thing the parser saw. \n\t */\n\tif( compile->last_sym && compile->last_sym->tool ) \n\t\tprogram_select_tool( program, compile->last_sym->tool );\n\n\tsymbol_recalculate_all();\n\n\treturn( TRUE );\n}\n\nstatic void\nprogram_tool_new_action_cb( GtkAction *action, Program *program )\n{\n\t/* Existing text changed? Parse it.\n\t */\n\tif( program->dirty && \n\t\t!program_parse( program ) ) {\n\t\tiwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_ERROR );\n\t\treturn;\n\t}\n\n\tprogram_select_kit( program, program->kit );\n}\n\nstatic void\nprogram_toolkit_new_done_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tStringset *ss = STRINGSET( iwnd );\n\tStringsetChild *name = stringset_child_get( ss, _( \"Name\" ) );\n\tStringsetChild *caption = stringset_child_get( ss, _( \"Caption\" ) );\n\tProgram *program = PROGRAM( client );\n\n\tToolkit *kit;\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tchar name_text[1024];\n\tchar caption_text[1024];\n\n\tif( !get_geditable_name( name->entry, name_text, 1024 ) ||\n\t\t!get_geditable_string( caption->entry, caption_text, 1024 ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\t/* Make a filename from the name ... user start directory.\n\t */\n\tvips_buf_appendf( &buf, \"$SAVEDIR\" G_DIR_SEPARATOR_S \n\t\t\"start\" G_DIR_SEPARATOR_S \"%s.def\", \n\t\tname_text );\n\tkit = toolkit_new_filename( main_toolkitgroup, vips_buf_all( &buf ) );\n\n\t/* Set caption.\n\t */\n\tif( strspn( caption_text, WHITESPACE ) != strlen( caption_text ) )\n\t\tiobject_set( IOBJECT( kit ), NULL, caption_text );\n\telse\n\t\tiobject_set( IOBJECT( kit ), NULL, \"untitled\" );\n\n\tprogram_select_kit( program, kit );\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nprogram_toolkit_new_action_cb( GtkAction *action, Program *program )\n{\n\tGtkWidget *ss = stringset_new();\n\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Name\" ), \"\", _( \"Set toolkit name here\" ) );\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Caption\" ), \"\", _( \"Set toolkit caption here\" ) );\n\tiwindow_set_title( IWINDOW( ss ), _( \"New Toolkit\" ) );\n\tidialog_set_callbacks( IDIALOG( ss ), \n\t\tiwindow_true_cb, NULL, NULL, program );\n\tidialog_add_ok( IDIALOG( ss ), \n\t\tprogram_toolkit_new_done_cb, _( \"Create\" ) );\n\tiwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( program ) );\n\tiwindow_build( IWINDOW( ss ) );\n\n\tgtk_widget_show( ss );\n}\n\nstatic gboolean\nprogram_check_kit( Program *program )\n{\n\tif( !program->kit ) {\n\t\terror_top( _( \"Nothing selected.\" ) );\n\t\terror_sub( \"%s\", _( \"No toolkit selected.\" ) );\n\t\tiwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_INFO );\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic void\nprogram_separator_new_action_cb( GtkAction *action, Program *program )\n{\n\tTool *tool;\n\tint pos;\n\n\tif( !program_check_kit( program ) )\n\t\treturn;\n\n\tpos = icontainer_pos_last( ICONTAINER( program->kit ) );\n\ttool = tool_new_sep( program->kit, pos + 1 );\n\tprogram_select_tool( program, tool );\n}\n\nstatic void\nprogram_column_item_new_done_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tStringset *ss = STRINGSET( iwnd );\n\tStringsetChild *name = stringset_child_get( ss, _( \"Name\" ) );\n\tStringsetChild *file = stringset_child_get( ss, _( \"Filename\" ) );\n\tProgram *program = PROGRAM( client );\n\tTool *tool;\n\n\tint pos;\n\tchar name_text[1024];\n\tchar file_text[1024];\n\n\tif( !get_geditable_name( name->entry, name_text, 1024 ) ||\n\t\t!get_geditable_filename( file->entry, file_text, 1024 ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tpos = icontainer_pos_last( ICONTAINER( program->kit ) );\n\ttool = tool_new_dia( program->kit, pos + 1, name_text, file_text );\n\tprogram_select_tool( program, tool );\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nprogram_column_item_new_action_cb( GtkAction *action, Program *program )\n{\n\tGtkWidget *ss;\n\n\tif( !program_check_kit( program ) )\n\t\treturn;\n\n\tss = stringset_new();\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Name\" ), \"\", _( \"Display this name\" ) );\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Filename\" ), \"\", _( \"Load this file\" ) );\n\tiwindow_set_title( IWINDOW( ss ), \"New Column Item\" );\n\tidialog_set_callbacks( IDIALOG( ss ), \n\t\tiwindow_true_cb, NULL, NULL, program );\n\tidialog_add_ok( IDIALOG( ss ), \n\t\tprogram_column_item_new_done_cb, _( \"Create\" ) );\n\tiwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( program ) );\n\tiwindow_build( IWINDOW( ss ) );\n\n\tgtk_widget_show( ss );\n}\n\nstatic void\nprogram_program_new_action_cb( GtkAction *action, Program *program )\n{\n\tProgram *program2;\n\n\tprogram2 = program_new( program->kitg );\n\n\tgtk_widget_show( GTK_WIDGET( program2 ) ); \n}\n\nstatic void *\nprogram_load_file_fn( Filesel *filesel, \n\tconst char *filename, Program *program, void *b )\n{\n\tToolkit *kit;\n\n\tif( !(kit = toolkit_new_from_file( main_toolkitgroup, filename )) ) \n\t\treturn( filesel );\n\n\tprogram_select_kit( program, kit );\n\n\treturn( NULL );\n}\n\n/* Callback from load browser.\n */\nstatic void\nprogram_load_file_cb( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( iwnd );\n\tProgram *program = PROGRAM( client );\n\n\tif( filesel_map_filename_multi( filesel,\n\t\t(FileselMapFn) program_load_file_fn, program, NULL ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tsymbol_recalculate_all();\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nprogram_open_action_cb( GtkAction *action, Program *program )\n{\n\tGtkWidget *filesel = filesel_new();\n\n\tiwindow_set_title( IWINDOW( filesel ), _( \"Load Definition\" ) );\n\tfilesel_set_flags( FILESEL( filesel ), FALSE, FALSE );\n\tfilesel_set_filetype( FILESEL( filesel ), filesel_type_definition, 0 ); \n\tiwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( program ) );\n\tfilesel_set_done( FILESEL( filesel ), program_load_file_cb, program );\n\tfilesel_set_multi( FILESEL( filesel ), TRUE );\n\tiwindow_build( IWINDOW( filesel ) );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\nstatic void\nprogram_save_action_cb( GtkAction *action, Program *program )\n{\n\tif( !program_check_kit( program ) )\n\t\treturn;\n\n\tfilemodel_inter_save( IWINDOW( program ), FILEMODEL( program->kit ) );\n}\n\nstatic void\nprogram_save_as_action_cb( GtkAction *action, Program *program )\n{\n\tif( !program_check_kit( program ) )\n\t\treturn;\n\n\tfilemodel_inter_saveas( IWINDOW( program ), FILEMODEL( program->kit ) );\n}\n\nstatic void\nprogram_process_action_cb( GtkAction *action, Program *program )\n{\n\tif( !program_parse( program ) )\n\t\tiwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_ERROR );\n}\n\nstatic void\nprogram_reload_menus_cb( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tmain_reload();\n\tsymbol_recalculate_all();\n\n\tnfn( sys, IWINDOW_YES );\n}\n\n/* Reload all menus.\n */\nstatic void\nprogram_reload_action_cb( GtkAction *action, Program *program )\n{\n\tbox_yesno( GTK_WIDGET( program ),\n\t\tprogram_reload_menus_cb, iwindow_true_cb, NULL,\n\t\tiwindow_notify_null, NULL,\n\t\t_( \"Reload\" ), \n\t\t_( \"Reload startup objects?\" ),\n\t\t_( \"Would you like to reload all startup menus, workspaces \"\n\t\t\"and plugins now? This may take a few seconds.\" ) );\n}\n\nstatic void\nprogram_cut_action_cb( GtkAction *action, Program *program )\n{\n\tGtkTextView *text_view = GTK_TEXT_VIEW( program->text );\n\tGtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view );\n\tGtkClipboard *clipboard = gtk_widget_get_clipboard( \n\t\tGTK_WIDGET( text_view ), GDK_SELECTION_CLIPBOARD );\n\tgboolean editable = !program->kit || !program->kit->pseudo;\n\n\tgtk_text_buffer_cut_clipboard( text_buffer, clipboard, editable );\n}\n\nstatic void\nprogram_copy( Program *program )\n{\n\tGtkTextView *text_view = GTK_TEXT_VIEW( program->text );\n\tGtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view );\n\tGtkClipboard *clipboard = gtk_widget_get_clipboard( \n\t\tGTK_WIDGET( text_view ), GDK_SELECTION_CLIPBOARD );\n\n\tgtk_text_buffer_copy_clipboard( text_buffer, clipboard );\n}\n\nstatic void\nprogram_copy_action_cb( GtkAction *action, Program *program )\n{\n\tprogram_copy( program );\n}\n\nstatic void\nprogram_paste_action_cb( GtkAction *action, Program *program )\n{\n\tGtkTextView *text_view = GTK_TEXT_VIEW( program->text );\n\tGtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view );\n\tGtkClipboard *clipboard = gtk_widget_get_clipboard( \n\t\tGTK_WIDGET( text_view ), GDK_SELECTION_CLIPBOARD );\n\tgboolean editable = !program->kit || !program->kit->pseudo;\n\n\tgtk_text_buffer_paste_clipboard( text_buffer, clipboard, NULL,\n\t\teditable );\n}\n\nstatic void\nprogram_delete_action_cb( GtkAction *action, Program *program )\n{\n\tGtkTextView *text_view = GTK_TEXT_VIEW( program->text );\n\tGtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view );\n\tgboolean editable = !program->kit || !program->kit->pseudo;\n\n\tgtk_text_buffer_delete_selection( text_buffer, TRUE, editable );\n}\n\nstatic void\nprogram_select_all_action_cb( GtkAction *action, Program *program )\n{\n\ttext_view_select_text( GTK_TEXT_VIEW( program->text ), 0, -1 );\n}\n\nstatic void\nprogram_deselect_all_action_cb( GtkAction *action, Program *program )\n{\n\tGtkTextView *text_view = GTK_TEXT_VIEW( program->text );\n\tGtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view );\n\tGtkTextMark *mark = gtk_text_buffer_get_insert( text_buffer );\n\tGtkTextIter iter;\n\n\tgtk_text_buffer_get_iter_at_mark( text_buffer, &iter, mark );\n\tgtk_text_buffer_select_range( text_buffer, &iter, &iter );\n}\n\nstatic void\nprogram_remove_tool_action_cb( GtkAction *action, Program *program )\n{\n\tModel *model = program_get_selected( program );\n\n\tif( model && IS_TOOL( model ) )\n\t\tmodel_check_destroy( GTK_WIDGET( program ), model, NULL );\n\telse {\n\t\terror_top( _( \"No tool selected\" ) );\n\t\tiwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_INFO );\n\t}\n}\n\nstatic void\nprogram_remove_toolkit_action_cb( GtkAction *action, Program *program )\n{\n\tif( !program_check_kit( program ) )\n\t\treturn;\n\n\tmodel_check_destroy( GTK_WIDGET( program ), \n\t\tMODEL( program->kit ), NULL );\n}\n\nstatic void\nprogram_find_done_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tFind *find = FIND( iwnd );\n\tProgram *program = PROGRAM( client );\n\n\tIM_FREEF( g_free, program->search );\n\n\tprogram->search = \n\t\tgtk_editable_get_chars( GTK_EDITABLE( find->search ), 0, -1 );\n\tprogram->csens = GTK_TOGGLE_BUTTON( find->csens )->active;\n\tprogram->fromtop = GTK_TOGGLE_BUTTON( find->fromtop )->active;\n\n#ifdef HAVE_GREGEX\n\tprogram->regexp = GTK_TOGGLE_BUTTON( find->regexp )->active;\n\n\tif( program->regexp ) {\n\t\tGRegexCompileFlags cflags = 0;\n\t\tGRegexMatchFlags mflags = 0;\n\n\t\tif( !program->csens )\n\t\t\tcflags |= G_REGEX_CASELESS;\n\n\t\tIM_FREEF( g_regex_unref, program->comp );\n\n\t\tif( !(program->comp = g_regex_new( program->search, \n\t\t\tcflags, mflags, NULL )) ) {\n\t\t\terror_top( _( \"Parse error.\" ) );\n\t\t\terror_sub( _( \"Bad regular expression.\" ) );\n\t\t\tnfn( sys, IWINDOW_ERROR );\n\t\t\treturn;\n\t\t}\n\t}\n#endif /*HAVE_GREGEX*/\n\n\tif( program->fromtop )\n\t\tprogram_find_reset( program );\n\telse\n\t\tprogram->find_start += 1;\n\n\tif( program_find( program ) ) {\n\t\tprogram_select_tool( program, program->find_sym->tool );\n\t\ttext_view_select_text( GTK_TEXT_VIEW( program->text ), \n\t\t\tprogram->find_start, program->find_end );\n\t}\n\telse {\n\t\terror_top( _( \"Not found.\" ) );\n\t\terror_sub( _( \"No match found for \\\"%s\\\".\" ), program->search );\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nprogram_find_action_cb( GtkAction *action, Program *program )\n{\n\tGtkWidget *find = find_new();\n\n\tiwindow_set_title( IWINDOW( find ), _( \"Find in all Toolkits\" ) );\n\tidialog_set_callbacks( IDIALOG( find ), \n\t\tiwindow_true_cb, NULL, NULL, program );\n\tidialog_add_ok( IDIALOG( find ), program_find_done_cb, GTK_STOCK_FIND );\n\tiwindow_set_parent( IWINDOW( find ), GTK_WIDGET( program ) );\n\tidialog_set_cancel_text( IDIALOG( find ), GTK_STOCK_CLOSE );\n\tiwindow_build( IWINDOW( find ) );\n\n\tif( program->search )\n\t\tset_gentry( FIND( find )->search, \"%s\", program->search );\n\tset_tooltip( FIND( find )->search, _( \"Enter search string here\" ) );\n        gtk_toggle_button_set_active( \n\t\tGTK_TOGGLE_BUTTON( FIND( find )->csens ), program->csens );\n#ifdef HAVE_GREGEX\n        gtk_toggle_button_set_active( \n\t\tGTK_TOGGLE_BUTTON( FIND( find )->regexp ), program->regexp );\n#endif /*HAVE_GREGEX*/\n        gtk_toggle_button_set_active( \n\t\tGTK_TOGGLE_BUTTON( FIND( find )->fromtop ), program->fromtop );\n\n\tgtk_widget_show( find );\n}\n\nstatic void\nprogram_find_again_action_cb( GtkAction *action, Program *program )\n{\n\tif( !program->search )\n\t\treturn;\n\n\tif( program->find_sym ) \n\t\tprogram->find_start += 1;\n\n\tif( program_find( program ) ) {\n\t\tprogram_select_tool( program, program->find_sym->tool );\n\t\ttext_view_select_text( GTK_TEXT_VIEW( program->text ), \n\t\t\tprogram->find_start, program->find_end );\n\t}\n\telse {\n\t\terror_top( _( \"Not found.\" ) );\n\t\tiwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_INFO );\n\t}\n}\n\nstatic void\nprogram_goto_done_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tProgram *program = PROGRAM( client );\n\tStringset *ss = STRINGSET( iwnd );\n\tStringsetChild *name = stringset_child_get( ss, _( \"Name\" ) );\n\tSymbol *sym;\n\tchar name_text[1024];\n\n\tif( !get_geditable_string( name->entry, name_text, 1024 ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tif( !(sym = compile_lookup( program->kitg->root->expr->compile, \n\t\tname_text )) ) {\n\t\terror_top( _( \"Not found.\" ) );\n\t\terror_sub( _( \"No top-level symbol called \\\"%s\\\".\" ), \n\t\t\tname_text );\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tif( !sym->tool ) {\n\t\terror_top( _( \"Not found.\" ) );\n\t\terror_sub( _( \"Symbol \\\"%s\\\" has no tool inforation.\" ), \n\t\t\tname_text );\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tif( !program_select( program, MODEL( sym->tool ) ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nprogram_goto_action_cb( GtkAction *action, Program *program )\n{\n\tGtkWidget *ss = stringset_new();\n\tStringsetChild *name;\n\n\tname = stringset_child_new( STRINGSET( ss ), \n\t\t_( \"Name\" ), \"\", _( \"Go to definition of this symbol\" ) );\n\n\tiwindow_set_title( IWINDOW( ss ), _( \"Go to Definition\" ) );\n\tidialog_set_callbacks( IDIALOG( ss ), \n\t\tiwindow_true_cb, NULL, NULL, program );\n\tidialog_add_ok( IDIALOG( ss ), \n\t\tprogram_goto_done_cb, GTK_STOCK_JUMP_TO );\n\tidialog_set_pinup( IDIALOG( ss ), TRUE );\n\tiwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( program ) );\n\tiwindow_build( IWINDOW( ss ) );\n\n\tgtk_widget_show( ss );\n\n\t/* Now try to paste the selection into the name widget.\n\t\t\n\t\tFIXME ... get rid of this, have a right-button menu on the \n\t\ttext widget which includes a 'go to def' item.\n\n\t\tor could make sym names into hyperlinks? see text demo example\n\n\t */\n\tprogram_copy( program );\n\tgtk_editable_paste_clipboard( GTK_EDITABLE( name->entry ) );\n}\n\nstatic void\nprogram_info_action_cb( GtkAction *action, Program *program )\n{\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tprogram_info( program, &buf );\n\terror_top( _( \"Object information.\" ) );\n\terror_sub( \"%s\", vips_buf_all( &buf ) );\n\tiwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_INFO );\n}\n\nstatic void\nprogram_trace_action_cb( GtkAction *action, Program *program )\n{\n\t(void) trace_new();\n}\n\nstatic void\nprogram_errorreport_action_cb( GtkAction *action, Program *program )\n{\n\tiError *ierror;\n\n\tierror = ierror_new( program->kitg );\n\tgtk_widget_show( GTK_WIDGET( ierror ) ); \n\n#ifdef DEBUG\n\t/* Dump VIPS memory usage info for debugging.\n\t */\n\tim__print_all();\n#endif /*DEBUG*/\n}\n\nstatic void\nprogram_tool_help_action_cb( GtkAction *action, Program *program )\n{\n\tif( program->tool && program->tool->type == TOOL_SYM && \n\t\tprogram->kit && program->kit->pseudo ) {\n\t\tswitch( program->tool->sym->type ) {\n\t\tcase SYM_EXTERNAL:\n\t\t\t/* With vips7 we displayed the man page. When we go\n\t\t\t * properly vips8, display the API docs.\n\t\t\t *\n\tchar txt[512];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\t\tvips_buf_appendf( &buf, \"file://\"\n\t\t\t\tVIPS_DOCPATH \"/man/%s.3.html\", \n\t\t\t\tIOBJECT( program->tool->sym )->name );\n\t\t\tbox_url( GTK_WIDGET( program ), vips_buf_all( &buf ) );\n\t\t\t *\n\t\t\t */\n\t\t\tbreak;\n\n\t\tcase SYM_BUILTIN:\n\t\t\tbox_help( GTK_WIDGET( program ), \"tb:builtin\" );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t}\n\telse {\n\t\terror_top( _( \"No documentation available.\" ) );\n\t\terror_sub( \"%s\", _( \"On-line documentation is only currently \"\n\t\t\t\"available for VIPS functions and nip builtins.\" ) );\n\t\tiwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_INFO );\n\t}\n}\n\n/* Expose/hide the definition browser.\n */\nstatic void\nprogram_defbrowser_action_cb( GtkToggleAction *action, Program *program )\n{\n\tif( gtk_toggle_action_get_active( action ) )\n\t\tpane_animate_open( program->rpane );\n\telse\n\t\tpane_animate_closed( program->rpane );\n}\n\n/* Our actions.\n */\nstatic GtkActionEntry program_actions[] = {\n\t/* Menu items.\n\t */\n\t{ \"DebugMenu\", NULL, \"_Debug\" },\n\n\t/* Actions.\n\t */\n\t{ \"NewTool\", \n\t\tGTK_STOCK_NEW, N_( \"New _Tool\" ), NULL, \n\t\tN_( \"Make a new tool\" ), \n\t\tG_CALLBACK( program_tool_new_action_cb ) },\n\n\t{ \"NewToolkit\", \n\t\tGTK_STOCK_NEW, N_( \"New Tool_kit\" ), NULL, \n\t\tN_( \"Make a new toolkit\" ), \n\t\tG_CALLBACK( program_toolkit_new_action_cb ) },\n\n\t{ \"NewSeparator\", \n\t\tGTK_STOCK_NEW, N_( \"New _Separator\" ), NULL, \n\t\tN_( \"Make a new separator\" ), \n\t\tG_CALLBACK( program_separator_new_action_cb ) },\n\n\t{ \"NewColumnItem\", \n\t\tGTK_STOCK_NEW, N_( \"New _Column Item\" ), NULL, \n\t\tN_( \"Make a new column item\" ), \n\t\tG_CALLBACK( program_column_item_new_action_cb ) },\n\n\t{ \"NewProgram\", \n\t\tGTK_STOCK_NEW, N_( \"New _Program Window\" ), NULL, \n\t\tN_( \"Make a new program window\" ), \n\t\tG_CALLBACK( program_program_new_action_cb ) },\n\n\t{ \"Open\", \n\t\tGTK_STOCK_OPEN, N_( \"_Open Toolkit\" ), NULL,\n\t\tN_( \"_Open toolkit\" ), \n\t\tG_CALLBACK( program_open_action_cb ) },\n\n\t{ \"Save\", \n\t\tGTK_STOCK_SAVE, N_( \"Save Toolkit\" ), NULL,\n\t\tN_( \"_Save toolkit\" ), \n\t\tG_CALLBACK( program_save_action_cb ) },\n\n\t{ \"SaveAs\", \n\t\tGTK_STOCK_SAVE_AS, N_( \"Save Toolkit _As\" ), NULL,\n\t\tN_( \"Save toolkit as\" ), \n\t\tG_CALLBACK( program_save_as_action_cb ) },\n\n\t{ \"Process\", \n\t\tNULL, N_( \"_Process\" ), NULL,\n\t\tN_( \"Process text\" ), \n\t\tG_CALLBACK( program_process_action_cb ) },\n\n\t{ \"Reload\", \n\t\tNULL, N_( \"_Reload All Toolkits\" ), NULL,\n\t\tN_( \"Remove and reload all startup data\" ), \n\t\tG_CALLBACK( program_reload_action_cb ) },\n\n\t{ \"Cut\", \n\t\tGTK_STOCK_CUT, N_( \"C_ut\" ), NULL,\n\t\tN_( \"Cut selected text\" ), \n\t\tG_CALLBACK( program_cut_action_cb ) },\n\n\t{ \"Copy\", \n\t\tGTK_STOCK_COPY, N_( \"_Copy\" ), NULL,\n\t\tN_( \"Copy selected text\" ), \n\t\tG_CALLBACK( program_copy_action_cb ) },\n\n\t{ \"Paste\", \n\t\tGTK_STOCK_PASTE, N_( \"_Paste\" ), NULL,\n\t\tN_( \"Paste selected text\" ), \n\t\tG_CALLBACK( program_paste_action_cb ) },\n\n\t{ \"Delete\", \n\t\tGTK_STOCK_DELETE, N_( \"_Delete\" ), NULL,\n\t\tN_( \"Delete selected text\" ), \n\t\tG_CALLBACK( program_delete_action_cb ) },\n\n\t{ \"SelectAll\", \n\t\tNULL, N_( \"Select _All\" ), NULL,\n\t\tN_( \"Select all text\" ), \n\t\tG_CALLBACK( program_select_all_action_cb ) },\n\n\t{ \"DeselectAll\", \n\t\tNULL, N_( \"Dese_lect All\" ), NULL,\n\t\tN_( \"Deselect all text\" ), \n\t\tG_CALLBACK( program_deselect_all_action_cb ) },\n\n\t{ \"DeleteTool\", \n\t\tNULL, N_( \"Delete _Tool\" ), NULL,\n\t\tN_( \"Delete current tool\" ), \n\t\tG_CALLBACK( program_remove_tool_action_cb ) },\n\n\t{ \"DeleteToolkit\", \n\t\tNULL, N_( \"Delete Tool_kit\" ), NULL,\n\t\tN_( \"Delete current toolkit\" ), \n\t\tG_CALLBACK( program_remove_toolkit_action_cb ) },\n\n\t{ \"Find\", \n\t\tGTK_STOCK_FIND, N_( \"_Find\" ), NULL,\n\t\tN_( \"Find text in toolkits\" ), \n\t\tG_CALLBACK( program_find_action_cb ) },\n\n\t{ \"FindNext\", \n\t\tNULL, N_( \"Find _Next\" ), \"<control>G\",\n\t\tN_( \"Find text again\" ), \n\t\tG_CALLBACK( program_find_again_action_cb ) },\n\n\t{ \"JumpTo\", \n\t\tGTK_STOCK_JUMP_TO, N_( \"_Jump To Definition\" ), NULL,\n\t\tN_( \"Jump to definition\" ), \n\t\tG_CALLBACK( program_goto_action_cb ) },\n\n\t{ \"Info\", \n\t\tNULL, N_( \"_Info\" ), NULL,\n\t\tN_( \"Info on selected object\" ), \n\t\tG_CALLBACK( program_info_action_cb ) },\n\n\t{ \"Trace\", \n\t\tNULL, N_( \"_Trace\" ), NULL,\n\t\tN_( \"Make a new trace window\" ), \n\t\tG_CALLBACK( program_trace_action_cb ) },\n\n\t{ \"Errors\", \n\t\tNULL, N_( \"_Errors\" ), NULL,\n\t\tN_( \"Show all errors\" ), \n\t\tG_CALLBACK( program_errorreport_action_cb ) },\n\n\t{ \"HelpTool\", \n\t\tNULL, N_( \"Help on _Tool\" ), NULL,\n\t\tN_( \"View docs for this tool\" ), \n\t\tG_CALLBACK( program_tool_help_action_cb ) }\n};\n\nstatic GtkToggleActionEntry program_toggle_actions[] = {\n\t{ \"DefBrowser\",\n\t\tNULL, N_( \"Definition _Browser\" ), NULL,\n\t\tN_( \"Show definition browser\" ),\n\t\tG_CALLBACK( program_defbrowser_action_cb ), FALSE }\n};\n\nstatic const char *program_menubar_ui_description =\n\"<ui>\"\n\"  <menubar name='ProgramMenubar'>\"\n\"    <menu action='FileMenu'>\"\n\"      <menu action='NewMenu'>\"\n\"        <menuitem action='NewTool'/>\"\n\"        <menuitem action='NewToolkit'/>\"\n\"        <menuitem action='NewSeparator'/>\"\n\"        <menuitem action='NewColumnItem'/>\"\n\"        <menuitem action='NewProgram'/>\"\n\"      </menu>\"\n\"      <menuitem action='Open'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Save'/>\"\n\"      <menuitem action='SaveAs'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Process'/>\"\n\"      <menuitem action='Reload'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Close'/>\"\n\"      <menuitem action='Quit'/>\"\n\"    </menu>\"\n\"    <menu action='EditMenu'>\"\n\"      <menuitem action='Cut'/>\"\n\"      <menuitem action='Copy'/>\"\n\"      <menuitem action='Paste'/>\"\n\"      <menuitem action='Delete'/>\"\n\"      <separator/>\"\n\"      <menuitem action='SelectAll'/>\"\n\"      <menuitem action='DeselectAll'/>\"\n\"      <separator/>\"\n\"      <menuitem action='DeleteTool'/>\"\n\"      <menuitem action='DeleteToolkit'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Find'/>\"\n\"      <menuitem action='FindNext'/>\"\n\"      <menuitem action='JumpTo'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Info'/>\"\n\"    </menu>\"\n\"    <menu action='ViewMenu'>\"\n\"      <menuitem action='DefBrowser'/>\"\n\"    </menu>\"\n\"    <menu action='DebugMenu'>\"\n\"      <menuitem action='Trace'/>\"\n\"      <menuitem action='Errors'/>\"\n\"    </menu>\"\n\"    <menu action='HelpMenu'>\"\n\"      <menuitem action='Guide'/>\"\n\"      <menuitem action='About'/>\"\n\"      <menuitem action='HelpTool'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Homepage'/>\"\n\"    </menu>\"\n\"  </menubar>\"\n\"</ui>\";\n\nstatic void\nprogram_lpane_changed_cb( Pane *pane, Program *program )\n{\n}\n\nstatic void\nprogram_rpane_changed_cb( Pane *pane, Program *program )\n{\n\tif( program->rpane_open != pane->open ||\n\t\tprogram->rpane_position != pane->user_position ) {\n\t\tprogram->rpane_open = pane->open;\n\t\tprogram->rpane_position = pane->user_position;\n\n\t\tprogram_refresh( program );\n\t}\n}\n\ngboolean\nprogram_select( Program *program, Model *model )\n{\n\t/* Existing text changed? Parse it.\n\t */\n\tif( program->dirty && !program_parse( program ) ) \n\t\treturn( FALSE );\n\n\tif( model ) {\n\t\tif( IS_TOOL( model ) ) \n\t\t\tprogram_select_tool( program, TOOL( model ) );\n\t\telse if( IS_TOOLKIT( model ) ) \n\t\t\tprogram_select_kit( program, TOOLKIT( model ) );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Select a row from an iter.\n */\nstatic void\nprogram_select_row( Program *program, GtkTreeIter *iter )\n{\n\tTool *tool;\n\tToolkit *kit;\n\tModel *model;\n\n\tgtk_tree_model_get( GTK_TREE_MODEL( program->store ), iter,\n\t\tTOOL_POINTER_COLUMN, &tool,\n\t\tKIT_POINTER_COLUMN, &kit,\n\t\t-1 );\n\tif( tool )\n\t\tmodel = MODEL( tool );\n\telse\n\t\tmodel = MODEL( kit );\n\n\tif( !program_select( program, model ) ) \n\t\tiwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_ERROR );\n}\n\nstatic void\nprogram_row_collapsed_cb( GtkTreeView *tree, \n\tGtkTreeIter *iter, GtkTreePath *path, Program *program )\n{\n\tToolkit *kit;\n\n#ifdef DEBUG\n\tprintf( \"program_row_collapsed_cb:\\n\" );\n\tprintf( \"  path = %s\\n\", gtk_tree_path_to_string( path ) );\n#endif /*DEBUG*/\n\n\tgtk_tree_model_get( GTK_TREE_MODEL( program->store ), iter,\n\t\tKIT_POINTER_COLUMN, &kit,\n\t\t-1 );\n\n\t/* If we have collapsed the kit containing the currently selected\n\t * tool, the kit will just bounce open again when we refresh the tree.\n\t * Unselect the tool.\n\t */\n\tif( program->kit == kit )\n\t\tprogram_select_kit( program, kit );\n}\n\nstatic void\nprogram_selection_changed_cb( GtkTreeSelection *select, Program *program )\n{\n        GtkTreeIter iter;\n        GtkTreeModel *model;\n\n#ifdef DEBUG\n\tprintf( \"program_selection_changed_cb:\\n\" );\n#endif /*DEBUG*/\n\n        if( gtk_tree_selection_get_selected( select, &model, &iter ) ) {\n#ifdef DEBUG\n\t\tprintf( \"  selection = %s\\n\",\n\t\t\tgtk_tree_path_to_string (\n\t\t\t\tgtk_tree_model_get_path( model, &iter ) ) );\n#endif /*DEBUG*/\n\n                program_select_row( program, &iter );\n\t}\n\n\tprogram_refresh( program );\n}\n\nstatic gboolean\nprogram_tree_event_cb( GtkTreeView *tree, GdkEvent *ev, Program *program )\n{\n\tGtkTreePath *path;\n\tgboolean handled = FALSE;\n\n        if( ev->type == GDK_BUTTON_PRESS && ev->button.button == 3 &&\n\t\tgtk_tree_view_get_path_at_pos( tree,\n\t\t\tev->button.x, ev->button.y, \n\t\t\t&path, NULL, NULL, NULL ) ) {\n\t\tGtkTreeIter iter;\n\n\t\tgtk_tree_model_get_iter( GTK_TREE_MODEL( program->store ),\n\t\t\t&iter, path );\n                program_select_row( program, &iter );\n\t\tgtk_tree_path_free( path );\n\t\tpopup_link( GTK_WIDGET( program ), program_menu, NULL );\n\t\tpopup_show( GTK_WIDGET( program ), ev );\n\n\t\thandled = TRUE;\n\t}\n\n\treturn( handled );\n}\n\nstatic void\nprogram_row_inserted_cb( GtkTreeModel *treemodel, \n\tGtkTreePath *path, GtkTreeIter *iter, Program *program )\n{\n\tGtkTreeIter iter2;\n\tGtkTreeIter iter3;\n\n#ifdef DEBUG\n\tprintf( \"program_row_inserted_cb:\\n\" );\n\tprintf( \"  path = %s\\n\", gtk_tree_path_to_string( path ) );\n#endif /*DEBUG*/\n\n\tprogram->to_pos = -1;\n\tprogram->to_kit = NULL;\n\n\tswitch( gtk_tree_path_get_depth( path ) ) {\n\tcase 3:\n\t\tprogram->to_pos = gtk_tree_path_get_indices( path )[1];\n\t\tgtk_tree_model_iter_parent( GTK_TREE_MODEL( program->store ),\n\t\t\t&iter2, iter );\n\t\tgtk_tree_model_iter_parent( GTK_TREE_MODEL( program->store ),\n\t\t\t&iter3, &iter2 );\n\t\tgtk_tree_model_get( GTK_TREE_MODEL( program->store ), &iter3,\n\t\t\tKIT_POINTER_COLUMN, &program->to_kit,\n\t\t\t-1 );\n\t\tbreak;\n\n\tcase 2:\n\t\tprogram->to_pos = gtk_tree_path_get_indices( path )[1];\n\t\tgtk_tree_model_iter_parent( GTK_TREE_MODEL( program->store ),\n\t\t\t&iter2, iter );\n\t\tgtk_tree_model_get( GTK_TREE_MODEL( program->store ), &iter2,\n\t\t\tKIT_POINTER_COLUMN, &program->to_kit,\n\t\t\t-1 );\n\t\tbreak;\n\n\tcase 1:\n\t\tprogram->to_pos = -1;\n\t\tgtk_tree_model_get( GTK_TREE_MODEL( program->store ), iter,\n\t\t\tKIT_POINTER_COLUMN, &program->to_kit,\n\t\t\t-1 );\n\t\tbreak;\n\n\t}\n\n#ifdef DEBUG\n\tif( program->to_kit ) {\n\t\tprintf( \"  to_kit = \" );\n\t\tiobject_print( IOBJECT( program->to_kit ) );\n\t}\n\telse\n\t\tprintf( \"  to_kit = NULL\\n\" );\n\tprintf( \"  to_pos = %d\\n\", program->to_pos );\n#endif /*DEBUG*/\n}\n\nstatic void\nprogram_row_deleted_cb( GtkTreeModel *treemodel, \n\tGtkTreePath *path, Program *program )\n{\n#ifdef DEBUG\n\tprintf( \"program_row_deleted_cb:\\n\" );\n\tprintf( \"  delete path = %s\\n\", gtk_tree_path_to_string( path ) );\n#endif /*DEBUG*/\n\n\tif( !program->to_kit || !program->tool ) {\n\t\terror_top( _( \"Bad drag.\" ) );\n\t\terror_sub( \"%s\", \n\t\t\t_( \"Sorry, you can only drag tools between toolkits. \"\n\t\t\t\"You can't reorder toolkits, you can't nest toolkits \"\n\t\t\t\"and you can't drag tools to the top level.\" ) );\n\t\tiwindow_alert( GTK_WIDGET( program ), GTK_MESSAGE_INFO );\n\t\treturn;\n\t}\n\n#ifdef DEBUG\n\tprintf( \"  to_kit = \" );\n\tiobject_print( IOBJECT( program->to_kit ) );\n\tprintf( \"  to_pos = %d\\n\", program->to_pos );\n\tprintf( \"  selected tool = \" );\n\tiobject_print( IOBJECT( program->tool ) );\n#endif /*DEBUG*/\n\n\t/* Move tool.\n\t */\n\tg_object_ref( G_OBJECT( program->tool ) );\n\ticontainer_child_remove( ICONTAINER( program->tool ) );\n\ticontainer_child_add( ICONTAINER( program->to_kit ), \n\t\tICONTAINER( program->tool ), program->to_pos );\n\tg_object_unref( G_OBJECT( program->tool ) );\n\tfilemodel_set_modified( FILEMODEL( program->to_kit ), TRUE );\n\tiobject_changed( IOBJECT( program->tool ) );\n}\n\nstatic void\nprogram_edit_map_cb( GtkWidget *widget, Program *program )\n{\n\tiWindow *iwnd = IWINDOW( program );\n\tGtkClipboard *clipboard = gtk_widget_get_clipboard( \n\t\tGTK_WIDGET( program ), GDK_SELECTION_CLIPBOARD );\n\tGtkTextView *text_view = GTK_TEXT_VIEW( program->text );\n\tGtkTextBuffer *text_buffer = gtk_text_view_get_buffer( text_view );\n\n\tgboolean editable = !program->kit || !program->kit->pseudo;\n\tgboolean available = gtk_clipboard_wait_is_text_available( clipboard );\n\tgboolean selected = gtk_text_buffer_get_selection_bounds( text_buffer,\n\t\tNULL, NULL );\n\n\tGtkAction *action;\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \"Paste\" );\n\tg_object_set( G_OBJECT( action ), \n\t\t\"sensitive\", available && editable,\n\t\tNULL );\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \"Copy\" );\n\tg_object_set( G_OBJECT( action ), \n\t\t\"sensitive\", selected,\n\t\tNULL );\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \"Cut\" );\n\tg_object_set( G_OBJECT( action ), \n\t\t\"sensitive\", selected && editable,\n\t\tNULL );\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \"Delete\" );\n\tg_object_set( G_OBJECT( action ), \n\t\t\"sensitive\", selected && editable,\n\t\tNULL );\n\n\taction = gtk_action_group_get_action( iwnd->action_group, \n\t\t\"DeselectAll\" );\n\tg_object_set( G_OBJECT( action ), \n\t\t\"sensitive\", selected,\n\t\tNULL );\n}\n\nstatic PangoTabArray *\nprogram_tabs_new( void )\n{\n\tconst int ntabs = 20;\n\tconst int tab_width = 30;\t/* in pixels, about 4 chars */\n\n\tPangoTabArray *tabs = pango_tab_array_new( ntabs, TRUE );\n\tint i;\n\n\tfor( i = 0; i < ntabs; i++ )\n\t\tpango_tab_array_set_tab( tabs, \n\t\t\ti, PANGO_TAB_LEFT, i * tab_width );\n\n\treturn( tabs );\n}\n\nGtkWidget *\nprogram_text_new( void )\n{\n\tPangoFontDescription *font_desc;\n\tPangoTabArray *tabs;\n\tGtkWidget *text;\n\n\ttext = gtk_text_view_new();\n\tfont_desc = pango_font_description_from_string( \"Monospace\" );\n\tgtk_widget_modify_font( text, font_desc );\n\tpango_font_description_free( font_desc );\n\ttabs = program_tabs_new();\n\tgtk_text_view_set_tabs( GTK_TEXT_VIEW( text ), tabs );\n\tpango_tab_array_free( tabs );\n\n\treturn( text );\n}\n\nstatic void\nprogram_build( Program *program, GtkWidget *vbox )\n{\n\tiWindow *iwnd = IWINDOW( program );\n\n\tGError *error;\n\n\tGtkWidget *mbar;\n\tGtkWidget *item;\n\tGtkCellRenderer *renderer;\n\tGtkTreeViewColumn *column;\n\tGtkTreeSelection *select;\n\tGtkWidget *swin;\n\tPanechild *panechild;\n\tGtkWidget *ebox;\n\n        /* Make main menu bar\n         */\n\tgtk_action_group_add_actions( iwnd->action_group, \n\t\tprogram_actions, G_N_ELEMENTS( program_actions ), \n\t\tGTK_WINDOW( program ) );\n\tgtk_action_group_add_toggle_actions( iwnd->action_group, \n\t\tprogram_toggle_actions, G_N_ELEMENTS( program_toggle_actions ), \n\t\tGTK_WINDOW( program ) );\n\n\terror = NULL;\n\tif( !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager,\n\t\t\tprogram_menubar_ui_description, -1, &error ) ) {\n\t\tg_message( \"building menus failed: %s\", error->message );\n\t\tg_error_free( error );\n\t\texit( EXIT_FAILURE );\n\t}\n\n\tmbar = gtk_ui_manager_get_widget( iwnd->ui_manager, \n\t\t\"/ProgramMenubar\" );\n\tgtk_box_pack_start( GTK_BOX( vbox ), mbar, FALSE, FALSE, 0 );\n        gtk_widget_show( mbar );\n\n\t/* On map of the edit menu, rethink cut/copy/paste sensitivity.\n\t */\n        item = gtk_ui_manager_get_widget( iwnd->ui_manager,\n\t\t\"/ProgramMenubar/EditMenu/Cut\" );\n\titem = gtk_widget_get_parent( GTK_WIDGET( item ) );\n        gtk_signal_connect( GTK_OBJECT( item ), \"map\",\n                GTK_SIGNAL_FUNC( program_edit_map_cb ), program );\n\n\t/* This will set to NULL if we don't have infobar support.\n\t */\n\tif( (IWINDOW( program )->infobar = infobar_new()) ) \n\t\tgtk_box_pack_start( GTK_BOX( vbox ), \n\t\t\tGTK_WIDGET( IWINDOW( program )->infobar ), \n\t\t\tFALSE, FALSE, 0 );\n\n\tprogram->rpane = pane_new( PANE_HIDE_RIGHT );\n\tg_signal_connect( program->rpane, \"changed\",\n\t\tG_CALLBACK( program_rpane_changed_cb ), program );\n\tgtk_box_pack_start( GTK_BOX( vbox ), \n\t\tGTK_WIDGET( program->rpane ), TRUE, TRUE, 0 );\n\tgtk_widget_show( GTK_WIDGET( program->rpane ) );\n\n\tprogram->lpane = pane_new( PANE_HIDE_LEFT );\n\tg_signal_connect( program->lpane, \"changed\",\n\t\tG_CALLBACK( program_lpane_changed_cb ), program );\n\tgtk_paned_set_position( GTK_PANED( program->lpane ), \n\t\tprogram->pane_position );\n\tgtk_paned_pack1( GTK_PANED( program->rpane ), \n\t\tGTK_WIDGET( program->lpane ), TRUE, FALSE );\n\tgtk_widget_show( GTK_WIDGET( program->lpane ) );\n\n\tswin = gtk_scrolled_window_new( NULL, NULL );\n\tgtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ),\n\t\tGTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );\n\tgtk_paned_pack1( GTK_PANED( program->lpane ), swin, FALSE, FALSE );\n\tgtk_widget_show( swin );\n\n\tprogram->store = gtk_tree_store_new( N_COLUMNS, \n\t\tG_TYPE_STRING, \n\t\tG_TYPE_POINTER,\n\t\tG_TYPE_POINTER );\n\tprogram->row_inserted_sid = g_signal_connect( \n\t\tG_OBJECT( program->store ), \"row_inserted\",\n\t\tG_CALLBACK( program_row_inserted_cb ), program );\n\tprogram->row_deleted_sid = g_signal_connect( \n\t\tG_OBJECT( program->store ), \"row_deleted\",\n\t\tG_CALLBACK( program_row_deleted_cb ), program );\n\n\tprogram->tree = gtk_tree_view_new_with_model( \n\t\tGTK_TREE_MODEL( program->store ) );\n\n\trenderer = gtk_cell_renderer_text_new();\n\tcolumn = gtk_tree_view_column_new_with_attributes( _( \"Tool\" ),\n\t\trenderer, \"text\", NAME_COLUMN, NULL );\n\tgtk_tree_view_append_column( GTK_TREE_VIEW( program->tree ), column );\n\n\tg_signal_connect( G_OBJECT( program->tree ), \"row_collapsed\",\n\t\tG_CALLBACK( program_row_collapsed_cb ), program );\n\n\tgtk_container_add( GTK_CONTAINER( swin ), program->tree );\n\tgtk_tree_view_set_headers_visible( GTK_TREE_VIEW( program->tree ), \n\t\tFALSE );\n\tgtk_tree_view_set_enable_search( GTK_TREE_VIEW( program->tree ), TRUE );\n\tgtk_tree_view_set_reorderable( GTK_TREE_VIEW( program->tree ), TRUE );\n\tselect = gtk_tree_view_get_selection( GTK_TREE_VIEW( program->tree ) );\n\tgtk_tree_selection_set_mode( select, GTK_SELECTION_SINGLE );\n\tprogram->select_changed_sid = g_signal_connect( \n\t\tG_OBJECT( select ), \"changed\",\n\t\tG_CALLBACK( program_selection_changed_cb ), program );\n\tgtk_signal_connect( GTK_OBJECT( program->tree ), \"event\",\n\t\tGTK_SIGNAL_FUNC( program_tree_event_cb ), program );\n\tgtk_widget_show( program->tree );\n\n\t/* Toolkit Browser pane.\n\t */\n\tpanechild = panechild_new( program->rpane, _( \"Definition Browser\" ) );\n\n\t/* Have to put toolkitbrowser in an ebox so the search entry gets\n\t * clipped to the pane size.\n\t */\n\tebox = gtk_event_box_new();\n\tgtk_container_add( GTK_CONTAINER( panechild ), GTK_WIDGET( ebox ) );\n\tgtk_widget_show( ebox );\n\n\tprogram->defbrowser = defbrowser_new();\n\tvobject_link( VOBJECT( program->defbrowser ), \n\t\tIOBJECT( program->kitg ) );\n\tdefbrowser_set_program( program->defbrowser, program );\n\tgtk_container_add( GTK_CONTAINER( ebox ), \n\t\tGTK_WIDGET( program->defbrowser ) );\n\tgtk_widget_show( GTK_WIDGET( program->defbrowser ) );\n\n\tswin = gtk_scrolled_window_new( NULL, NULL );\n\tgtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ),\n\t\tGTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );\n\tgtk_paned_pack2( GTK_PANED( program->lpane ), swin, TRUE, TRUE );\n\tgtk_widget_show( swin );\n\n\tprogram->text = program_text_new();\n\tg_signal_connect(\n\t\tgtk_text_view_get_buffer( GTK_TEXT_VIEW( program->text ) ),\n\t\t\"notify::cursor-position\",\n                G_CALLBACK( program_text_cursor_position ), program );\n\tg_signal_connect(\n\t\tgtk_text_view_get_buffer( GTK_TEXT_VIEW( program->text ) ),\n\t\t\"changed\",\n                G_CALLBACK( program_text_changed ), program );\n\n\tgtk_container_add( GTK_CONTAINER( swin ), program->text );\n\tgtk_widget_show( program->text );\n\n\tgtk_widget_grab_focus( program->text );\n}\n\nstatic void\nprogram_popdown( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys )\n{\n\tProgram *program = PROGRAM( iwnd );\n\n\tprefs_set( \"PROGRAM_PANE_POSITION\", \"%d\", \n\t\tgtk_paned_get_position( GTK_PANED( program->lpane ) ) );\n\n\t/* We can't parse in popdown, we may have lost too much of the rest of \n\t * nip2 before here.\n\t */\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nprogram_link( Program *program, Toolkitgroup *kitg )\n{\n\tprogram->kitg = kitg;\n\tprogram_title( program );\n\tiwindow_set_size_prefs( IWINDOW( program ), \n\t\t\"PROGRAM_WIDTH\", \"PROGRAM_HEIGHT\" );\n\tiwindow_set_build( IWINDOW( program ), \n\t\t(iWindowBuildFn) program_build, NULL, NULL, NULL );\n\tiwindow_set_popdown( IWINDOW( program ), program_popdown, NULL );\n\tiwindow_build( IWINDOW( program ) );\n\tprogram_all = g_slist_prepend( program_all, program );\n\tprogram_refresh( program );\n\n\tprogram->kitgroup_changed_sid = \n\t\tg_signal_connect( G_OBJECT( program->kitg ), \"changed\",\n\t\t\tG_CALLBACK( program_kitgroup_changed ), program );\n\tprogram->kitgroup_destroy_sid = \n\t\tg_signal_connect( G_OBJECT( program->kitg ), \"destroy\",\n\t\t\tG_CALLBACK( program_kitgroup_destroy ), program );\n\n\tpane_set_state( program->rpane, \n\t\tprogram->rpane_open, program->rpane_position );\n}\n\nProgram *\nprogram_new( Toolkitgroup *kitg )\n{\n\tProgram *program = gtk_type_new( TYPE_PROGRAM );\n\n\tprogram_link( program, kitg );\n\n\treturn( program );\n}\n"
  },
  {
    "path": "src/program.h",
    "content": "/* Decls for program.c ... edit window\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_PROGRAM (program_get_type())\n#define PROGRAM( obj ) (GTK_CHECK_CAST( (obj), TYPE_PROGRAM, Program ))\n#define PROGRAM_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_PROGRAM, ProgramClass ))\n#define IS_PROGRAM( obj ) (GTK_CHECK_TYPE( (obj), TYPE_PROGRAM ))\n#define IS_PROGRAM_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_PROGRAM ))\n\nstruct _Program {\n\tiWindow parent_class;\n\n\t/* The set of kits we manage.\n\t */\n\tToolkitgroup *kitg;\n\n\tGtkWidget *text;\n\tgboolean dirty;\t\t/* Has the text changed since we set it */\n\tguint text_hash;\t/* Hash of the last text we set */\n\tGtkWidget *tree;\n\tPane *lpane;\n\tint pane_position;\n\tPane *rpane;\n\tint rpane_position;\n\tgboolean rpane_open;\n\tDefbrowser *defbrowser;\n\tguint refresh_timeout;\t/* Timeout for UI refresh */\n\tguint select_changed_sid;\t\n\tguint row_inserted_sid;\t\n\tguint row_deleted_sid;\t\n\n\t/* Track during drags.\n\t */\n\tToolkit *to_kit;\n\tint to_pos;\n\n\t/* Store for kit/tool view.\n\t */\n\tGtkTreeStore *store;\n\n\t/* Listen for all kit changes here.\n\t */\n\tguint kitgroup_changed_sid;\t\n\tguint kitgroup_destroy_sid;\t\t\n\t\n\t/* The current kit.\n\t */\n\tToolkit *kit;\t\t\n\tguint kit_destroy_sid;\t\n\n\t/* The selected tool.\n\t */\n\tTool *tool;\t\n\tint pos;\t\t/* Position of tool in kit */\n\tguint tool_destroy_sid;\t\n\n\t/* Current search settings.\n\t */\n\tchar *search;\n\tgboolean csens;\t\t/* Case sensitive */\n\tgboolean fromtop;\t/* Start search from beginning again */\n#ifdef HAVE_GREGEX\n\tgboolean regexp;\t/* Interpret as regexp */\n\tGRegex *comp;\t\t/* Compiled pattern */\n#endif /*HAVE_GREGEX*/\n\n\t/* Current search position.\n\t */\n\tSymbol *find_sym;\t/* Tool containing search point */\n\tsize_t find_start;\t/* Offset into tool text of found string */\n\tsize_t find_end;\t\n\tguint find_sym_destroy_sid;/* Watch for find_sym death here */\n};\n\ntypedef struct _ProgramClass {\n\tiWindowClass parent_class;\n\n\t/* My methods.\n\t */\n} ProgramClass;\n\nGtkType program_get_type( void );\nGtkWidget *program_text_new( void );\nProgram *program_new( Toolkitgroup *kitg );\n\ngboolean program_select( Program *program, Model *model );\n"
  },
  {
    "path": "src/progress.c",
    "content": "/* Handle feedback about eval progress.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your watch) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG_MEMUSE\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic iContainerClass *progress_parent_class = NULL;\n\n/* Our signals. \n */\nenum {\n\tSIG_BEGIN,\t\t/* Switch to busy state */\n\tSIG_UPDATE,\t\t/* Busy progress update */\n\tSIG_END,\t\t/* End busy state */\n\tSIG_LAST\n};\n\nstatic guint progress_signals[SIG_LAST] = { 0 };\n\n/* Delay before we start showing busy feedback.\n */\nstatic const double progress_busy_delay = 1.0;\n\n/* Delay between busy updates.\n */\nstatic const double progress_update_interval = 0.1;\n\nvoid\nprogress_begin( void )\n{\n\tProgress *progress = progress_get();\n\n\tg_assert( progress->count >= 0 );\n\n#ifdef DEBUG\n\tprintf( \"progress_begin: %d\\n\", progress->count );\n#endif /*DEBUG*/\n\n\tprogress->count += 1;\n\n\tif( progress->count == 1 ) {\n\t\tg_timer_start( progress->busy_timer );\n\t\tg_timer_start( progress->update_timer );\n\n#ifdef DEBUG_MEMUSE\n\t\tprintf( \"progress_begin:\\n\" );\n\t\tim__print_all();\n#endif /*DEBUG_MEMUSE*/\n\t}\n}\n\nstatic void\nprogress_update( Progress *progress )\n{\n\t/* Don't show the process and cancel button for a bit.\n\t */\n\tif( progress->count ) {\n\t\tdouble elapsed = g_timer_elapsed( progress->busy_timer, NULL );\n\n\t\tif( !progress->busy && \n\t\t\telapsed > progress_busy_delay ) {\n#ifdef DEBUG\n\t\t\tprintf( \"progress_update: displaying progress bar\\n\" );\n#endif /*DEBUG*/\n\n\t\t\tg_signal_emit( G_OBJECT( progress ), \n\t\t\t\tprogress_signals[SIG_BEGIN], 0 );\n\t\t\tprogress->busy = TRUE;\n\t\t}\n\t}\n \n\t/* Update regularly, even if we're not inside a begin/end\n\t * block.\n\t */\n\tif( g_timer_elapsed( progress->update_timer, NULL ) > \n\t\tprogress_update_interval ) {\n\t\tgboolean cancel;\n\n#ifdef DEBUG\n\t\tprintf( \"progress_update:\\n\" );\n#endif /*DEBUG*/\n\n\t\tg_timer_start( progress->update_timer );\n\n\t\t/* Overwrite the message if we're cancelling.\n\t\t */\n\t\tif( progress->cancel ) {\n\t\t\tvips_buf_rewind( &progress->feedback );\n\t\t\tvips_buf_appends( &progress->feedback, \n\t\t\t\t_( \"Cancelling\" ) );\n\t\t\tvips_buf_appends( &progress->feedback, \" ...\" );\n\t\t}\n\n\t\tcancel = FALSE;\n\t\tg_signal_emit( progress, \n\t\t\tprogress_signals[SIG_UPDATE], 0, &cancel );\n\t\tif( cancel )\n\t\t\tprogress->cancel = TRUE;\n\n\t\t/* Rather dangerous, but we need this to give nice updates\n\t\t * for the feedback thing.\n\t\t */\n\t\tprocess_events();\n\n#ifdef DEBUG_MEMUSE\n\t\tprintf( \"progress_update:\\n\" );\n\t\tim__print_all();\n#endif /*DEBUG_MEMUSE*/\n\t}\n}\n\ngboolean\nprogress_update_percent( int percent, int eta )\n{\n\tProgress *progress = progress_get();\n\n\tvips_buf_rewind( &progress->feedback );\n\tif( eta > 30 ) {\n\t\tint minutes = (eta + 30) / 60;\n\n\t\tvips_buf_appendf( &progress->feedback, ngettext( \n\t\t\t\"%d minute left\", \"%d minutes left\", \n\t\t\tminutes ), minutes );\n\t}\n\telse if( eta > 5 ) \n\t\tvips_buf_appendf( &progress->feedback, ngettext( \n\t\t\t\"%d second left\", \"%d seconds left\", \n\t\t\teta ), eta );\n\telse\n\t\t/* The empty string changes the height of the progress bar\n\t\t * argh.\n\t\t */\n\t\tvips_buf_appendf( &progress->feedback, \" \" );\n\n\tprogress->percent = percent;\n\n\tprogress_update( progress );\n\n\treturn( progress->cancel );\n}\n\ngboolean\nprogress_update_expr( Expr *expr )\n{\n\tProgress *progress = progress_get();\n\n\tvips_buf_rewind( &progress->feedback );\n\tvips_buf_appends( &progress->feedback, _( \"Calculating\" ) );\n\tvips_buf_appends( &progress->feedback, \" \" );\n\tif( expr ) \n\t\texpr_name( expr, &progress->feedback );\n\telse\n\t\tvips_buf_appends( &progress->feedback, symbol_get_last_calc() );\n\tvips_buf_appends( &progress->feedback, \" ...\" );\n\tprogress->percent = 0;\n\n\tprogress_update( progress );\n\n\treturn( progress->cancel );\n}\n\ngboolean\nprogress_update_loading( int percent, const char *filename )\n{\n\tProgress *progress = progress_get();\n\n\tvips_buf_rewind( &progress->feedback );\n\tvips_buf_appends( &progress->feedback, _( \"Loading\" ) );\n\tvips_buf_appendf( &progress->feedback, \" \\\"%s\\\"\", filename );\n\tprogress->percent = percent;\n\n\tprogress_update( progress );\n\n\treturn( progress->cancel );\n}\n\ngboolean\nprogress_update_tick( void )\n{\n\tProgress *progress = progress_get();\n\n\tprogress_update( progress );\n\n\treturn( progress->cancel );\n}\n\nvoid\nprogress_end( void )\n{\n\tProgress *progress = progress_get();\n\n\tprogress->count -= 1;\n\n#ifdef DEBUG\n\tprintf( \"progress_end: %d\\n\", progress->count );\n#endif /*DEBUG*/\n\n\tg_assert( progress->count >= 0 );\n\n\tif( !progress->count ) {\n\t\tif( progress->busy )\n\t\t\tg_signal_emit( G_OBJECT( progress ), \n\t\t\t\tprogress_signals[SIG_END], 0 );\n\n\t\tprogress->cancel = FALSE;\n\t\tprogress->busy = FALSE;\n\n#ifdef DEBUG_MEMUSE\n\t\tprintf( \"progress_end:\\n\" );\n\t\tim__print_all();\n#endif /*DEBUG_MEMUSE*/\n\t}\n}\n\nstatic void\nprogress_class_init( ProgressClass *class )\n{\n\tprogress_parent_class = g_type_class_peek_parent( class );\n\n\tprogress_signals[SIG_BEGIN] = g_signal_new( \"begin\",\n\t\tG_OBJECT_CLASS_TYPE( class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ProgressClass, begin ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\n\tprogress_signals[SIG_UPDATE] = g_signal_new( \"update\",\n\t\tG_OBJECT_CLASS_TYPE( class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ProgressClass, update ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__POINTER,\n\t\tG_TYPE_NONE, 1,\n\t\tG_TYPE_POINTER );\n\n\tprogress_signals[SIG_END] = g_signal_new( \"end\",\n\t\tG_OBJECT_CLASS_TYPE( class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( ProgressClass, end ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n}\n\nstatic void\nprogress_init( Progress *progress )\n{\n#ifdef DEBUG\n\tprintf( \"progress_init\\n\" );\n#endif /*DEBUG*/\n\n\tprogress->count = 0;\n\tprogress->busy_timer = g_timer_new();\n\tprogress->update_timer = g_timer_new();\n\tprogress->cancel = FALSE;\n\tprogress->busy = FALSE;\n\tvips_buf_init_static( &progress->feedback, \n\t\tprogress->buf, PROGRESS_FEEDBACK_SIZE );\n}\n\nGType\nprogress_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ProgressClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) progress_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Progress ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) progress_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_IOBJECT, \n\t\t\t\"Progress\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic Progress *\nprogress_new( void )\n{\n\tProgress *progress = PROGRESS( g_object_new( TYPE_PROGRESS, NULL ) );\n\n\treturn( progress );\n}\n\nProgress *\nprogress_get( void ) \n{\n\tstatic Progress *progress = NULL;\n\n\tif( !progress )\n\t\tprogress = progress_new();\n\n\treturn( progress );\n}\n"
  },
  {
    "path": "src/progress.h",
    "content": "/* Handle feedback about eval progress.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your watch) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* The max size of the feedback message.\n */\n#define PROGRESS_FEEDBACK_SIZE (100)\n\n#define TYPE_PROGRESS (progress_get_type())\n#define PROGRESS( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_PROGRESS, Progress ))\n#define PROGRESS_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_PROGRESS, ProgressClass))\n#define IS_PROGRESS( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_PROGRESS ))\n#define IS_PROGRESS_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_PROGRESS ))\n#define PROGRESS_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_PROGRESS, ProgressClass ))\n\ntypedef struct _Progress {\n\tiObject parent_object;\n\n\t/* Nest progress_begin() calls with this.\n\t */\n\tint count;\n\n\t/* How long we've been busy, time since last update.\n\t */\n\tGTimer *busy_timer;\n\tGTimer *update_timer;\n\n\t/* Trying to cancel.\n\t */\n\tgboolean cancel;\n\n\t/* In the \"busy\" state, ie. we've emitted \"begin\" and so we need to\n\t * emit \"end\" on progress_end().\n\t */\n\tgboolean busy;\n\n\t/* The feedback message we suggest, percent for progress bar.\n\t */\n\tVipsBuf feedback;\n\tchar buf[PROGRESS_FEEDBACK_SIZE];\n\tint percent;\n} Progress;\n\ntypedef struct _ProgressClass {\n\tiObjectClass parent_class;\n\n\t/* Entering busy state: display progress bar, change cursor, etc.\n\t */\n\tvoid (*begin)( Progress * );\n\n\t/* Progress update. Set cancel to cancel computation.\n\t */\n\tvoid (*update)( Progress *, gboolean *cancel );\n\n\t/* End busy state. Restore screen.\n\t */\n\tvoid (*end)( Progress * );\n} ProgressClass;\n\n/* Called from all over nip2 as computation proceeds.\n */\nvoid progress_begin( void );\ngboolean progress_update_percent( int percent, int eta );\ngboolean progress_update_expr( Expr *expr );\ngboolean progress_update_loading( int percent, const char *filename );\ngboolean progress_update_tick( void );\nvoid progress_end( void );\n\nGType progress_get_type( void );\nProgress *progress_get( void );\n"
  },
  {
    "path": "src/real.c",
    "content": "/* an input real ... put/get methods\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ValueClass *parent_class = NULL;\n\nstatic void\nreal_class_init( RealClass *class )\n{\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\nreal_init( Real *real )\n{\n\tiobject_set( IOBJECT( real ), CLASS_REAL, NULL );\n}\n\nGType\nreal_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( RealClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) real_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Real ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) real_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_VALUE, \n\t\t\t\"Real\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/real.h",
    "content": "/* a real in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_REAL (real_get_type())\n#define REAL( obj ) (GTK_CHECK_CAST( (obj), TYPE_REAL, Real ))\n#define REAL_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_REAL, RealClass ))\n#define IS_REAL( obj ) (GTK_CHECK_TYPE( (obj), TYPE_REAL ))\n#define IS_REAL_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_REAL ))\n\ntypedef struct _Real {\n\tValue parent_object;\n\n\t/* Private ... build iobject caption here.\n\t */\n} Real;\n\ntypedef struct _RealClass {\n\tValueClass parent_class;\n\n\t/* My methods.\n\t */\n} RealClass;\n\nGType real_get_type( void );\n"
  },
  {
    "path": "src/reduce.c",
    "content": "/* Graph reducer.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* trace each regeneration\n#define DEBUG_REGEN\n */\n\n/* trace each reduction\n#define DEBUG_TRACE\n */\n\n/* trace copies of code from compile heap to main heap.\n#define DEBUG_COPY\n */\n\n/* trace just member regeneration\n#define DEBUG_REGEN_MEMBER\n */\n\n/* Turn on WHNF tests.\n#define WHNF_DEBUG\n */\n\n/* regular tests that we stay in weak head normal form\n#define WHNF_DEBUG\n */\n\n/* State of the reduction engine.\n */\nReduce *reduce_context;\n\n/* Index with a CombinatorType, get the number of args that combinator takes.\n        COMB_S = 0,\t\t\n        COMB_SL,\t\n        COMB_SR,\n\tCOMB_I,\n\tCOMB_K,\n\tCOMB_GEN,\n */\nstatic int nargs[] = {3, 3, 3, 1, 2, 3};\n\n/* Recomps this time.\n */\nint reduce_total_recomputations = 0;\n\n/* The current expr being reduced. Used for computation feedback messages.\n */\nstatic Expr *reduce_current_expr = NULL;\n\n/* Eval error here. Longjmp back a ways.\n */\nvoid\nreduce_throw( Reduce *rc )\n{\n\tif( !rc->running ) \n\t\terror( \"panic: uncaught exception in reduce_throw()!\" );\n\telse\n\t\tlongjmp( rc->error[--rc->running], -1 );\n}\n\n\nstatic gboolean\nreduce_safe_pointer_wrap( Reduce *rc, \n\tPElement *out, reduce_safe_pointer_fn fn, \n\tvoid *a, void *b, void *c, void *d,\n\tvoid **result )\n{\n\tREDUCE_CATCH_START( FALSE );\n\t*result = fn( rc, out, a, b, c, d );\n\tREDUCE_CATCH_STOP; \n\n\treturn( TRUE );\n}\n\n/* Call a function, passing in a \"safe\" PElement ... ie. the PElement points\n * at a fresh element which will be safe from the GC. \n */\nvoid *\nreduce_safe_pointer( Reduce *rc, reduce_safe_pointer_fn fn, \n\tvoid *a, void *b, void *c, void *d )\n{\n\tElement e;\n\tPElement pe;\n\tvoid *result;\n\n\te.type = ELEMENT_NOVAL;\n\te.ele = (void *) 12;\n\tPEPOINTE( &pe, &e );\n\theap_register_element( rc->heap, &e );\n\n\tif( !reduce_safe_pointer_wrap( rc, &pe, fn, a, b, c, d, &result ) ) {\n\t\theap_unregister_element( rc->heap, &e );\n\t\treduce_throw( rc );\n\t}\n\theap_unregister_element( rc->heap, &e );\n\n\treturn( result );\n}\n\nvoid\nreduce_error_typecheck( Reduce *rc, \n\tPElement *e, const char *name, const char *type )\n{\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\terror_top( _( \"Typecheck error.\" ) );\n\tvips_buf_appendf( &buf, \n\t\t_( \"%s expected %s, instead saw:\" ), name, type );\n\tvips_buf_appends( &buf, \"\\n  \" );\n\titext_value_ev( rc, &buf, e );\n\terror_sub( \"%s\", vips_buf_all( &buf ) );\n\n\treduce_throw( rc );\n}\n\nstatic void\nreduce_error_toobig( Reduce *rc, const char *name )\n{\n\terror_top( _( \"Overflow error.\" ) );\n\terror_sub( _( \"%s too long.\" ), name );\n\treduce_throw( rc );\n}\n\n/* 'get' a list: convert a MANAGEDSTRING into a list, if necessary.\n */\nvoid\nreduce_get_list( Reduce *rc, PElement *list )\n{\n\tif( !heap_get_list( list ) )\n\t\treduce_throw( rc );\n}\n\n/* Map over a heap list. Reduce the list spine as we go, don't reduce the\n * heads. \n */\nvoid *\nreduce_map_list( Reduce *rc, \n\tPElement *base, reduce_map_list_fn fn, void *a, void *b )\n{\n\tPElement e = *base;\n\n\treduce_spine( rc, &e );\n\n\tif( !PEISLIST( &e ) ) \n\t\treduce_error_typecheck( rc, &e, \"reduce_map_list\", \"list\" );\n\n\twhile( PEISFLIST( &e ) ) {\n\t\tPElement head;\n\t\tvoid *res;\n\n\t\treduce_get_list( rc, &e );\n\n\t\t/* Apply user function to the head.\n\t\t */\n\t\tPEGETHD( &head, &e );\n\t\tif( (res = fn( rc, &head, a, b )) )\n\t\t\treturn( res );\n\n\t\t/* Reduce the tail.\n\t\t */\n\t\tPEGETTL( &e, &e );\n\t\treduce_spine( rc, &e );\n\t}\n\n\treturn( NULL );\n}\n\ntypedef struct _ReduceMapDict {\n\treduce_map_dict_fn fn;\n\tvoid *a;\n\tvoid *b;\n} ReduceMapDict;\n\nstatic void *\nreduce_map_dict_entry( Reduce *rc, PElement *head, ReduceMapDict *map_dict )\n{\n\tchar key[256];\n\tPElement p1, p2;\n\tvoid *result;\n\n\treduce_spine( rc, head );\n\tif( !PEISFLIST( head ) ) \n\t\treduce_error_typecheck( rc, head, \"reduce_map_dict\", \"[*]\" );\n\n\treduce_get_list( rc, head );\n\tPEGETHD( &p1, head );\n\treduce_get_string( rc, &p1, key, 256 );\n\tPEGETTL( &p2, head );\n\n\treduce_spine( rc, &p2 );\n\tif( !PEISFLIST( &p2 ) ) \n\t\treduce_error_typecheck( rc, &p2, \"reduce_map_dict\", \"[*]\" );\n\n\treduce_get_list( rc, &p2 );\n\tPEGETHD( &p1, &p2 );\n\tif( (result = map_dict->fn( rc, key, &p1, map_dict->a, map_dict->b )) )\n\t\treturn( result );\n\n\tPEGETTL( &p1, &p2 );\n\treduce_spine( rc, &p1 );\n\tif( !PEISELIST( &p1 ) ) \n\t\treduce_error_typecheck( rc, &p1, \"reduce_map_dict\", \"[]\" );\n\n\treturn( NULL );\n}\n\n/* Map over a list of [\"key\", value] pairs.\n */\nvoid *\nreduce_map_dict( Reduce *rc, PElement *base, \n\treduce_map_dict_fn fn, void *a, void *b )\n{\n\tReduceMapDict map_dict;\n\n\tmap_dict.fn = fn;\n\tmap_dict.a = a;\n\tmap_dict.b = b;\n\n\treturn( reduce_map_list( rc, base, \n\t\t(reduce_map_list_fn) reduce_map_dict_entry, &map_dict, NULL ) );\n}\n\nstatic void *\nreduce_clone_list_sub( Reduce *rc, PElement *head, PElement *out )\n{\n\tPElement lhs;\n\n\tif( !heap_list_add( rc->heap, out, &lhs ) )\n\t\treduce_throw( rc );\n\tPEPUTPE( &lhs, head );\n\n\theap_list_next( out );\n\n\treturn( NULL );\n}\n\n/* Clone a list ... just clone the spine, copy pointers to the heads. Reduce\n * the list as we go (strict shallow clone). We update out as we go, so that\n * on return it points to the tail (always []) of the cloned list.\n */\nvoid\nreduce_clone_list( Reduce *rc, PElement *base, PElement *out )\n{\n\theap_list_init( out );\n\n\t(void) reduce_map_list( rc, base, \n\t\t(reduce_map_list_fn) reduce_clone_list_sub, out, NULL );\n}\n\n/* Sub-fn of below. Add a character to the buffer.\n */\nstatic void *\nreduce_add_char( Reduce *rc, PElement *base, char **buf, int *sz )\n{\n\t/* Overflow?\n\t */\n\tif( *sz == 0 ) \n\t\treduce_error_toobig( rc, \"[char]\" );\n\n\t/* Reduce this list element.\n\t */\n\treduce_spine( rc, base );\n\n\t/* Should be a char.\n\t */\n\tif( !PEISCHAR( base ) ) \n\t\treduce_error_typecheck( rc, base, \"reduce_add_char\", \"char\" );\n\n\t/* Add to buffer.\n\t */\n\t**buf = PEGETCHAR( base );\n\t(*buf)++;\n\t(*sz)--;\n\n\treturn( NULL );\n}\n\n/* Evaluate a PElement into a string buffer. Return the number of characters \n * in string, not including '\\0' terminator.\n */\nint\nreduce_get_string( Reduce *rc, PElement *base, char *buf, int n )\n{\n\tint sz = n - 1;\n\n\treduce_spine( rc, base );\n\n\tif( PEISMANAGEDSTRING( base ) ) {\n\t\t/* A static string ... rather than expanding to a list and\n\t\t * parsing, we can copy directly.\n\t\t */\n\t\tManagedstring *managedstring = PEGETMANAGEDSTRING( base );\n\n\t\tim_strncpy( buf, managedstring->string, n );\n\t\tsz -= strlen( buf );\n\t}\n\telse {\n\t\t(void) reduce_map_list( rc, base, \n\t\t\t(reduce_map_list_fn) reduce_add_char, &buf, &sz );\n\n\t\t/* Add '\\0' terminator.\n\t\t */\n\t\t*buf = '\\0';\n\t}\n\n\treturn( n - sz - 1 );\n}\n\nstatic void *\nreduce_get_lstring_sub( Reduce *rc, PElement *base, GSList **labels, int *n )\n{\n\tchar buf[MAX_STRSIZE];\n\n\t(void) reduce_get_string( rc, base, buf, MAX_STRSIZE );\n\t*labels = g_slist_append( *labels, g_strdup( buf ) );\n\n\treturn( NULL );\n}\n\n/* Evaluate to [[char]]. Return the number of strings we read. \n */\nint\nreduce_get_lstring( Reduce *rc, PElement *base, GSList **labels )\n{\n\tint n;\n\n\tn = 0;\n\t*labels = NULL;\n\t(void) reduce_map_list( rc, base,\n\t\t(reduce_map_list_fn) reduce_get_lstring_sub, labels, &n );\n\n\treturn( n );\n}\n\n/* Get an element as a boolean. \n */\ngboolean\nreduce_get_bool( Reduce *rc, PElement *base )\n{\n\treduce_spine( rc, base );\n\n\tif( !PEISBOOL( base ) ) \n\t\treduce_error_typecheck( rc, base, \"reduce_get_bool\", \"bool\" );\n\n\treturn( PEGETBOOL( base ) );\n}\n\n/* Get an element as a real. \n */\ndouble\nreduce_get_real( Reduce *rc, PElement *base )\n{\n\t/* Reduce this element.\n\t */\n\treduce_spine( rc, base );\n\n\t/* Should be a real.\n\t */\n\tif( !PEISREAL( base ) ) \n\t\treduce_error_typecheck( rc, base, \"reduce_get_real\", \"real\" );\n\n\treturn( PEGETREAL( base ) );\n}\n\n/* Get an element as a class. \n */\nvoid\nreduce_get_class( Reduce *rc, PElement *base )\n{\n\t/* Reduce this element.\n\t */\n\treduce_spine( rc, base );\n\n\t/* Should be a class.\n\t */\n\tif( !PEISCLASS( base ) ) \n\t\treduce_error_typecheck( rc, base, \"reduce_get_class\", \"class\" );\n}\n\n/* Get an element as an image. \n */\nImageinfo *\nreduce_get_image( Reduce *rc, PElement *base )\n{\n\t/* Reduce this element.\n\t */\n\treduce_spine( rc, base );\n\n\t/* Should be an image.\n\t */\n\tif( !PEISIMAGE( base ) ) \n\t\treduce_error_typecheck( rc, base, \"reduce_get_image\", \"image\" );\n\n\treturn( PEGETII( base ) );\n}\n\n/* Sub-fn of below. Add a real to the buffer.\n */\nstatic void *\nreduce_add_real( Reduce *rc, PElement *base, double **buf, int *sz )\n{\n\t/* Overflow?\n\t */\n\tif( *sz == 0 ) \n\t\treduce_error_toobig( rc, \"[real]\" );\n\n\t/* Add to buffer.\n\t */\n\t**buf = reduce_get_real( rc, base );\n\t(*buf)++;\n\t(*sz)--;\n\n\treturn( NULL );\n}\n\n/* Get an element as a realvec. Return length of vector.\n */\nint\nreduce_get_realvec( Reduce *rc, PElement *base, double *buf, int n )\n{\n\tint sz = n;\n\n\t(void) reduce_map_list( rc, base, \n\t\t(reduce_map_list_fn) reduce_add_real, &buf, &sz );\n\n\treturn( n - sz );\n}\n\n/* Sub-fn of below. Add an ii to the buffer.\n */\nstatic void *\nreduce_add_image( Reduce *rc, PElement *base, Imageinfo ***buf, int *sz )\n{\n\t/* Overflow?\n\t */\n\tif( *sz == 0 ) \n\t\treduce_error_toobig( rc, \"[image]\" );\n\n\t/* Add to buffer.\n\t */\n\t**buf = reduce_get_image( rc, base );\n\t(*buf)++;\n\t(*sz)--;\n\n\treturn( NULL );\n}\n\n/* Get an element as a realvec. Return length of vector.\n */\nint\nreduce_get_imagevec( Reduce *rc, PElement *base, Imageinfo **buf, int n )\n{\n\tint sz = n;\n\n\t(void) reduce_map_list( rc, base, \n\t\t(reduce_map_list_fn) reduce_add_image, &buf, &sz );\n\n\treturn( n - sz );\n}\n\n/* Test for 1st sz elements are reals. Init sz < 0 for unlimited test.\n */\nstatic void *\nreduce_test_real( Reduce *rc, PElement *base, int *sz )\n{\n\t/* Tested enough?\n\t */\n\tif( *sz == 0 ) \n\t\treturn( NULL );\n\n\t(void) reduce_get_real( rc, base );\n\t(*sz)--;\n\n\treturn( NULL );\n}\n\n/* Sub fn ... get the length of a list of real.\n */\nint\nreduce_get_real_size( Reduce *rc, PElement *base )\n{\n\tint n;\n\n\tn = -1;\n\t(void) reduce_map_list( rc, base, \n\t\t(reduce_map_list_fn) reduce_test_real, &n, NULL );\n\n\treturn( -1 - n );\n}\n\n/* Sub fn of below ... get the length of one line from a matrix.\n */\nstatic void *\nreduce_get_line_size( Reduce *rc, PElement *base, int *w, int *h )\n{\n\tint l;\n\n\tl = reduce_get_real_size( rc, base );\n\n\tif( *w == 0 )\n\t\t*w = l;\n\telse if( *w != l ) {\n\t\terror_top( _( \"Not rectangular.\" ) );\n\t\terror_sub( _( \"Matrix of real is not rectangular. \"\n\t\t\t\"Found row of length %d, should be %d.\" ), l, *w );\n\t\treduce_throw( rc );\n\t}\n\n\t*h += 1;\n\n\treturn( NULL );\n}\n\n/* Find the size of a matrix. Write xsize/ysize to args.\n */\nvoid\nreduce_get_matrix_size( Reduce *rc, \n\tPElement *base, int *xsize, int *ysize )\n{\n\tint w, h;\n\n\tw = 0; \n\th = 0;\n\t(void) reduce_map_list( rc, base, \n\t\t(reduce_map_list_fn) reduce_get_line_size, &w, &h );\n\n\tif( w == 0 || h == 0 ) {\n\t\terror_top( _( \"Zero dimension.\" ) );\n\t\terror_sub( _( \"Matrix has width %d, height %d.\" ), w, h ); \n\t\treduce_throw( rc );\n\t}\n\n\t*xsize = w;\n\t*ysize = h;\n}\n\n/* Track stuff during a get_matrix in one of these.\n */\ntypedef struct {\n\tdouble *buf;\t\t/* Start of output buffer */\n\tint mx;\t\t\t/* Size of output buffer */\n\tint w, h;\t\t/* Size of matrix we have generated */\n\tint i;\t\t\t/* Current write point */\n} GetMatrixInfo;\n\n/* Sub-fn of below ... get another line of the matrix.\n */\nstatic void *\nreduce_get_line( Reduce *rc, PElement *base, GetMatrixInfo *gmi )\n{\n\tint l;\n\tint remain = gmi->mx - gmi->i;\n\n\t/* Read next line from matrix.\n\t */\n\tl = reduce_get_realvec( rc, base, gmi->buf + gmi->i, remain );\n\n\t/* Overflow?\n\t */\n\tif( l > remain ) \n\t\treduce_error_toobig( rc, \"Matrix\" );\n\n\t/* 1st line?\n\t */\n\tif( gmi->h == 0 )\n\t\tgmi->w = l;\n\telse if( l != gmi->w ) {\n\t\terror_top( _( \"Not rectangular.\" ) );\n\t\terror_sub( _( \"Matrix of real is not rectangular. \"\n\t\t\t\"Found row of length %d, should be %d.\" ), l, gmi->w );\n\t\treduce_throw( rc );\n\t}\n\n\t/* Move pointers on!\n\t */\n\tgmi->h++;\n\tgmi->i += l;\n\n\treturn( NULL );\n}\n\n/* Get an element as a matrix. Return length of buffer used. \n * Write xsize/ysize to args.\n */\nint\nreduce_get_matrix( Reduce *rc, \n\tPElement *base, double *buf, int n, int *xsize, int *ysize )\n{\n\tGetMatrixInfo gmi;\n\n\tgmi.buf = buf;\n\tgmi.mx = n;\n\tgmi.w = gmi.h = 0;\n\tgmi.i = 0;\n\n\t(void) reduce_map_list( rc, base, \n\t\t(reduce_map_list_fn) reduce_get_line, &gmi, NULL );\n\n\t*xsize = gmi.w;\n\t*ysize = gmi.h;\n\n\treturn( gmi.i );\n}\n\n/* Test for object is the empty list.\n */\ngboolean\nreduce_is_elist( Reduce *rc, PElement *base )\n{\n\treduce_spine( rc, base );\n\tif( PEISELIST( base ) ) \n\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\n/* Test for object is any list.\n */\ngboolean\nreduce_is_list( Reduce *rc, PElement *base )\n{\n\treduce_spine( rc, base );\n\tif( PEISLIST( base ) ) \n\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\n/* Sub-fn of below. Test for 1st sz elements are char. We have several\n * possible return values :-(\n *\n * - evaluation error ... we can throw an exception\n * - we find a non-char in the first n elements ... return -1\n * - we have tested the first n and want to stop looking ... return -2\n * - all OK so far, but we want to keep looking ... return NULL\n */\nstatic void *\nreduce_test_char( Reduce *rc, PElement *base, int *sz )\n{\n\t/* Tested enough?\n\t */\n\tif( *sz == 0 ) \n\t\treturn( (void *) -2 );\n\n\t/* Reduce this list element.\n\t */\n\treduce_spine( rc, base );\n\n\t/* Should be a char.\n\t */\n\tif( !PEISCHAR( base ) ) \n\t\treturn( (void *) -1 );\n\n\t/* Move on.\n\t */\n\t(*sz)--;\n\n\treturn( NULL );\n}\n\n/* Test the first n elements of a list are char. n < 0 means test all\n * elements.\n */\nstatic gboolean\nreduce_n_is_string( Reduce *rc, PElement *base, int sz )\n{\n\tvoid *result;\n\n\treduce_spine( rc, base );\n\n\t/* We know managedstrings are strings without needing to expand them.\n\t */\n\tif( PEISMANAGEDSTRING( base ) )\n\t\treturn( TRUE );\n\n\t/* reduce_map_list() will throw an exeception if we give it a\n\t * non-list.\n\t */\n\tif( !PEISLIST( base ) ) \n\t\treturn( FALSE ); \n\n\tresult = reduce_map_list( rc, base, \n\t\t(reduce_map_list_fn) reduce_test_char, &sz, NULL );\n\n\tif( result == (void *) -1 )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Test for object is string. Just test the first few elements, so we\n * allow infinite strings.\n */\ngboolean\nreduce_is_string( Reduce *rc, PElement *base )\n{\n\treturn( reduce_n_is_string( rc, base, 4 ) );\n}\n\n/* Test for list is a finite string. \n */\ngboolean\nreduce_is_finitestring( Reduce *rc, PElement *base )\n{\n\treturn( reduce_n_is_string( rc, base, -1 ) );\n}\n\n/* Test for list is realvec.\n */\ngboolean\nreduce_is_realvec( Reduce *rc, PElement *base )\n{\n\tint sz = 4;\n\n\treduce_spine( rc, base );\n\tif( !PEISLIST( base ) ) \n\t\treturn( FALSE );\n\n\tif( reduce_map_list( rc, base, \n\t\t(reduce_map_list_fn) reduce_test_real, &sz, NULL ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Test for 1st sz elements are reals. Init sz < 0 for unlimited test.\n */\nstatic void *\nreduce_test_image( Reduce *rc, PElement *base, int *sz )\n{\n\t/* Tested enough?\n\t */\n\tif( *sz == 0 ) \n\t\treturn( NULL );\n\n\t(void) reduce_get_image( rc, base );\n\t(*sz)--;\n\n\treturn( NULL );\n}\n\n/* Test for list is imagevec.\n */\ngboolean\nreduce_is_imagevec( Reduce *rc, PElement *base )\n{\n\tint sz = 4;\n\n\treduce_spine( rc, base );\n\tif( !PEISLIST( base ) ) \n\t\treturn( FALSE );\n\n\tif( reduce_map_list( rc, base, \n\t\t(reduce_map_list_fn) reduce_test_image, &sz, NULL ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Sub-fn of below ... test another line of the matrix.\n */\nstatic void *\nreduce_test_line( Reduce *rc, PElement *base, int *w, int *h )\n{\n\t/* Test next line from matrix.\n\t */\n\tif( !reduce_is_realvec( rc, base ) )\n\t\treturn( base );\n\n\treturn( NULL );\n}\n\n/* Test for object is [[real]] .. don't test for rectangularness.\n */\ngboolean\nreduce_is_matrix( Reduce *rc, PElement *base )\n{\n\treduce_spine( rc, base );\n\tif( !PEISLIST( base ) ) \n\t\treturn( FALSE );\n\n\tif( reduce_map_list( rc, base, \n\t\t(reduce_map_list_fn) reduce_test_line, NULL, NULL ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Test for object is a class.\n */\ngboolean\nreduce_is_class( Reduce *rc, PElement *klass )\n{\n\treduce_spine( rc, klass );\n\tif( PEISCLASS( klass ) )\n\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\n/* Test for instance is an exact instance ... ie. no inheritance.\n\n\tFIXME ... yuk! strcmp()!!\n\n */\ngboolean\nreduce_is_instanceof_exact( Reduce *rc, const char *name, PElement *instance )\n{\n        char txt[256];\n        VipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tif( !reduce_is_class( rc, instance ) )\n\t\treturn( FALSE );\n\n        symbol_qualified_name( PEGETCLASSCOMPILE( instance )->sym, &buf );\n        if( strcmp( name, vips_buf_all( &buf ) ) == 0 )\n                return( TRUE );\n\n\treturn( FALSE );\n}\n\n/* Test for thing is an instance of the named class symbol.\n */\ngboolean\nreduce_is_instanceof( Reduce *rc, const char *name, PElement *instance )\n{\n\tPElement super;\n\n\treduce_spine( rc, instance );\n\tif( !PEISCLASS( instance ) )\n\t\treturn( FALSE );\n\tif( reduce_is_instanceof_exact( rc, name, instance ) )\n\t\treturn( TRUE );\n\tif( class_get_super( instance, &super ) && !PEISELIST( &super ) ) \n\t\treturn( reduce_is_instanceof( rc, name, &super ) );\n\n\treturn( FALSE );\n}\n\n/* Find the length of a list, with a bailout for the largest size we test.\n * Handy for avoiding finding the length of \"[1..]\".\n */\nint\nreduce_list_length_max( Reduce *rc, PElement *base, int max_length )\n{\n\tPElement p;\n\tint i;\n\n\t/* Reduce to first element.\n\t */\n\tp = *base;\n\treduce_spine( rc, &p );\n\n\t/* Does it look like the start of a list? \n\t */\n\tif( !PEISLIST( &p ) ) \n\t\treduce_error_typecheck( rc, &p, _( \"List length\" ), \"list\" );\n\n\tif( PEISMANAGEDSTRING( &p ) ) {\n\t\tManagedstring *managedstring = PEGETMANAGEDSTRING( &p );\n\n\t\ti = strlen( managedstring->string );\n\t}\n\telse {\n\t\t/* Loop down list.\n\t\t */\n\t\tfor( i = 0; PEISFLIST( &p ); i++ ) {\n\t\t\tHeapNode *hn;\n\n\t\t\tif( max_length != -1 && i > max_length ) \n\t\t\t\treduce_error_toobig( rc, \"list\" );\n\n\t\t\treduce_get_list( rc, &p );\n\n\t\t\thn = PEGETVAL( &p );\n\t\t\tPEPOINTRIGHT( hn, &p );\n\n\t\t\treduce_spine( rc, &p );\n\t\t}\n\n\t\tg_assert( PEISELIST( &p ) );\n\t}\n\n\treturn( i );\n}\n\n/* Find the length of a list.\n */\nint\nreduce_list_length( Reduce *rc, PElement *base )\n{\n\treturn( reduce_list_length_max( rc, base, -1 ) );\n}\n\n/* Point \"out\" at the nth element of a list. Index from 0.\n */\nvoid\nreduce_list_index( Reduce *rc, PElement *base, int n, PElement *out )\n{\n\tPElement p;\n\tint i;\n\tHeapNode *hn;\n\n\tif( n < 0 ) {\n\t\terror_top( _( \"Bad argument.\" ) );\n\t\terror_sub( _( \"List index must be positive, not %d\" ), n );\n\t\treduce_throw( rc );\n\t}\n\n\tp = *base;\n\treduce_spine( rc, &p );\n\n\tif( !PEISLIST( &p ) ) \n\t\treduce_error_typecheck( rc, &p, _( \"List index\" ), \"list\" );\n\n\tfor( i = n;; ) {\n\t\tif( PEISELIST( &p ) ) {\n\t\t\terror_top( _( \"Bad argument.\" ) );\n\t\t\terror_sub( _( \"List only has %d elements, \"\n\t\t\t\t\"unable to get element %d.\" ), n - i, n );\n\t\t\treduce_throw( rc );\n\t\t}\n\n\t\tg_assert( PEISFLIST( &p ) );\n\n\t\treduce_get_list( rc, &p );\n\n\t\thn = PEGETVAL( &p );\n\t\tPEPOINTRIGHT( hn, &p );\n\n\t\tif( --i < 0 )\n\t\t\tbreak;\n\n\t\treduce_spine( rc, &p );\n\t}\n\n\tif( trace_flags & TRACE_OPERATOR ) {\n\t\tVipsBuf *buf = trace_push();\n\n\t\ttrace_pelement( base );\n\t\tvips_buf_appendf( buf, \" \\\"?\\\" %d ->\\n\", n );\n\t}\n\n\tPEPOINTLEFT( hn, out );\n\n\tif( trace_flags & TRACE_OPERATOR ) {\n\t\ttrace_result( TRACE_OPERATOR, out );\n\t\ttrace_pop();\n\t}\n}\n\n/* No args allowed error.\n */\nstatic void\nargserror( Reduce *rc,  PElement *a )\n{\n\tchar txt[MAX_ERROR_FRAG];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\titext_value_ev( rc, &buf, a );\n\n\terror_top( _( \"No arguments allowed.\" ) );\n\terror_sub( _( \"Object \\\"%s\\\" should have no arguments.\" ),\n\t\tvips_buf_all( &buf ) );\n\treduce_throw( rc );\n}\n\n#ifdef WHNF_DEBUG\n/* Test for PElement is in weak head-normal form.\n */\nstatic gboolean\nis_WHNF( PElement *out )\n{\n\tPElement spine;\n\tint i;\n\tHeapNode *hn;\n\tSymbol *sym;\n\tCompile *compile;\n\tint na;\n\n\t/* Might be a base type ...\n\t */\n\tif( PEISREAL( out ) || \n\t\tPEISCOMPLEX( out ) || PEISNUM( out ) || PEISCHAR( out ) ||\n\t\tPEISBOOL( out ) || PEISTAG( out ) || PEISIMAGE( out ) ||\n\t\tPEISLIST( out ) || PEISCLASS( out ) || PEISSYMREF( out ) ||\n\t\tPEISCOMPILEREF( out ) || PEISNOVAL( out ) )\n\t\treturn( TRUE );\n\n\t/* Must be a function or generator ... loop down the spine, counting \n\t * args.\n\t */\n\tfor( spine = *out, i = 0; PEGETTYPE( &spine ) == ELEMENT_NODE; i++ ) {\n\t\thn = PEGETVAL( &spine );\n\n\t\tif( hn->type != TAG_APPL )\n\t\t\tbreak;\n\n\t\tPEPOINTLEFT( PEGETVAL( &spine ), &spine );\n\t}\n\n\tif( PEISBINOP( &spine ) ) {\n\t\tif( i > 1 )\n\t\t\treturn( FALSE );\n\t}\n\telse if( PEISUNOP( &spine ) ) {\n\t\tif( i > 0 )\n\t\t\treturn( FALSE );\n\t}\n\telse if( PEISCOMB( &spine ) ) {\n\t\tif( i > nargs[(int) PEGETCOMB( &spine )] - 1 )\n\t\t\treturn( FALSE );\n\t}\n\telse if( PEISCONSTRUCTOR( &spine ) ) {\n\t\tcompile = PEGETCOMPILE( &spine );\n\t\tna = compile->nparam + compile->nsecret;\n\n\t\tif( i > na ) {\n\t\t\tprintf( \"constructor %s with %d args \", \n\t\t\t\tsymbol_name( sym ), i );\n\t\t\tprintf( \"should have %d args\\n\", compile->nparam ); \n\t\t\treturn( FALSE );\n\t\t}\n\t}\n\telse if( PEISSYMBOL( &spine ) ) {\n\t\t/* If it's a VIPS or a builtin with too few args, it's OK.\n\t\t */\n\t\tsym = SYMBOL( PEGETVAL( &spine ) );\n\n\t\tif( sym->type == SYM_EXTERNAL ) {\n\t\t\tif( i < sym->fn_nargs )\n\t\t\t\treturn( TRUE );\n\t\t}\n\t\telse if( sym->type == SYM_BUILTIN ) {\n\t\t\tif( i < sym->builtin->nargs )\n\t\t\t\treturn( TRUE );\n\t\t}\n\n\t\t/* Nope ... should have been reduced.\n\t\t */\n\t\treturn( FALSE );\n\t}\n\telse {\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n#endif /*WHNF_DEBUG*/\n\n/* Main reduction machine loop.\n */\nvoid\nreduce_spine( Reduce *rc, PElement *out )\n{\n\tHeap *heap = rc->heap;\n\tPElement np;\n\n\t/* Check for possible C stack overflow ... can't go over 2M on most\n\t * systems if we're using (or any of our libs are using) threads.\n\t */\n\tif( (char *) main_c_stack_base - (char *) &rc > 2000000 ) {\n\t\terror_top( _( \"Overflow error.\" ) );\n\t\terror_sub( _( \"C stack overflow. Expression too complex.\" ) );\n\t\treduce_throw( rc );\n\t}\n\n\t/* Point node pointer at reduction start.\n\t */\n\tnp = *out;\n\n\t/* Start a new frame.\n\t */\n\tRSPUSHFRAME( rc, out ); \n\nreduce_start:\n\treduce_total_recomputations += 1;\n\tif( (reduce_total_recomputations % 100000) == 0 ) {\n\t\tif( progress_update_expr( reduce_current_expr ) ) {\n\t\t\terror_top( _( \"Cancelled.\" ) );\n\t\t\terror_sub( _( \"Evaluation cancelled.\" ) );\n\t\t\treduce_throw( rc );\n\t\t}\n\t}\n\n#ifdef DEBUG_TRACE\n{\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_pelement( rc->heap, &buf, out, TRUE );\n\tprintf( \"reduce_spine: %s\\n\", vips_buf_all( &buf ) );\n}\n#endif /*DEBUG_TRACE*/\n\n\tswitch( PEGETTYPE( &np ) ) {\n\tcase ELEMENT_CHAR:\n\tcase ELEMENT_BOOL:\n\tcase ELEMENT_ELIST:\n\tcase ELEMENT_TAG:\n\tcase ELEMENT_SYMREF:\n\tcase ELEMENT_COMPILEREF:\n\tcase ELEMENT_MANAGED:\n\t\t/* Base type .. no more reduction needed.\n\t\t */\n\n\t\t/* Should have no args.\n\t\t */\n\t\tif( RSFRAMESIZE( rc ) != 0 ) \n\t\t\targserror( rc, &np );\n\n\t\tbreak;\n\n\tcase ELEMENT_CONSTRUCTOR:\n\t{\n\t\tCompile *compile;\n\t\tHeapNode **arg;\n\t\tPElement rhs1;\n\t\tint na;\n\n\t\t/* Class constructor.\n\t\t */\n\t\tcompile = PEGETCOMPILE( &np );\n\t\tg_assert( is_class( compile ) );\n\n\t\t/* Class args ... real params, secret params.\n\t\t */\n\t\tna = compile->nparam + compile->nsecret;\n\n\t\t/* Get args.\n\t\t */\n\t\tif( !RSCHECKARGS( rc, na ) ) \n\t\t\tbreak;\n\t\targ = &RSGET( rc, na - 1 );\n\n\t\tif( na == 0 ) {\n\t\t\t/* Zero args ... just construct on top of the current\n\t\t\t * node pointer.\n\t\t\t */\n\t\t\taction_proc_construct( rc, compile, arg, &np );\n\t\t\tgoto reduce_start;\n\t\t}\n\n\t\t/* Overwrite RHS of arg[0], make LHS into COMB_I.\n\t\t */\n\t\tPEPOINTRIGHT( arg[0], &rhs1 ); \n\t\taction_proc_construct( rc, compile, arg, &rhs1 );\n\t\tPPUTLEFT( arg[0], ELEMENT_COMB, COMB_I );\n\n\t\tRSPOP( rc, na );\n\t\tif( RSFRAMEEMPTY( rc ) )\n\t\t\tnp = RSGETWB( rc ); \n\t\telse\n\t\t\tPEPOINTLEFT( RSGET( rc, 0 ), &np );\n\t\tPEPUTP( &np, \n\t\t\tGETRT( arg[0] ), GETRIGHT( arg[0] ) );\n\n\t\tgoto reduce_start;\n\t}\n\n\tcase ELEMENT_SYMBOL:\n\t{\n\t\tSymbol *sym = PEGETSYMBOL( &np );\n\n\t\tg_assert( sym );\n\n\t\tswitch( sym->type ) {\n\t\tcase SYM_VALUE:\n\t\t{\n\t\t\tCompile *compile = sym->expr->compile;\n\n\t\t\t/* Make sure it's clean ... we can get \n\t\t\t * links to dirty syms through dynamic dependencies.\n\t\t\t */\n\t\t\tif( sym->dirty ) {\n\t\t\t\terror_top( _( \"No value.\" ) );\n\t\t\t\terror_sub( _( \"Symbol \\\"%s\\\" has no value.\" ), \n\t\t\t\t\tsymbol_name( sym ) );\n\t\t\t\treduce_throw( rc );\n\t\t\t}\n\n\t\t\t/* We copy code, but link to values. We have to take a\n\t\t\t * fresh copy of code as (together with any args our\n\t\t\t * context might supply) it will expand to a value,\n\t\t\t * which we might then edit in a row. We want to make \n\t\t\t * sure any edits do not zap the original code.\n \t\t\t */\n\t\t\tif( compile->nparam + compile->nsecret == 0 ) {\n\t\t\t\t/* Make sure the value has copied to the main\n\t\t\t\t * heap.\n\t\t\t\t */\n\t\t\t\tif( PEISNOVAL( &sym->expr->root ) ) {\n\t\t\t\t\tgboolean res;\n\n\t\t\t\t\tres = reduce_regenerate( sym->expr, \n\t\t\t\t\t\t&sym->expr->root );\n\t\t\t\t\texpr_new_value( sym->expr );\n\n\t\t\t\t\tif( !res ) \n\t\t\t\t\t\treduce_throw( rc );\n\t\t\t\t}\n\n\t\t\t\t/* Link to this sym's value.\n\t\t\t\t */\n\t\t\t\tPEPUTPE( &np, &sym->expr->root );\n\t\t\t}\n\t\t\telse \n\t\t\t\t/* Copy compiled code from the private compile\n\t\t\t\t * heap.\n\t\t\t\t */\n\t\t\t\tif( !heap_copy( rc->heap, compile, &np ) )\n\t\t\t\t\treduce_throw( rc );\n\n\t\t\tgoto reduce_start;\n\t\t}\n\n\t\tcase SYM_PARAM:\n\t\t\t/* All params should be taken out by var abstract.\n\t\t\t */\n\t\t\tprintf( \"sym-param found, argh: \" ); \n\t\t\tsymbol_name_print( sym );\n\t\t\tprintf( \"\\n\" );\n\t\t\tg_assert( FALSE );\n\t\t\tbreak;\n\n\t\tcase SYM_EXTERNAL:\n\t\t{\n\t\t\tHeapNode **arg;\n\t\t\tint na;\n\n\t\t\t/* A VIPS function.\n\t\t\t */\n\t\t\tna = sym->fn_nargs;\n\n\t\t\t/* Get args. \n\t\t\t */\n\t\t\tif( !RSCHECKARGS( rc, na ) ) \n\t\t\t\t/* Not enough ... function result. \n\t\t\t\t */\n\t\t\t\tbreak;\n\n\t\t\t/* Run strictly.\n\t\t\t */\n\t\t\targ = &RSGET( rc, na - 1 );\n\n\t\t\taction_dispatch( rc, NULL, reduce_spine,\n\t\t\t\t-1, sym->function->name, FALSE,\n\t\t\t\t(ActionFn) call_run, na, arg, \n\t\t\t\tsym->function );\n\n\t\t\t/* Find output element.\n\t\t\t */\n\t\t\tRSPOP( rc, na );\n\n\t\t\tif( RSFRAMEEMPTY( rc ) )\n\t\t\t\tnp = RSGETWB( rc ); \n\t\t\telse\n\t\t\t\tPEPOINTLEFT( RSGET( rc, 0 ), &np );\n\n\t\t\t/* Write to node above.\n\t\t\t */\n\t\t\tPEPUTP( &np, \n\t\t\t\tGETRT( arg[0] ), GETRIGHT( arg[0] ) );\n\n\t\t\tgoto reduce_start;\n\t\t}\n\n\t\tcase SYM_BUILTIN:\n\t\t{\n\t\t\tHeapNode **arg;\n\t\t\tint na;\n\n\t\t\t/* A builtin function.\n\t\t\t */\n\t\t\tna = sym->builtin->nargs;\n\n\t\t\t/* Get args. \n\t\t\t */\n\t\t\tif( !RSCHECKARGS( rc, na ) ) \n\t\t\t\t/* Not enough ... function result. \n\t\t\t\t */\n\t\t\t\tbreak;\n\n\t\t\t/* Run strictly.\n\t\t\t */\n\t\t\targ = &RSGET( rc, na - 1 );\n\n\t\t\taction_dispatch( rc, NULL, reduce_spine,\n\t\t\t\t-1, sym->builtin->name, sym->builtin->override,\n\t\t\t\t(ActionFn) builtin_run, \n\t\t\t\tna, arg, sym->builtin );\n\n\t\t\t/* Find output element.\n\t\t\t */\n\t\t\tRSPOP( rc, na );\n\n\t\t\tif( RSFRAMEEMPTY( rc ) )\n\t\t\t\tnp = RSGETWB( rc ); \n\t\t\telse\n\t\t\t\tPEPOINTLEFT( RSGET( rc, 0 ), &np );\n\n\t\t\t/* Write to node above.\n\t\t\t */\n\t\t\tPEPUTP( &np, \n\t\t\t\tGETRT( arg[0] ), GETRIGHT( arg[0] ) );\n\n\t\t\tgoto reduce_start;\n\t\t}\n\n\t\tcase SYM_ZOMBIE:\n\t\t{\n\t\t\tSymbol *new_sym;\n\n\t\t\t/* Could be defined on an enclosing scope. Search\n\t\t\t * outwards for a definition.\n\t\t\t */\n\t\t\tif( !(new_sym = compile_resolve_top( sym )) ) {\n\t\t\t\tsymbol_not_defined( sym );\n\t\t\t\treduce_throw( rc );\n\t\t\t}\n\n\t\t\t/* Zap linked symbol into graph.\n\t\t\t */\n\t\t\tPEPUTP( &np, ELEMENT_SYMBOL, new_sym );\n\n\t\t\tgoto reduce_start;\n\t\t}\n\n\t\tcase SYM_ROOT:\n\t\tcase SYM_WORKSPACE:\n\t\tcase SYM_WORKSPACEROOT:\n\t\t\t/* Becomes a symref ... base type.\n\t\t\t */\n\t\t\tPEPUTP( &np, ELEMENT_SYMREF, sym );\n\n\t\t\t/* Should have no args.\n\t\t\t */\n\t\t\tif( RSFRAMESIZE( rc ) != 0 ) \n\t\t\t\targserror( rc, &np );\n\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tg_assert( FALSE );\n\t\t}\n\n\t\tbreak;\n\t}\n\n\tcase ELEMENT_NODE:\n\t{\n\t\tHeapNode *hn;\n\n\t\t/* Get the node that np points to.\n\t\t */\n\t\thn = PEGETVAL( &np );\n\n\t\tswitch( hn->type ) {\n\t\tcase TAG_CONS:\n\t\tcase TAG_DOUBLE:\n\t\tcase TAG_COMPLEX:\n\t\tcase TAG_CLASS:\n\t\t\t/* Base type ... reduction all done! We don't test\n\t\t\t * that class's superclasses are base, as they aren't\n\t\t\t * always for non-top-level base types ... see \n\t\t\t * reduce_pelement().\n\t\t\t */\n\n\t\t\t/* Should have no args.\n\t\t\t */\n\t\t\tif( RSFRAMESIZE( rc ) != 0 )\n\t\t\t\targserror( rc, &np );\n\n\t\t\tbreak;\n\n\t\tcase TAG_APPL:\n\t\t\t/* Function application ... push this node and loop\n\t\t\t * down the LHS looking for a combinator.\n\t\t\t */\n\n\t\t\t/* Push this node.\n\t\t\t */\n\t\t\tRSPUSH( rc, hn );\n\n\t\t\t/* Move down left branch.\n\t\t\t */\n\t\t\tPEPOINTLEFT( hn, &np );\n\n\t\t\tgoto reduce_start;\n\n\t\tcase TAG_GEN:\n\t\t{\n\t\t\tdouble d1;\n\t\t\tdouble d2;\n\t\t\tdouble d3 = 0.0;\t/* keeps gcc happy */\n\t\t\tgboolean limit;\n\t\t\tHeapNode *hn1, *hn2;\n\n\t\t\t/* Extract next, step, final.\n\t\t\t */\n\t\t\td1 = GETLEFT( hn )->body.num;\n\t\t\td2 = GETLEFT( GETRIGHT( hn ) )->body.num;\n\t\t\tlimit = GETRT( GETRIGHT( hn ) ) != ELEMENT_ELIST;\n\t\t\tif( limit )\n\t\t\t\td3 = GETRIGHT( GETRIGHT( hn ) )->body.num;\n\n\t\t\tif( trace_flags & TRACE_OPERATOR ) {\n\t\t\t\tVipsBuf *buf = trace_push();\n\n\t\t\t\tif( limit )\n\t\t\t\t\tvips_buf_appendf( buf, \n\t\t\t\t\t\t\"generator %g %g %g ->\\n\",\n\t\t\t\t\t\td1, d2, d3 );\n\t\t\t\telse\n\t\t\t\t\tvips_buf_appendf( buf, \n\t\t\t\t\t\t\"generator %g %g ->\\n\",\n\t\t\t\t\t\td1, d2 );\n\t\t\t}\n\n\t\t\t/* At end?\n\t\t\t */\n\t\t\tif( GETRT( GETRIGHT( hn ) ) != ELEMENT_ELIST &&\n\t\t\t\t((d2 > 0 && d1 > d3) || \n\t\t\t\t\t(d2 < 0 && d1 < d3)) ) {\n\t\t\t\t/* Make I node for end.\n\t\t\t\t */\n\t\t\t\thn->type = TAG_APPL;\n\t\t\t\tPPUT( hn, \n\t\t\t\t\tELEMENT_COMB, COMB_I,\n\t\t\t\t\tELEMENT_ELIST, NULL ); \n\n\t\t\t\t/* Write back to node above.\n\t\t\t\t */\n\t\t\t\tPEPUTP( &np, ELEMENT_ELIST, NULL );\n\n\t\t\t\tif( trace_flags & TRACE_OPERATOR ) {\n\t\t\t\t\ttrace_result( TRACE_OPERATOR, &np );\n\t\t\t\t\ttrace_pop();\n\t\t\t\t}\n\n\t\t\t\t/* All done!\n\t\t\t\t */\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Not at end, or no final. Generate new gen node.\n\t\t\t */\n\t\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\t\treduce_throw( rc );\n\t\t\t*hn1 = *hn;\n\n\t\t\t/* Change hn into CONS node.\n\t\t\t */\n\t\t\thn->type = TAG_CONS;\n\t\t\tPPUTRIGHT( hn, ELEMENT_NODE, hn1 ); \n\n\t\t\t/* Generate new number.\n\t\t\t */\n\t\t\tif( NEWNODE( heap, hn2 ) )\n\t\t\t\treduce_throw( rc );\n\t\t\thn2->type = TAG_DOUBLE;\n\t\t\thn2->body.num = d1 + d2;\n\t\t\tPPUTLEFT( hn1, \n\t\t\t\tELEMENT_NODE, hn2 ); \n\n\t\t\tif( trace_flags & TRACE_OPERATOR ) {\n\t\t\t\ttrace_result( TRACE_OPERATOR, &np );\n\t\t\t\ttrace_pop();\n\t\t\t}\n\n\t\t\t/* And loop!\n\t\t\t */\n\t\t\tgoto reduce_start;\n\t\t}\n\n\t\tcase TAG_FILE:\n\t\t{\n\t\t\tManagedfile *managedfile = MANAGEDFILE( GETLEFT( hn ) );\n\t\t\tint ch = managedfile_getc( managedfile );\n\n\t\t\t/* -1 means error, 0 means EOF.\n\t\t\t */\n\t\t\tif( ch == -1 )\n\t\t\t\treduce_throw( rc );\n\t\t\telse if( ch == 0 ) {\n\t\t\t\t/* Turn us into [].\n\t\t\t\t */\n\t\t\t\thn->type = TAG_APPL;\n\t\t\t\tPPUT( hn, \n\t\t\t\t\tELEMENT_COMB, COMB_I,\n\t\t\t\t\tELEMENT_ELIST, NULL ); \n\t\t\t}\n\t\t\telse {\n\t\t\t\tHeapNode *hn1;\n\n\t\t\t\t/* Not at end ... make another CONS.\n\t\t\t\t */\n\t\t\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\t\t\treduce_throw( rc );\n\t\t\t\t*hn1 = *hn;\n\t\t\t\thn->type = TAG_CONS;\n\t\t\t\tPPUT( hn, \n\t\t\t\t\tELEMENT_CHAR, GUINT_TO_POINTER( ch ), \n\t\t\t\t\tELEMENT_NODE, hn1 );\n\t\t\t}\n\n\t\t\t/* Loop again with new np.\n\t\t\t */\n\t\t\tgoto reduce_start;\n\t\t}\n\n\t\tcase TAG_FREE:\n\t\t\tg_assert( FALSE );\n\n\t\tdefault:\n\t\t\tg_assert( FALSE );\n\t\t}\n\n\t\tbreak;\n\t}\n\n\tcase ELEMENT_COMB:\n\t{\n\t\tCombinatorType comb = PEGETCOMB( &np );\n\t\tHeapNode *hn1, *hn2;\n\t\tHeapNode **arg;\n\t\tint na;\n\n\t\tna = nargs[(int) comb];\n\n\t\t/* Get args. \n\t\t */\n\t\tif( !RSCHECKARGS( rc, na ) ) \n\t\t\t/* Not enough ... function result. \n\t\t\t */\n\t\t\tbreak;\n\n\t\t/* Extract args.\n\t\t */\n\t\targ = &RSGET( rc, na - 1 );\n\n\t\tswitch( comb ) {\n\t\tcase COMB_S:\n\t\t\t/* Rewrite graph for S a b c => (a c) (b c).\n\t\t\t */\n\n\t\t\t/* Make (b c) appl node.\n\t\t\t */\n\t\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\t\treduce_throw( rc );\n\t\t\t*hn1 = *arg[0];\n\t\t\tPPUTLEFT( hn1, \n\t\t\t\tGETRT( arg[1] ), GETRIGHT( arg[1] ) ); \n\t\t\tPPUTRIGHT( arg[0], \n\t\t\t\tELEMENT_NODE, hn1 );\n\n\t\t\t/* Make (a c) appl node.\n\t\t\t */\n\t\t\tif( NEWNODE( heap, hn2 ) )\n\t\t\t\treduce_throw( rc );\n\t\t\t*hn2 = *hn1;\n\t\t\tPPUTLEFT( hn2, \n\t\t\t\t GETRT( arg[2] ), GETRIGHT( arg[2] ) );\n\t\t\tPPUTLEFT( arg[0], \n\t\t\t\tELEMENT_NODE, hn2 ); \n\n\t\t\t/* End of S ... now pop three, push 1 and loop.\n\t\t\t */\n\t\t\tRSPOP( rc, 2 );\n\t\t\tPEPOINTLEFT( arg[0], &np );\n\t\t\tgoto reduce_start;\n\n\t\tcase COMB_SL:\n\t\t\t/* Rewrite graph for Sl a b c => (a c) b.\n\t\t\t */\n\n\t\t\t/* Make (a c) appl node.\n\t\t\t */\n\t\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\t\treduce_throw( rc );\n\t\t\t*hn1 = *arg[0];\n\t\t\tPPUTLEFT( hn1, \n\t\t\t\tGETRT( arg[2] ), GETRIGHT( arg[2] ) );\n\t\t\tPPUT( arg[0], \n\t\t\t\tELEMENT_NODE, hn1,\n\t\t\t\tGETRT( arg[1] ), GETRIGHT( arg[1] ) );\n\n\t\t\t/* End of SL ... now pop three, push 1 and loop.\n\t\t\t */\n\t\t\tRSPOP( rc, 2 );\n\t\t\tPEPOINTLEFT( arg[0], &np );\n\t\t\tgoto reduce_start;\n\n\t\tcase COMB_SR:\n\t\t\t/* Rewrite graph for Sr a b c => a (b c).\n\t\t\t */\n\n\t\t\t/* Make (b c) appl node.\n\t\t\t */\n\t\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\t\treduce_throw( rc );\n\t\t\t*hn1 = *arg[0];\n\t\t\tPPUTLEFT( hn1, \n\t\t\t\tGETRT( arg[1] ), GETRIGHT( arg[1] ) );\n\t\t\tPPUT( arg[0],\n\t\t\t\tGETRT( arg[2] ), GETRIGHT( arg[2] ),\n\t\t\t\tELEMENT_NODE, hn1 );\n\n\t\t\t/* End of SR ... now pop three, push 1 and loop.\n\t\t\t */\n\t\t\tRSPOP( rc, 2 );\n\t\t\tPEPOINTLEFT( arg[0], &np );\n\t\t\tgoto reduce_start;\n\n\t\tcase COMB_I:\n\t\t\t/* No action necessary.\n\t\t\t */\n\t\t\tbreak;\n\n\t\tcase COMB_K:\n\t\t\t/* Make I node. \n\t\t\t */\n\t\t\tPPUT( arg[0], \n\t\t\t\tELEMENT_COMB, COMB_I,\n\t\t\t\tGETRT( arg[1] ), GETRIGHT( arg[1] ) );\n\n\t\t\tbreak;\n\n\t\tcase COMB_GEN:\n\t\t{\n\t\t\tdouble d1;\n\t\t\tdouble d2 = 0.0;\t/* Don't need to init, but */\n\t\t\tdouble d3 = 0.0;\t/* keeps gcc happy */\n\t\t\tPElement rhs1, rhs2, rhs3;\n\n\t\t\tPEPOINTRIGHT( arg[2], &rhs1 );\n\t\t\tPEPOINTRIGHT( arg[1], &rhs2 );\n\t\t\tPEPOINTRIGHT( arg[0], &rhs3 );\n\t\t\treduce_spine_strict( rc, &rhs1 );\n\t\t\treduce_spine_strict( rc, &rhs2 );\n\t\t\treduce_spine_strict( rc, &rhs3 );\n\n\t\t\t/* May have done ourselves in the process.\n\t\t\t */\n\t\t\tif( arg[0]->type != TAG_APPL )\n\t\t\t\tbreak;\n\n\t\t\t/* Typecheck.\n\t\t\t */\n\t\t\tif( !PEISREAL( &rhs1 ) ) \n\t\t\t\treduce_error_typecheck( rc, &rhs1, \n\t\t\t\t\t_( \"List generator\" ), \"real\" );\n\t\t\td1 = PEGETREAL( &rhs1 );\n\n\t\t\tif( !PEISELIST( &rhs2 ) && !PEISREAL( &rhs2 ) ) \n\t\t\t\treduce_error_typecheck( rc, &rhs2, \n\t\t\t\t\t_( \"List generator\" ), \"real\" );\n\t\t\tif( PEISREAL( &rhs2 ) )\n\t\t\t\td2 = PEGETREAL( &rhs2 ); \n\n\t\t\tif( !PEISELIST( &rhs3 ) && !PEISREAL( &rhs3 ) ) \n\t\t\t\treduce_error_typecheck( rc, &rhs3, \n\t\t\t\t\t_( \"List generator\" ), \"real\" );\n\t\t\tif( PEISREAL( &rhs3 ) )\n\t\t\t\td3 = PEGETREAL( &rhs3 ); \n\n\t\t\tif( trace_flags & TRACE_OPERATOR ) {\n\t\t\t\tVipsBuf *buf = trace_push();\n\n\t\t\t\tvips_buf_appends( buf, \"generator constructor \" );\n\t\t\t\ttrace_args( arg, 3 );\n\t\t\t}\n\n\t\t\t/* If next is missing, set default.\n\t\t\t */\n\t\t\tif( PEISREAL( &rhs2 ) ) \n\t\t\t\t/* Next is there, calculate step.\n\t\t\t\t */\n\t\t\t\td2 = d2 - d1;\n\t\t\telse {\n\t\t\t\t/* If final is missing, default is 1.\n\t\t\t\t */\n\t\t\t\tif( PEISELIST( &rhs3 ) ) \n\t\t\t\t\td2 = 1;\n\t\t\t\telse {\n\t\t\t\t\t/* Final is there, choose 1 or -1.\n\t\t\t\t\t */\n\t\t\t\t\tif( d1 < d3 )\n\t\t\t\t\t\td2 = 1;\n\t\t\t\t\telse\n\t\t\t\t\t\td2 = -1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Make node for pairing next and final fields.\n\t\t\t */\n\t\t\tif( NEWNODE( heap, hn1 ) )\n\t\t\t\treduce_throw( rc );\n\t\t\thn1->type = TAG_COMPLEX;\n\t\t\tPPUT( hn1, \n\t\t\t\tGETRT( arg[1] ), GETRIGHT( arg[1] ),\n\t\t\t\tGETRT( arg[0] ), GETRIGHT( arg[0] ) );\n\n\t\t\t/* Link to old root, make gen node.\n\t\t\t */\n\t\t\targ[0]->type = TAG_GEN;\n\t\t\tPPUT( arg[0],\n\t\t\t\tGETRT( arg[2] ), GETRIGHT( arg[2] ),\n\t\t\t\tELEMENT_NODE, hn1 );\n\n\t\t\t/* Make step node.\n\t\t\t */\n\t\t\tif( NEWNODE( heap, hn2 ) )\n\t\t\t\treduce_throw( rc );\n\t\t\thn2->type = TAG_DOUBLE;\n\t\t\thn2->body.num = d2;\n\t\t\tPPUTLEFT( hn1,\n\t\t\t\tELEMENT_NODE, hn2 );\n\n\t\t\tif( trace_flags & TRACE_OPERATOR ) {\n\t\t\t\tVipsBuf *buf = trace_current();\n\n\t\t\t\tvips_buf_appends( buf, \"    \" ); \n\t\t\t\ttrace_node( arg[0] );\n\t\t\t\tvips_buf_appends( buf, \"\\n\" ); \n\n\t\t\t\ttrace_text( TRACE_OPERATOR, \n\t\t\t\t\t\"%s\", vips_buf_all( buf ) ); \n\n\t\t\t\ttrace_pop();\n\t\t\t}\n\n\t\t\t/* Find output element.\n\t\t\t */\n\t\t\tRSPOP( rc, 3 );\n\t\t\tif( RSFRAMEEMPTY( rc ) )\n\t\t\t\tnp = RSGETWB( rc ); \n\t\t\telse\n\t\t\t\tPEPOINTLEFT( RSGET( rc, 0 ), &np );\n\n\t\t\t/* Restart from there.\n\t\t\t */\n\t\t\tgoto reduce_start;\n\t\t}\n\n\t\tdefault:\n\t\t\tg_assert( FALSE );\n\t\t}\n\n\t\t/* Find output element.\n\t\t */\n\t\tRSPOP( rc, na );\n\t\tif( RSFRAMEEMPTY( rc ) )\n\t\t\tnp = RSGETWB( rc ); \n\t\telse\n\t\t\tPEPOINTLEFT( RSGET( rc, 0 ), &np );\n\n\t\t/* Write to above node.\n\t\t */\n\t\tPEPUTP( &np, \n\t\t\t GETRT( arg[0] ), GETRIGHT( arg[0] ) );\n\n\t\t/* Loop again with new np.\n\t\t */\n\t\tgoto reduce_start;\n\t\t/*NOTREACHED*/\n\t}\n\n\tcase ELEMENT_BINOP:\n\t{\n\t\tBinOp bop = PEGETBINOP( &np );\n\t\tHeapNode **arg;\n\t\tCompile *compile;\n\t\tPElement rhs1, rhs2;\n\n\t\t/* Three args to binops ... first is the Compile that built us\n\t\t * (for error messages), other two are actual args.\n\t\t */\n\t\tif( !RSCHECKARGS( rc, 3 ) )\n\t\t\t/* Not enough ... function result.\n\t\t\t */\n\t\t\tbreak;\n\n\t\t/* Extract args.\n\t\t */\n\t\targ = &RSGET( rc, 2 );\n\t\tcompile = COMPILE( GETRIGHT( arg[2] ) );\n\n\t\t/* CONS is very, very lazy ... more like a combinator.\n\t\t */\n\t\tif( bop == BI_CONS ) {\n\t\t\tPEPOINTRIGHT( arg[1], &rhs1 );\n\n\t\t\tif( trace_flags & TRACE_OPERATOR ) {\n\t\t\t\ttrace_push();\n\n\t\t\t\tPEPOINTRIGHT( arg[0], &rhs2 );\n\t\t\t\ttrace_binop( compile, &rhs1, bop, &rhs2 );\n\t\t\t}\n\n\t\t\targ[0]->type = TAG_CONS;\n\t\t\tPPUTLEFT( arg[0], \n\t\t\t\tPEGETTYPE( &rhs1 ), PEGETVAL( &rhs1 ) );\n\n\t\t\tif( trace_flags & TRACE_OPERATOR ) {\n\t\t\t\tVipsBuf *buf = trace_current();\n\n\t\t\t\tvips_buf_appends( buf, \"    \" ); \n\t\t\t\ttrace_node( arg[0] );\n\t\t\t\tvips_buf_appends( buf, \"\\n\" ); \n\n\t\t\t\ttrace_text( TRACE_OPERATOR, \n\t\t\t\t\t\"%s\", vips_buf_all( buf ) );\n\n\t\t\t\ttrace_pop();\n\t\t\t}\n\n\t\t\tRSPOP( rc, 3 );\n\n\t\t\tbreak;\n\t\t}\n\n\t\taction_proc_bop( rc, compile, bop, arg );\n\n\t\t/* Find output element.\n\t\t */\n\t\tRSPOP( rc, 3 );\n\n\t\tif( RSFRAMEEMPTY( rc ) )\n\t\t\tnp = RSGETWB( rc ); \n\t\telse\n\t\t\tPEPOINTLEFT( RSGET( rc, 0 ), &np );\n\n\t\t/* Write to node above.\n\t\t */\n\t\tPEPUTP( &np, \n\t\t\tGETRT( arg[0] ), GETRIGHT( arg[0] ) );\n\n\t\t/* Loop again with new np.\n\t\t */\n\t\tgoto reduce_start;\n\t}\n\n\tcase ELEMENT_UNOP:\n\t{\n\t\tHeapNode **arg;\n\t\tCompile *compile;\n\n\t\t/* Some unary operator. First arg is the compile that built\n\t\t * us, 2nd is the actual arg that might need reducing.\n\t\t */\n\t\tif( !RSCHECKARGS( rc, 2 ) )\n\t\t\t/* Not enough ... function result.\n\t\t\t */\n\t\t\tbreak;\n\n\t\t/* Extract arg.\n\t\t */\n\t\targ = &RSGET( rc, 1 );\n\t\tcompile = COMPILE( GETRIGHT( arg[1] ) );\n\n\t\taction_dispatch( rc, compile, reduce_spine,\n\t\t\tPEGETUNOP( &np ), OPERATOR_NAME( PEGETUNOP( &np ) ),\n\t\t\tTRUE, (ActionFn) action_proc_uop, 1, arg, NULL );\n\n\t\t/* Find output element.\n\t\t */\n\t\tRSPOP( rc, 2 );\n\t\tif( RSFRAMEEMPTY( rc ) )\n\t\t\tnp = RSGETWB( rc ); \n\t\telse\n\t\t\tPEPOINTLEFT( RSGET( rc, 0 ), &np );\n\n\t\t/* Write to above node.\n\t\t */\n\t\tPEPUTP( &np, \n\t\t\t GETRT( arg[0] ), GETRIGHT( arg[0] ) );\n\n\t\t/* Loop again with new np.\n\t\t */\n\t\tgoto reduce_start;\n\t}\n\n\tcase ELEMENT_NOVAL:\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\t/* Unwind stack, restore frame pointer.\n\t */\n\tRSPOPFRAME( rc ); \n\n#ifdef WHNF_DEBUG\n\t/* Should now be in WHNF ... test!\n\t */\n\tif( !is_WHNF( out ) ) {\n\t\tchar txt[1000];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\tgraph_pelement( heap, &buf, out, TRUE );\n\t\tprintf( \"*** internal error:\\n\" );\n\t\tprintf( \"result of reduce_spine not in WHNF: \" );\n\t\tprintf( \"%s\\n\", vips_buf_all( &buf ) );\n\t\treduce_throw( rc );\n\t}\n#endif /*WHNF_DEBUG*/\n}\n\n/* Strict reduction ... fully eval all lists etc.\n */\nvoid\nreduce_spine_strict( Reduce *rc, PElement *np )\n{\n\tPElement rhs, lhs;\n\n\t/* Make sure this element is reduced.\n\t */\n\treduce_spine( rc, np );\n\n\t/* If it's a non-empty list, may need to reduce inside. Not managed\n\t * strings though, we can leave them unevaluated.\n\t */\n\tif( PEISFLIST( np ) && !PEISMANAGEDSTRING( np ) ) {\n\t\t/* Recurse for head and tail.\n\t\t */\n\t\tHeapNode *hn = PEGETVAL( np );\n\n\t\tPEPOINTLEFT( hn, &lhs );\n\t\tPEPOINTRIGHT( hn, &rhs );\n\t\treduce_spine_strict( rc, &lhs );\n\t\treduce_spine_strict( rc, &rhs );\n\t}\n}\n\n/* Free a Reduce.\n */\nvoid\nreduce_destroy( Reduce *rc )\n{\n\theap_unregister_reduce( rc->heap, rc );\n\tUNREF( rc->heap );\n\tIM_FREE( rc );\n}\n\n/* Max cells function for main reduce engine. Read from Preferences, and scale\n * by the number of workspaces we have open.\n */\nstatic int\nreduce_heap_max_fn( Heap *heap )\n{\n\treturn( workspace_number() * MAX_HEAPSIZE );\n}\n\n/* Build a Reduce.\n */\nReduce *\nreduce_new( void )\n{\n\t/* Initial heap size. Big enough that we won't need to grow just\n\t * loading prefs and standard stuff.\n\t */\n\tconst int stsz = 100000;\n\n\t/* Heap increment..\n\t */\n\tconst int incr = 2000;\n\n\tReduce *rc = INEW( NULL, Reduce );\n\n\tif( !rc )\n\t\treturn( NULL );\n\trc->sp = 0;\n\trc->fsp = 0;\n\trc->heap = NULL;\n\trc->running = 0;\n\n\trc->heap = heap_new( NULL, reduce_heap_max_fn, stsz, incr );\n\tg_object_ref( G_OBJECT( rc->heap ) );\n\tiobject_sink( IOBJECT( rc->heap ) );\n\theap_register_reduce( rc->heap, rc );\n\tiobject_set( IOBJECT( rc->heap ), \"reduce-heap\", NULL );\n\n\treturn( rc );\n}\n\n/* Reduce a PElement to a base type. Return TRUE/FALSE, no longjmp.\n */\ngboolean\nreduce_pelement( Reduce *rc, ReduceFunction fn, PElement *out )\n{\n\tgboolean res = TRUE;\n\n\tREDUCE_CATCH_START( FALSE );\n\tfn( reduce_context, out );\n\tREDUCE_CATCH_STOP;\n\n\treturn( res );\n}\n\n/* Make sure a symbol's value is registered with the main GC.\n */\nvoid\nreduce_register( Symbol *sym )\n{\n\tReduce *rc = reduce_context;\n\tHeap *heap = rc->heap;\n\n\theap_register_element( heap, &sym->base );\n}\n\n/* Make sure a symbol's value is not registered with the main GC.\n */\nvoid\nreduce_unregister( Symbol *sym )\n{\n\tReduce *rc = reduce_context;\n\tHeap *heap = rc->heap;\n\n\theap_unregister_element( heap, &sym->base );\n}\n\n/* Copy and evaluate compiled code into element pointed to by out.\n */\ngboolean\nreduce_regenerate( Expr *expr, PElement *out )\n{\n\tReduce *rc = reduce_context;\n\tHeap *heap = rc->heap;\n\n\t/* Clear any run state from old expr value.\n\t */\n\texpr_error_clear( expr );\n\tif( slist_map( expr->dynamic_links, \n\t\t(SListMapFn) link_expr_destroy, NULL ) )\n\t\treturn( FALSE );\n\n\t/* Copy new code in.\n\t */\n\tif( !heap_copy( heap, expr->compile, out ) ) {\n\t\texpr_error_set( expr );\n\t\treturn( FALSE );\n\t}\n\n#ifdef DEBUG_REGEN\n{\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_pelement( heap, &buf, out, TRUE );\n\tprintf( \"reduce_regenerate: reducing \" );\n\texpr_name_print( expr );\n\tprintf( \"graph: %s\\n\", vips_buf_all( &buf ) );\n}\n#endif /*DEBUG_REGEN*/\n\n\treduce_current_expr = expr;\n\tif( !reduce_pelement( rc, reduce_spine, out ) ) {\n\t\treduce_current_expr = NULL;\n\t\texpr_error_set( expr );\n\t\t(void) heap_gc( heap );\n\t\treturn( FALSE );\n\t}\n\treduce_current_expr = NULL;\n\n#ifdef DEBUG_REGEN\n{\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t/* Force immediate GC to pick up any stray pointers.\n\t */\n\tif( !heap_gc( heap ) ) {\n\t\texpr_error_set( expr );\n\t\treturn( FALSE );\n\t}\n\n\tgraph_pelement( heap, &buf, out, TRUE );\n\tprintf( \"reduce_regenerate: reduced \" );\n\texpr_name_print( expr );\n\tprintf( \" to: %s\\n\", vips_buf_all( &buf ) );\n}\n#endif /*DEBUG_REGEN*/\n\n\treturn( TRUE );\n}\n\n/* Regenerate an (expr this) pair.\n */\ngboolean\nreduce_regenerate_member( Expr *expr, PElement *ths, PElement *out )\n{\n\tReduce *rc = reduce_context;\n\tHeap *heap = rc->heap;\n\n\tPElement e;\n\tHeapNode *apl;\n\n\t/* New (NULL this) pair.\n\t */\n\tif( NEWNODE( heap, apl ) ) {\n\t\texpr_error_set( expr );\n\t\treturn( FALSE );\n\t}\n\tapl->type = TAG_APPL;\n\tPPUT( apl, ELEMENT_NOVAL, (void *) 10, \n\t\tPEGETTYPE( ths ), PEGETVAL( ths ) ); \n\tPEPUTP( out, ELEMENT_NODE, apl );\n\n\t/* Link code to node.\n\t */\n\tPEPOINTLEFT( apl, &e );\n\tif( !reduce_regenerate( expr, &e ) ) \n\t\treturn( FALSE );\n\n#ifdef DEBUG_REGEN_MEMBER\n{\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tgraph_pelement( heap, &buf, out, TRUE );\n\tprintf( \"reduce_regenerate_member: \" );\n\texpr_name_print( expr );\n\tprintf( \" new code: %s\\n\", vips_buf_all( &buf ) );\n}\n#endif /*DEBUG_REGEN_MEMBER*/\n\n\t/* Do initial reduction.\n\t */\n\tif( !reduce_pelement( rc, reduce_spine, out ) ) {\n\t\t/* Failure! Junk the half-made value. \n\t\t */\n\t\texpr_error_set( expr );\n\t\t(void) heap_gc( heap );\n\t\treturn( FALSE );\n\t}\n\n\t/* Special case: if this is a \"super\" row, we need to rebuild the\n\t * class.\n\t */\n\tif( is_super( expr->compile->sym ) ) {\n\t\tCompile *parent = compile_get_parent( expr->compile );\n\t\tPElement instance;\n\n\t\tPEPOINTE( &instance, &expr->row->scol->base );\n\n\t\tif( !class_new_super( heap, parent, ths, &instance ) )\n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n"
  },
  {
    "path": "src/reduce.h",
    "content": "/* Header for reduction machine.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* Huge :-( this pushes sizeof(Reduce) up to 14MB. But we need to be able to\n * loop down very long lists, eg. for a 65k x 3 LUT held as a Matrix. Drop\n * this down when we represent matricies more sensibly.\n */\n#define SPINE_SIZE (80000)\n\n/* Reduction machine state. Not very opaque ... see mark_reduce()\n */\nstruct _Reduce {\n\t/* Stack of heap nodes for spine.\n\t */\n\tHeapNode *nstack[SPINE_SIZE];\n\n\t/* Index of free element above node stack top.\n\t */\n\tint sp;\n\n\t/* Frame stack ... top of fstack is sp we block GET above.\n\t */\n\tint fstack[SPINE_SIZE];\n\n\t/* Writeback stack ... where the result of each frame goes.\n\t */\n\tPElement wbstack[SPINE_SIZE];\n\n\t/* Frame stack pointer.\n\t */\n\tint fsp;\n\n\t/* Heap we evaluate.\n\t */\n\tHeap *heap;\n\n\t/* Nested reductions ... need to be able to longjmp() out of stuff,\n\t * and restore the machine state.\n\t */\n\tint running;\n\tjmp_buf error[SPINE_SIZE];\n\tint sps[SPINE_SIZE];\n\tint fsps[SPINE_SIZE];\n\tint tsp[SPINE_SIZE];\n};\n\n#define RSPUSH(RC,N) { \\\n\tif( (RC)->sp == SPINE_SIZE ) { \\\n\t\terror_top( _( \"Stack overflow.\" ) ); \\\n\t\terror_sub( _( \"Spine stack overflow, runaway recursion?\" ) ); \\\n\t\treduce_throw( (RC) ); \\\n\t} \\\n\telse \\\n\t\t(RC)->nstack[(RC)->sp++]=(N); \\\n}\n\n/* Number of items in current frame.\n */\n#define RSFRAMESIZE(RC) ((RC)->sp - (RC)->fstack[(RC)->fsp - 1])\n\n/* Check for at least N args present.\n */\n#define RSCHECKARGS(RC,N) (RSFRAMESIZE(RC) >= (N))\n\n/* Frame is empty?\n */\n#define RSFRAMEEMPTY(RC) (RSFRAMESIZE(RC) == 0)\n\n/* Get offset from stack top, offset 0 is top item.\n */\n#define RSGET(RC,N) ((RC)->nstack[(RC)->sp - ((N) + 1)])\n\n/* Get the writeback for this frame.\n */\n#define RSGETWB(RC) ((RC)->wbstack[(RC)->fsp - 1])\n\n#define RSPUSHFRAME(RC,OUT) { \\\n\tif( (RC)->fsp == SPINE_SIZE )  { \\\n\t\terror_top( _( \"Stack overflow.\" ) ); \\\n\t\terror_sub( _( \"Frame stack overflow, \" \\\n\t\t\t\"expression too complex.\" ) ); \\\n\t\treduce_throw( (RC) ); \\\n\t} \\\n\telse { \\\n\t\t(RC)->wbstack[(RC)->fsp] = *out; \\\n\t\t(RC)->fstack[(RC)->fsp] = (RC)->sp; \\\n\t\t(RC)->fsp++; \\\n\t} \\\n}\n\n#define RSPOPFRAME(RC) { \\\n\tif( (RC)->fsp == 0 ) { \\\n\t\terror_top( _( \"Stack underflow.\" ) ); \\\n\t\terror_sub( _( \"Frame stack underflow, you've found a bug!\" ) ); \\\n\t\treduce_throw( (RC) ); \\\n\t} \\\n\telse { \\\n\t\t(RC)->fsp--; \\\n\t\t(RC)->sp = (RC)->fstack[(RC)->fsp]; \\\n\t} \\\n}\n\n#define RSPOP(RC,N) { \\\n\tif( !RSCHECKARGS(RC,N) ) { \\\n\t\terror_top( _( \"Stack underflow.\" ) ); \\\n\t\terror_sub( _( \"Spine stack underflow, you've found a bug!\" ) ); \\\n\t\treduce_throw( (RC) ); \\\n\t} \\\n\telse \\\n\t\t(RC)->sp -= (N); \\\n}\n\n/* Pop this code before any calls to reduce_*() to init stuff and catch \n * errors. Arg is function return value. The missing running decrement is done\n * by throw().\n */\n#define REDUCE_CATCH_START( R ) \\\n{ \\\n\trc->sps[rc->running] = rc->sp; \\\n\trc->fsps[rc->running] = rc->fsp; \\\n\trc->tsp[rc->running] = trace_get_mark(); \\\n\tif( setjmp( rc->error[rc->running++] ) ) { \\\n\t\tg_assert( rc->running >= 0 ); \\\n\t\trc->sp = rc->sps[rc->running]; \\\n\t\trc->fsp = rc->fsps[rc->running]; \\\n\t\ttrace_pop_to( rc->tsp[rc->running] ); \\\n\t\treturn( (R) ); \\\n\t} \\\n}\n\n/* After any calls to reduce_*().\n */\n#define REDUCE_CATCH_STOP \\\n{ \\\n\trc->running -= 1; \\\n\tg_assert( rc->running >= 0 ); \\\n}\n\n/* Util.\n */\nvoid reduce_throw( Reduce *rc ) __attribute__((noreturn));\n\ntypedef void *(*reduce_safe_pointer_fn)( Reduce *rc, PElement *, \n\tvoid *, void *, void *, void * );\nvoid *reduce_safe_pointer( Reduce *rc, reduce_safe_pointer_fn fn, \n\tvoid *a, void *b, void *c, void *d );\n\nvoid reduce_get_list( Reduce *rc, PElement *list );\nvoid reduce_error_typecheck( Reduce *rc, \n\tPElement *e, const char *name, const char *type );\ntypedef void *(*reduce_map_list_fn)( Reduce *rc,\n\tPElement *, void *, void * );\nvoid *reduce_map_list( Reduce *rc, \n\tPElement *base, reduce_map_list_fn fn, void *a, void *b );\ntypedef void *(*reduce_map_dict_fn)( Reduce *, \n\tconst char *, PElement *, void *a, void *b );\nvoid *reduce_map_dict( Reduce *rc, \n\tPElement *base, reduce_map_dict_fn fn, void *a, void *b );\nvoid reduce_clone_list( Reduce *rc, PElement *base, PElement *out );\nint reduce_get_string( Reduce *rc, PElement *base, char *buf, int n );\nint reduce_get_lstring( Reduce *rc, PElement *base, GSList **labels );\ngboolean reduce_get_bool( Reduce *rc, PElement *base );\ndouble reduce_get_real( Reduce *rc, PElement *base );\nvoid reduce_get_class( Reduce *rc, PElement *base );\nImageinfo *reduce_get_image( Reduce *rc, PElement *base );\nint reduce_get_realvec( Reduce *rc, PElement *base, double *buf, int n );\nint reduce_get_imagevec( Reduce *rc, PElement *base, Imageinfo **buf, int n );\nint reduce_get_matrix( Reduce *rc, \n\tPElement *base, double *buf, int n, int *xsize, int *ysize );\nvoid reduce_get_matrix_size( Reduce *rc, \n\tPElement *base, int *xsize, int *ysize );\ngboolean reduce_is_elist( Reduce *rc, PElement *base );\ngboolean reduce_is_list( Reduce *rc, PElement *base );\ngboolean reduce_is_string( Reduce *rc, PElement *base );\ngboolean reduce_is_finitestring( Reduce *rc, PElement *base );\ngboolean reduce_is_realvec( Reduce *rc, PElement *base );\ngboolean reduce_is_imagevec( Reduce *rc, PElement *base );\ngboolean reduce_is_matrix( Reduce *rc, PElement *base );\ngboolean reduce_is_class( Reduce *rc, PElement *klass );\nint reduce_list_length( Reduce *rc, PElement *base );\nint reduce_list_length_max( Reduce *rc, PElement *base, int max_length );\nvoid reduce_list_index( Reduce *rc, PElement *base, int n, PElement *out );\ngboolean reduce_is_instanceof_exact( Reduce *rc, \n\tconst char *name, PElement *instance );\ngboolean reduce_is_instanceof( Reduce *rc, \n\tconst char *name, PElement *instance );\n\n/* Main.\n */\nextern Reduce *reduce_context;\nextern int reduce_total_recomputations;\n\nvoid reduce_destroy( Reduce *rc );\nReduce *reduce_new( void );\ngboolean reduce_regenerate( Expr *expr, PElement *out );\ngboolean reduce_regenerate_member( Expr *expr, PElement *ths, PElement *out );\n\nvoid reduce_spine( Reduce *rc, PElement *out );\nvoid reduce_spine_strict( Reduce *rc, PElement *out );\n\ngboolean reduce_pelement( Reduce *, ReduceFunction fn, PElement *out );\n\n/* Register and unregister values.\n */\nvoid reduce_register( Symbol *sym );\nvoid reduce_unregister( Symbol *sym );\n"
  },
  {
    "path": "src/regionview.c",
    "content": "/* run the displays for regions on images\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* Verbose.\n#define DEBUG\n */\n\n/* Just trace create/destroy.\n#define DEBUG_MAKE\n */\n\n/* Trace grab/ungrab\n#define DEBUG_GRAB\n */\n\n/* Define this to trace event propogation\n#define EVENT\n */\n\n/* See paint events.\n#define DEBUG_PAINT\n */\n\n/* Define this to make region drags default to no-update during drag/resize.\n#define NO_UPDATE\n */\n\n#include \"ip.h\"\n\ntypedef void *(*regionview_rect_fn)( Regionview *, Rect *, void * );\ntypedef void (*regionview_paint_fn)( Regionview * );\n\n/* Cursor shape for each resize type.\n */\niWindowShape regionview_cursors[REGIONVIEW_RESIZE_LAST] = {\n\tIWINDOW_SHAPE_EDIT,\t\t/* REGIONVIEW_RESIZE_NONE */\n\tIWINDOW_SHAPE_MOVE, \t\t/* REGIONVIEW_RESIZE_MOVE */\n\tIWINDOW_SHAPE_MOVE,\t\t/* REGIONVIEW_RESIZE_EDIT */\n\tIWINDOW_SHAPE_TOPLEFT,\t\t/* REGIONVIEW_RESIZE_TOPLEFT */\n\tIWINDOW_SHAPE_TOP,\t\t/* REGIONVIEW_RESIZE_TOP */\n\tIWINDOW_SHAPE_TOPRIGHT,\t\t/* REGIONVIEW_RESIZE_TOPRIGHT */\n\tIWINDOW_SHAPE_RIGHT,\t\t/* REGIONVIEW_RESIZE_RIGHT */\n\tIWINDOW_SHAPE_BOTTOMRIGHT,\t/* REGIONVIEW_RESIZE_BOTTOMRIGHT */\n\tIWINDOW_SHAPE_BOTTOM,\t\t/* REGIONVIEW_RESIZE_BOTTOM */\n\tIWINDOW_SHAPE_BOTTOMLEFT,\t/* REGIONVIEW_RESIZE_BOTTOMLEFT */\n\tIWINDOW_SHAPE_LEFT\t\t/* REGIONVIEW_RESIZE_LEFT */\n};\n\n/* Region border width, without shadows.\n */\nstatic const int regionview_border_width = 2;\n\n/* Space around text in label.\n */\nstatic const int regionview_label_border = 5;\n\n/* Length of crosshair bars.\n */\nstatic const int regionview_crosshair_length = 5;\n\n/* The center of the crosshair is also sensitive for arrows.\n */\nstatic const int regionview_crosshair_centre = 8;\n\n/* How close you need to get to switch the type.\n */\nstatic const int regionview_morph_threshold = 20;\n\nstatic ViewClass *parent_class = NULL;\n\n/* Just one popup for all regions.\n */\nstatic GtkWidget *regionview_popup_menu = NULL;\n\n/* Paint a rectangle. \n */\nvoid\nregionview_paint_rect( GdkDrawable *draw, GdkGC *gc, Rect *r )\n{\t\n\tgdk_draw_rectangle( draw, gc, FALSE, \n\t\tr->left, r->top, \n\t\tIM_MAX( 0, r->width - 1 ), IM_MAX( 0, r->height - 1 ) );\n}\n\n/* Paint a thick rectangle. \n */\nvoid\nregionview_paint_rect_thick( GdkDrawable *draw, GdkGC *gc, Rect *r, int n )\n{\n\tRect our_r;\n\tint i;\n\n\tour_r = *r;\n\tfor( i = 0; i < n; i++ ) {\n\t\tregionview_paint_rect( draw, gc, &our_r );\n\t\tim_rect_marginadjust( &our_r, 1 );\n\t}\n}\n\n/* Paint a rect in 3D --- pass a GC for the top-left and a gc for the\n * bottom-right shadows.\n */\nstatic void\nregionview_paint_rect_3d( GdkDrawable *draw, GdkGC *tl, GdkGC *br, Rect *r )\n{\n\t/* Bottom and right.\n\t */\n\tgdk_draw_line( draw, br, \n\t\tIM_RECT_RIGHT( r ) - 1, r->top, \n\t\tIM_RECT_RIGHT( r ) - 1, IM_RECT_BOTTOM( r ) - 1 );\n\tgdk_draw_line( draw, br, \n\t\tIM_RECT_RIGHT( r ) - 1, IM_RECT_BOTTOM( r ) - 1, \n\t\tr->left, IM_RECT_BOTTOM( r ) - 1 );\n\n\t/* Top and left.\n\t */\n\tgdk_draw_line( draw, tl, \n\t\tr->left, IM_RECT_BOTTOM( r ) - 1, r->left, r->top );\n\tgdk_draw_line( draw, tl, \n\t\tr->left, r->top, IM_RECT_RIGHT( r ) - 1, r->top );\n}\n\n/* Paint little ticks ... for marking the edges of the resize handles. \n */\nstatic void\nregionview_paint_vtick( GdkDrawable *draw, GdkGC *tl, GdkGC *br, \n\tint x, int y, int n )\n{\n\tgdk_draw_line( draw, br, x, y - 1, x, y - n );\n\tgdk_draw_line( draw, tl, x + 1, y - 1, x + 1, y - n );\n}\n\nstatic void\nregionview_paint_htick( GdkDrawable *draw, GdkGC *tl, GdkGC *br, \n\tint x, int y, int n )\n{\n\tgdk_draw_line( draw, br, x - 1, y, x - n, y );\n\tgdk_draw_line( draw, tl, x - 1, y + 1, x - n, y + 1 );\n}\n\n/* Paint a region border, enclosing the pixels in r.\n */\nstatic void\nregionview_paint_border( GdkDrawable *draw, GdkGC *tl, GdkGC *bg, GdkGC *br,\n\tRect *r, gboolean locked ) \n{\n\tint n = regionview_border_width;\n\tRect our_r = *r;\n\n\tim_rect_marginadjust( &our_r, 1 );\n\tregionview_paint_rect_3d( draw, br, tl, &our_r );\n\tim_rect_marginadjust( &our_r, 1 );\n\tregionview_paint_rect_thick( draw, bg, &our_r, n );\n\tim_rect_marginadjust( &our_r, n );\n\tregionview_paint_rect_3d( draw, tl, br, &our_r );\n\n\t/* Add little tick marks for corner resizing. Don't bother for very \n\t * small rects, or for locked rects.\n\t */\n\tif( !locked && r->width > 20 ) {\n\t\t/* Top edge.\n\t\t */\n\t\tregionview_paint_vtick( draw, tl, br, \n\t\t\tr->left + 10, r->top - 1, n );\n\t\tregionview_paint_vtick( draw, tl, br, \n\t\t\tIM_RECT_RIGHT( r ) - 11, r->top - 1, n );\n\n\t\t/* Bottom edge.\n\t\t */\n\t\tregionview_paint_vtick( draw, tl, br, \n\t\t\tr->left + 10, IM_RECT_BOTTOM( r ) + n + 1, n );\n\t\tregionview_paint_vtick( draw, tl, br, \n\t\t\tIM_RECT_RIGHT( r ) - 11, IM_RECT_BOTTOM( r ) + n + 1, \n\t\t\tn );\n\t}\n\n\tif( !locked && r->height > 20 ) {\n\t\t/* Left edge.\n\t\t */\n\t\tregionview_paint_htick( draw, tl, br, \n\t\t\tr->left - 1, r->top + 10, n );\n\t\tregionview_paint_htick( draw, tl, br, \n\t\t\tr->left - 1, IM_RECT_BOTTOM( r ) - 12, n );\n\n\t\t/* Right edge.\n\t\t */\n\t\tregionview_paint_htick( draw, tl, br, \n\t\t\tIM_RECT_RIGHT( r ) + n + 1, r->top + 10, n );\n\t\tregionview_paint_htick( draw, tl, br, \n\t\t\tIM_RECT_RIGHT( r ) + n + 1, IM_RECT_BOTTOM( r ) - 12, \n\t\t\tn );\n\t}\n}\n\n/* Paint a square area, with a beveled edge.\n */\nstatic void\nregionview_paint_area( GdkDrawable *draw, \n\tGdkGC *tl, GdkGC *bg, GdkGC *br,\n\tRect *r )\n{\n\tgdk_draw_rectangle( draw, bg, TRUE,\n\t\tr->left, r->top, r->width, r->height );\n\tregionview_paint_rect_3d( draw, tl, br, r );\n}\n\n/* Paint a region label.\n */\nstatic void\nregionview_paint_label( Regionview *regionview, GdkDrawable *draw, \n\tRect *r, int ascent, const char *txt )\n{\n\tGtkWidget *widget = GTK_WIDGET( regionview->ip->id );\n\tint n = regionview_label_border;\n\tPangoLayout *layout;\n\tGdkRectangle grect;\n\n\t/* Clip to this area ... don't want to paint outside label.\n\t */\n\tgrect.x = r->left;\n\tgrect.y = r->top;\n\tgrect.width = r->width;\n\tgrect.height = r->height;\n\tgtk_paint_flat_box( widget->style, draw, regionview->paint_state, \n\t\tGTK_SHADOW_OUT,\n\t\t&grect, widget, \"buttondefault\",\n\t\tgrect.x, grect.y, grect.width, grect.height );\n\n\t/* Paint text over the top.\n\t */\n\tlayout = gtk_widget_create_pango_layout( widget, txt );\n\tgtk_paint_layout( widget->style, draw, regionview->paint_state,\n\t\tFALSE,\n\t\t&grect, widget, NULL,\n\t\tr->left + n, r->top + n + ascent, layout );\n\tg_object_unref( layout );\n}\n\n/* Paint a crosshair, centered at x, y.\n */\nstatic void\nregionview_paint_crosshair( GdkDrawable *draw,\n        GdkGC *tl, GdkGC *bg, GdkGC *br,\n\tint x, int y )\n{\n\tconst int bw = regionview_border_width / 2 + 1;\n\tconst int l = regionview_crosshair_length + 2;\n\n\tRect area;\n\n\tarea.left = x - bw - 1 - l;\n\tarea.top = y - bw;\n\tarea.width = l;\n\tarea.height = bw * 2;\n\tregionview_paint_area( draw, tl, bg, br, &area );\n\n\tarea.left = x + bw + 1;\n\tregionview_paint_area( draw, tl, bg, br, &area );\n\n\tarea.left = x - bw;\n\tarea.top = y - bw - 1 - l;\n\tarea.width = bw * 2;\n\tarea.height = l;\n\tregionview_paint_area( draw, tl, bg, br, &area );\n\n\tarea.top = y + bw + 1;\n\tregionview_paint_area( draw, tl, bg, br, &area );\n}\n\n/* Paint the dotted line connecting an arrow or a guide.\n */\nstatic void\nregionview_paint_arrow( GdkDrawable *draw, GdkGC *fg, int off, Rect *r )\n{\n        static gint8 dash_list[] = { 10, 10 };\n\n        gdk_gc_set_dashes( fg, off, dash_list, 2 );\n\tgdk_gc_set_line_attributes( fg, 2, \n\t\tGDK_LINE_DOUBLE_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER );\n\tgdk_draw_line( draw, fg, \n\t\tr->left, r->top, IM_RECT_RIGHT( r ), IM_RECT_BOTTOM( r ) );\n\tgdk_gc_set_line_attributes( fg, 0, \n\t\tGDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );\n}\n\n/* Paint the dotted box for a text preview, or rectangle paint preview.\n */\nstatic void\nregionview_paint_box( GdkDrawable *draw, GdkGC *fg, int off, Rect *r )\n{\n        static gint8 dash_list[] = { 10, 10 };\n\n        gdk_gc_set_dashes( fg, off, dash_list, 2 );\n\tgdk_gc_set_line_attributes( fg, 2, \n\t\tGDK_LINE_DOUBLE_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER );\n\tgdk_draw_line( draw, fg, \n\t\tr->left, r->top, \n\t\tIM_RECT_RIGHT( r ), r->top );\n\tgdk_draw_line( draw, fg, \n\t\tIM_RECT_RIGHT( r ), r->top, \n\t\tIM_RECT_RIGHT( r ), IM_RECT_BOTTOM( r ) );\n\tgdk_draw_line( draw, fg, \n\t\tIM_RECT_RIGHT( r ), IM_RECT_BOTTOM( r ),\n\t\tr->left, IM_RECT_BOTTOM( r ) );\n\tgdk_draw_line( draw, fg, \n\t\tr->left, IM_RECT_BOTTOM( r ),\n\t\tr->left, r->top );\n\tgdk_gc_set_line_attributes( fg, 0, \n\t\tGDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER );\n}\n\n/* Apply a function to every rect in a crosshair positioned at (x, y).\n */\nstatic void *\nregionview_crosshair_foreach( Regionview *regionview, \n\tint x, int y, regionview_rect_fn fn, void *data )\n{\n\tconst int n = regionview_border_width + 2;\n\tconst int l = regionview_crosshair_length + 2;\n\n\tRect area;\n\tvoid *res;\n\n\tarea.left = x - n/2 - 1 - l;\n\tarea.top = y - n/2;\n\tarea.width = l;\n\tarea.height = n;\n\tif( (res = fn( regionview, &area, data )) )\n\t\treturn( res );\n\n\tarea.left = x + n/2 + 1;\n\tif( (res = fn( regionview, &area, data )) )\n\t\treturn( res );\n\n\tarea.left = x - n/2;\n\tarea.top = y - n/2 - 1 - l;\n\tarea.width = n;\n\tarea.height = l;\n\tif( (res = fn( regionview, &area, data )) )\n\t\treturn( res );\n\n\tarea.top = y + n/2 + 1;\n\tif( (res = fn( regionview, &area, data )) )\n\t\treturn( res );\n\n\treturn( NULL );\n}\n\n/* Apply a function to every rect in a region border positioned at border.\n */\nstatic void *\nregionview_border_foreach( Regionview *regionview, \n\tRect *border, regionview_rect_fn fn, void *data )\n{\n\tconst int n = regionview_border_width + 2;\n\n\tRect area;\n\tvoid *res;\n\n\tarea.left = border->left - n;\n\tarea.top = border->top - n;\n\tarea.width = border->width + 2*n;\n\tarea.height = n;\n\tif( (res = fn( regionview, &area, data )) )\n\t\treturn( res );\n\n\tarea.top = IM_RECT_BOTTOM( border );\n\tif( (res = fn( regionview, &area, data )) )\n\t\treturn( res );\n\n\tarea.left = border->left - n;\n\tarea.top = border->top;\n\tarea.width = n;\n\tarea.height = border->height;\n\tif( (res = fn( regionview, &area, data )) )\n\t\treturn( res );\n\n\tarea.left = IM_RECT_RIGHT( border );\n\tif( (res = fn( regionview, &area, data )) )\n\t\treturn( res );\n\n\treturn( NULL );\n}\n\n/* Repaint ... as a rect_foreach function.\n */\nstatic void *\nregionview_queue_draw_area( Regionview *regionview, Rect *area, void *dummy )\n{\n#ifdef DEBUG_PAINT\n\tprintf( \"regionview_queue_draw_area: at %dx%d size %dx%d\\n\",\n\t\tarea->left, area->top, area->width, area->height );\n#endif /*DEBUG_PAINT*/\n\n\timagedisplay_queue_draw_area( regionview->ip->id, area );\n\n\treturn( NULL );\n}\n\n/* Queue draws for all the pixels a region might touch.\n */\nstatic void\nregionview_queue_draw( Regionview *regionview )\n{\n\tImagedisplay *id = regionview->ip->id;\n\tConversion *conv = id->conv;\n\tRect *area = &regionview->area;\n\n\tRect dr;\n\tint x, y;\n\n\tswitch( regionview->last_type ) {\n\tcase REGIONVIEW_AREA:\n\tcase REGIONVIEW_REGION:\n\t\tconversion_im_to_disp_rect( conv, area, &dr );\n\t\t(void) regionview_border_foreach( regionview, &dr, \n\t\t\tregionview_queue_draw_area, NULL );\n\t\tbreak;\n\n\tcase REGIONVIEW_MARK:\n\t\tconversion_im_to_disp( conv, area->left, area->top, &x, &y );\n\t\t(void) regionview_crosshair_foreach( regionview, x, y, \n\t\t\tregionview_queue_draw_area, NULL );\n\t\tbreak;\n\n\tcase REGIONVIEW_ARROW:\n\t\tconversion_im_to_disp_rect( conv, area, &dr );\n\t\t(void) regionview_crosshair_foreach( regionview, \n\t\t\tdr.left, dr.top,\n\t\t\tregionview_queue_draw_area, NULL );\n\t\t(void) regionview_crosshair_foreach( regionview, \n\t\t\tIM_RECT_RIGHT( &dr ), \n\t\t\tIM_RECT_BOTTOM( &dr ),\n\t\t\tregionview_queue_draw_area, NULL );\n\n\t\tim_rect_normalise( &dr );\n\t\tim_rect_marginadjust( &dr, 2 );\n\t\tregionview_queue_draw_area( regionview, &dr, NULL );\n\n\t\tbreak;\n\n\tcase REGIONVIEW_HGUIDE:\n\tcase REGIONVIEW_VGUIDE:\n\tcase REGIONVIEW_LINE:\n\t\tconversion_im_to_disp_rect( conv, area, &dr );\n\t\tim_rect_normalise( &dr );\n\t\tim_rect_marginadjust( &dr, 2 );\n\t\tregionview_queue_draw_area( regionview, &dr, NULL );\n\t\tbreak;\n\n\tcase REGIONVIEW_BOX:\n\t\tconversion_im_to_disp_rect( conv, area, &dr );\n\t\tim_rect_normalise( &dr );\n\t\tim_rect_marginadjust( &dr, -2 );\n\t\t(void) regionview_border_foreach( regionview, &dr, \n\t\t\tregionview_queue_draw_area, NULL );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\tif( regionview->classmodel )\n\t\timagedisplay_queue_draw_area( id, &regionview->label );\n}\n\n/* Paint a region ... assume the screen has only the background visible (ie.\n * we've nothing of this region visible). Clip paints against clip rect (in\n * xev coordinates) ... either the expose area, or the imagedisplay area.\n */\nstatic void\nregionview_paint( Regionview *regionview )\n{\n\tImagepresent *ip = regionview->ip;\n\tImagedisplay *id = ip->id;\n\tConversion *conv = id->conv;\n\n\tGtkStyle *style = gtk_widget_get_style( GTK_WIDGET( id ) );\n\tGdkDrawable *draw = GTK_WIDGET( id )->window;\n\tint state = regionview->last_paint_state;\n\n\tGdkGC *tl, *br, *bg;\n\tRect dr;\n\n\ttl = style->light_gc[state];\n\tbr = style->dark_gc[state];\n\tbg = style->bg_gc[state];\n\n\tconversion_im_to_disp_rect( conv, &regionview->area, &dr );\n\tswitch( regionview->last_type ) {\n\tcase REGIONVIEW_REGION:\n\t\tregionview_paint_border( draw, tl, bg, br, &dr, FALSE );\n\t\tbreak;\n\n\tcase REGIONVIEW_AREA:\n\t\tregionview_paint_border( draw, tl, bg, br, &dr, TRUE );\n\t\tbreak;\n\n\tcase REGIONVIEW_MARK:\n\t\tregionview_paint_crosshair( draw, \n\t\t\ttl, bg, br, dr.left, dr.top );\n\t\tbreak;\n\n\tcase REGIONVIEW_ARROW:\n\t\tregionview_paint_arrow( draw, \n\t\t\ttl, regionview->dash_offset, &dr );\n\t\tregionview_paint_crosshair( draw, \n\t\t\ttl, bg, br, dr.left, dr.top );\n\t\tregionview_paint_crosshair( draw, tl, bg, br, \n\t\t\tIM_RECT_RIGHT( &dr ), IM_RECT_BOTTOM( &dr ) );\n\t\tbreak;\n\n\tcase REGIONVIEW_HGUIDE:\n\tcase REGIONVIEW_VGUIDE:\n\tcase REGIONVIEW_LINE:\n\t\tregionview_paint_arrow( draw, \n\t\t\ttl, regionview->dash_offset, &dr );\n\t\tbreak;\n\n\tcase REGIONVIEW_BOX:\n\t\tim_rect_normalise( &dr );\n\t\tregionview_paint_box( draw, \n\t\t\ttl, regionview->dash_offset, &dr );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\tif( regionview->classmodel ) \n\t\tregionview_paint_label( regionview, draw, \n\t\t\t&regionview->label, regionview->ascent,\n\t\t\tvips_buf_all( &regionview->caption ) );\n}\n\n/* Stop tracking.\n */\nstatic void\nregionview_detach( Regionview *regionview )\n{\n\tif( regionview->grabbed ) {\n\t\tg_assert( regionview->ip->grabbed == regionview );\n\n#ifdef DEBUG_GRAB\n\t\tprintf( \"regionview_detach: %p\\n\", regionview );\n#endif /*DEBUG_GRAB*/\n\n\t\tregionview->state = REGIONVIEW_WAIT;\n\t\tregionview->paint_state = GTK_STATE_PRELIGHT;\n\t\tregionview->grabbed = FALSE;\n\t\tregionview->ip->grabbed = NULL;\n\n\t\timagepresent_scroll_stop( regionview->ip );\n\t}\n}\n\nstatic void\nregionview_destroy( GtkObject *object )\n{\n\tRegionview *regionview;\n\tImagedisplay *id;\n\n#ifdef DEBUG_MAKE\n\tprintf( \"regionview_destroy: %p\\n\", object );\n#endif /*DEBUG_MAKE*/\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_REGIONVIEW( object ) );\n\n\tregionview = REGIONVIEW( object );\n\n\tif( !regionview->first ) \n\t\tregionview_queue_draw( regionview ); \n\tregionview->first = FALSE;\n\n\tregionview_detach( regionview );\n\n\tif( (id = regionview->ip->id) ) { \n\t\tFREESID( regionview->expose_sid, id ); \n\t\tFREESID( regionview->destroy_sid, id ); \n\t\tFREESID( regionview->event_sid, id ); \n\t\tFREESID( regionview->changed_sid, id->conv ); \n\t\tFREESID( regionview->conv_destroy_sid, id->conv ); \n\t}\n\n\tFREESID( regionview->model_changed_sid, regionview->classmodel ); \n\tIM_FREEF( g_source_remove, regionview->dash_crawl );\n\tIM_FREEF( iwindow_cursor_context_destroy, regionview->cntxt );\n\tvips_buf_destroy( &regionview->caption );\n\n\tif( regionview->ip ) {\n\t\tif( regionview->ip->regionview == regionview )\n\t\t\tregionview->ip->regionview = NULL;\n\n\t\tregionview->ip->regionviews = \n\t\t\tg_slist_remove( regionview->ip->regionviews, \n\t\t\tregionview );\n\n\t\tregionview->ip = NULL;\n\t}\n\n\tif( regionview->classmodel ) {\n\t\tregionview->classmodel->views = g_slist_remove( \n\t\t\tregionview->classmodel->views, regionview );\n\t\tregionview->classmodel = NULL;\n\t}\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\n/* Compute the label geometry.\n */\nstatic void\nregionview_label_geo( Regionview *regionview )\n{\n\tint n = regionview_label_border;\n\tconst char *str = vips_buf_all( &regionview->caption );\n\tint width, height;\n\tPangoLayout *layout;\n\n\tlayout = gtk_widget_create_pango_layout( \n\t\tGTK_WIDGET( regionview->ip->id ), str );\n\tpango_layout_get_pixel_size( layout, &width, &height );\n\tg_object_unref( layout );\n\n\tregionview->label.width = width + 2 * n;\n\tregionview->label.height = height + 2 * n;\n\tregionview->ascent = 0;\n}\n\nstatic void\nregionview_refresh_label( Regionview *regionview )\n{\n\tif( regionview->classmodel ) {\n\t\tRow *row = HEAPMODEL( regionview->classmodel )->row;\n\n\t\tvips_buf_rewind( &regionview->caption );\n\t\trow_qualified_name_relative( row->ws->sym, row, \n\t\t\t&regionview->caption );\n\t\tregionview_label_geo( regionview );\n\t}\n}\n\n/* Move label to try to keep it within the window, and away from the\n * selected pixels.\n */\nstatic void\nregionview_position_label( Regionview *regionview )\n{\n\tImagepresent *ip = regionview->ip;\n\tConversion *conv = ip->id->conv;\n\tRect *visible = &conv->visible;\n\tRect *label = &regionview->label;\n\tconst int b = regionview_border_width + 2;\n\n\tRect dr;\n\n\tif( regionview->label_geo ) {\n\t\tregionview_refresh_label( regionview );\n\t\tregionview->label_geo = FALSE;\n\t}\n\n\tconversion_im_to_disp_rect( conv, &regionview->area, &dr );\n\n\tswitch( regionview->type ) {\n\tcase REGIONVIEW_REGION:\n\tcase REGIONVIEW_AREA:\n\tcase REGIONVIEW_BOX:\n\t\tif( dr.top > visible->top + label->height + b ) {\n\t\t\t/* Space above region for label.\n\t\t\t */\n\t\t\tlabel->left = dr.left - b;\n\t\t\tlabel->top = dr.top - label->height - b;\n\t\t}\n\t\telse if( dr.left > visible->left + label->width + b ) {\n\t\t\t/* Space to left of region for label\n\t\t\t */\n\t\t\tlabel->left = dr.left - label->width - b;\n\t\t\tlabel->top = dr.top - b;\n\t\t}\n\t\telse if( IM_RECT_RIGHT( &dr ) < \n\t\t\tIM_RECT_RIGHT( visible ) - label->width - b ) {\n\t\t\t/* Space at right.\n\t\t\t */\n\t\t\tlabel->left = IM_RECT_RIGHT( &dr ) + b;\n\t\t\tlabel->top = dr.top - b;\n\t\t}\n\t\telse if( IM_RECT_BOTTOM( &dr ) < \n\t\t\tIM_RECT_BOTTOM( visible ) - label->height - b ) {\n\t\t\t/* Space at bottom.\n\t\t\t */\n\t\t\tlabel->left = dr.left - b;\n\t\t\tlabel->top = IM_RECT_BOTTOM( &dr ) + b;\n\t\t}\n\t\telse {\n\t\t\t/* Inside top left.\n\t\t\t */\n\t\t\tlabel->left = dr.left;\n\t\t\tlabel->top = dr.top;\n\t\t}\n\t\tbreak;\n\n\tcase REGIONVIEW_HGUIDE:\n\tcase REGIONVIEW_VGUIDE:\n\tcase REGIONVIEW_MARK:\n\tcase REGIONVIEW_ARROW:\n\tcase REGIONVIEW_LINE:\n\t\t/* Space above? \n\t\t */\n\t\tif( dr.top > visible->top + label->height + b/2 + 2 ) {\n\t\t\tif( dr.left > IM_RECT_RIGHT( visible ) - \n\t\t\t\tlabel->width - b/2 - 2 ) {\n\t\t\t\t/* Above left.\n\t\t\t\t */\n\t\t\t\tlabel->left = dr.left - b/2 - 2 - label->width;\n\t\t\t\tlabel->top = dr.top - b/2 - 2 - label->height;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t/* Above right.\n\t\t\t\t */\n\t\t\t\tlabel->left = dr.left + b/2 + 2;\n\t\t\t\tlabel->top = dr.top - b/2 - 2 - label->height;\n\t\t\t}\n\t\t}\n\t\telse if( dr.left > IM_RECT_RIGHT( visible ) -\n\t\t\tlabel->width - b/2 - 2 ) {\n\t\t\t/* Below left.\n\t\t\t */\n\t\t\tlabel->left = dr.left - b/2 - 2 - label->width;\n\t\t\tlabel->top = dr.top + b/2 + 2;\n\t\t}\n\t\telse {\n\t\t\t/* Below right.\n\t\t\t */\n\t\t\tlabel->left = dr.left + b/2 + 2;\n\t\t\tlabel->top = dr.top + b/2 + 2;\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n}\n\nstatic Rect *\nregionview_get_model( Regionview *regionview )\n{\n\tClassmodel *classmodel = regionview->classmodel;\n\tiRegionInstance *instance;\n\tRect *model_area;\n\n        /* If we have a class, update from the inside of that.\n         */\n        if( classmodel &&\n\t\t(instance = classmodel_get_instance( classmodel )) ) \n                model_area = &instance->area;\n        else\n                model_area = regionview->model_area;\n\n\treturn( model_area );\n}\n\n/* Update our_area from the model. Translate to our cods too: we always have\n * x/y in 0 to xsize/ysize.\n */\nstatic void\nregionview_update_from_model( Regionview *regionview )\n{\n\tRect *model_area = regionview_get_model( regionview );\n\n#ifdef DEBUG\n\tprintf( \"regionview_update_from_model: model is %dx%d size %dx%d\\n\",\n\t\tmodel_area->left, model_area->top, \n\t\tmodel_area->width, model_area->height );\n#endif /*DEBUG*/\n\n\tregionview->our_area = *model_area;\n\n#ifdef DEBUG\n\tprintf( \"regionview_update_from_model: set regionview to %dx%d size %dx%d\\n\",\n\t\tregionview->our_area.left, regionview->our_area.top, \n\t\tregionview->our_area.width, regionview->our_area.height );\n#endif /*DEBUG*/\n}\n\n/* Update the model from our_area.\n */\nstatic void\nregionview_model_update( Regionview *regionview )\n{\n\tClassmodel *classmodel = regionview->classmodel;\n\tRect *model_area = regionview_get_model( regionview );\n\n#ifdef DEBUG\n\tprintf( \"regionview_model_update: regionview is %dx%d size %dx%d\\n\",\n\t\tregionview->our_area.left, regionview->our_area.top, \n\t\tregionview->our_area.width, regionview->our_area.height );\n#endif /*DEBUG*/\n\n\t*model_area = regionview->our_area;\n\n\tif( classmodel ) {\n\t\tclassmodel_update( classmodel );\n\n\t\tif( CALC_RECOMP_REGION ) \n\t\t\tsymbol_recalculate_all();\n\t}\n\n\t/* Refresh immediately .. gives faster feedback during drag.\n\t */\n\tvobject_refresh( VOBJECT( regionview ) );\n\n#ifdef DEBUG\n\tprintf( \"regionview_model_update: set model to %dx%d size %dx%d\\n\",\n\t\tmodel_area->left, model_area->top, \n\t\tmodel_area->width, model_area->height );\n#endif /*DEBUG*/\n}\n\n/* Our model has changed ... undraw in the old position, draw in the new\n * position.\n */\nstatic void \nregionview_refresh( vObject *vobject )\n{\n\tRegionview *regionview = REGIONVIEW( vobject );\n\n#ifdef DEBUG\n\tprintf( \"regionview_refresh1: %dx%d size %dx%d\\n\",\n\t\tregionview->our_area.left, regionview->our_area.top, \n\t\tregionview->our_area.width, regionview->our_area.height );\n#endif /*DEBUG*/\n\n\t/* Update our_area from model.\n\t */\n\tregionview_update_from_model( regionview );\n\n#ifdef DEBUG\n\tprintf( \"regionview_refresh2: %dx%d size %dx%d\\n\",\n\t\tregionview->our_area.left, regionview->our_area.top, \n\t\tregionview->our_area.width, regionview->our_area.height );\n#endif /*DEBUG*/\n\n\tif( !regionview->first ) \n\t\tregionview_queue_draw( regionview ); \n\tregionview->first = FALSE;\n\n\t/* Set new position. \n\t */\n\tregionview->area = regionview->our_area;\n\tregionview->last_paint_state = regionview->paint_state;\n\tregionview->last_type = regionview->type;\n\n\t/* Choose a new label position.\n\t */\n\tregionview_position_label( regionview );\n\n\t/* Draw in the new place, clip against imagedisplay draw area.\n\t */\n\tregionview_queue_draw( regionview ); \n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\nregionview_edit_cb( GtkWidget *menu, Regionview *regionview, Imagepresent *ip )\n{\n\tmodel_edit( GTK_WIDGET( ip ), MODEL( regionview->classmodel ) );\n}\n\nstatic void\nregionview_clone_cb( GtkWidget *menu, Regionview *regionview, Imagepresent *ip )\n{\n\tRow *row = HEAPMODEL( regionview->classmodel )->row;\n\tWorkspace *ws = row->top_col->ws;\n\n\tif( row->top_row != row ) {\n\t\terror_top( _( \"Can't duplicate.\" ) );\n\t\terror_sub( \"%s\", \n\t\t\t_( \"You can only duplicate top level regions.\" ) );\n\t\tiwindow_alert( GTK_WIDGET( regionview->ip ), GTK_MESSAGE_INFO );\n\t\treturn;\n\t}\n\n        workspace_deselect_all( ws );\n        row_select( row );\n        if( !workspace_selected_duplicate( ws ) )\n\t\tiwindow_alert( GTK_WIDGET( regionview ), GTK_MESSAGE_ERROR );\n        workspace_deselect_all( ws );\n\n        symbol_recalculate_all();\n}\n\nstatic void\nregionview_clear_edited_cb( GtkWidget *menu, \n\tRegionview *regionview, Imagepresent *ip )\n{\n\t(void) icontainer_map_all( ICONTAINER( regionview->classmodel ),\n\t\t(icontainer_map_fn) model_clear_edited, NULL );\n        symbol_recalculate_all();\n}\n\nstatic void\nregionview_remove_yes( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tRegionview *regionview = REGIONVIEW( client );\n\tRow *row = HEAPMODEL( regionview->classmodel )->row;\n\n\tIDESTROY( row->sym );\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nregionview_remove_cb( GtkWidget *menu, \n\tRegionview *regionview, Imagepresent *ip )\n{\n\tRow *row = HEAPMODEL( regionview->classmodel )->row;\n\n\tif( row->top_row != row ) {\n\t\terror_top( _( \"Can't delete.\" ) );\n\t\terror_sub( _( \"You can only delete top level regions.\" ) );\n\t\tiwindow_alert( GTK_WIDGET( regionview->ip ), GTK_MESSAGE_INFO );\n\t\treturn;\n\t}\n\n\tbox_yesno( GTK_WIDGET( ip ),\n\t\tregionview_remove_yes, iwindow_true_cb, regionview,\n\t\tiwindow_notify_null, NULL,\n\t\tGTK_STOCK_DELETE, \n\t\t_( \"Delete Region?\" ),\n\t\t_( \"Are you sure you want to delete Region \\\"%s\\\"?\" ), \n\t\tvips_buf_all( &regionview->caption ) );\n}\n\nstatic void\nregionview_class_init( RegionviewClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\n\tGtkWidget *pane;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = regionview_destroy;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = regionview_refresh;\n\n        /* Other init.\n         */\n\tpane = regionview_popup_menu = popup_build( _( \"Region menu\" ) );\n\tpopup_add_but( pane, _( \"_Edit\" ), \n\t\tPOPUP_FUNC( regionview_edit_cb ) );\n\tpopup_add_but( pane, STOCK_DUPLICATE,\n\t\tPOPUP_FUNC( regionview_clone_cb ) );\n\tpopup_add_but( pane, _( \"_Reset\" ), \n\t\tPOPUP_FUNC( regionview_clear_edited_cb ) );\n\tmenu_add_sep( pane );\n\tpopup_add_but( pane, GTK_STOCK_DELETE,\n\t\tPOPUP_FUNC( regionview_remove_cb ) );\n}\n\nstatic void\nregionview_init( Regionview *regionview )\n{\n\tstatic Rect empty_rect = { -1, -1, -1, -1 };\n\n#ifdef DEBUG_MAKE\n\tprintf( \"regionview_init\\n\" );\n#endif /*DEBUG_MAKE*/\n\n\tregionview->type = REGIONVIEW_MARK;\n\tregionview->frozen = TRUE;\n\n\tregionview->state = REGIONVIEW_WAIT;\n\tregionview->resize = REGIONVIEW_RESIZE_NONE;\n\tregionview->dx = -1;\n\tregionview->dy = -1;\n\tregionview->grabbed = FALSE;\n\n\tregionview->classmodel = NULL;\n\tregionview->ip = NULL;\n\tregionview->cntxt = NULL;\n\tregionview->expose_sid = 0;\n\tregionview->destroy_sid = 0;\n\tregionview->event_sid = 0;\n\tregionview->changed_sid = 0;\n\tregionview->conv_destroy_sid = 0;\n\n\tregionview->model_area = NULL;\n\tregionview->paint_state = GTK_STATE_NORMAL;\n\n\tregionview->area = empty_rect;\n\tregionview->label = empty_rect;\n\tregionview->ascent = 0;\n\tregionview->dash_offset = 0;\n\tregionview->dash_crawl = 0;\n\tregionview->last_paint_state = (GtkStateType) -1;\n\tregionview->last_type = (RegionviewType) -1;\n\tregionview->first = TRUE;\n\tregionview->label_geo = TRUE;\n\n\tvips_buf_init_dynamic( &regionview->caption, REGIONVIEW_LABEL_MAX );\n\n\tgtk_widget_set_name( GTK_WIDGET( regionview ), \"regionview_widget\" );\n}\n\nGtkType\nregionview_get_type( void )\n{\n\tstatic GtkType regionview_type = 0;\n\n\tif( !regionview_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Regionview\",\n\t\t\tsizeof( Regionview ),\n\t\t\tsizeof( RegionviewClass ),\n\t\t\t(GtkClassInitFunc) regionview_class_init,\n\t\t\t(GtkObjectInitFunc) regionview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tregionview_type = gtk_type_unique( TYPE_VIEW, &info );\n\t}\n\n\treturn( regionview_type );\n}\n\n/* Test for rect touches rect (non-empty intersection).\n */\nstatic void *\nregionview_rect_touching( Regionview *regionview, Rect *a, Rect *b )\n{\n\tRect overlap;\n\n\tim_rect_intersectrect( a, b, &overlap );\n\n\tif( !im_rect_isempty( &overlap ) )\n\t\treturn( regionview );\n\telse\n\t\treturn( NULL );\n}\n\n/* Does expose rect touch the mark positioned at mark_x/mark_y. Include a big\n * grab handle in the centre of the crosshair.\n */\nstatic gboolean \nregionview_rect_touches_mark( Regionview *regionview, \n\tint mark_x, int mark_y, Rect *expose )\n{\n\tConversion *conv = regionview->ip->id->conv;\n\n\tRect tiny;\n\tint x, y;\n\n\tconversion_im_to_disp( conv, mark_x, mark_y, &x, &y ); \n\tif( regionview_crosshair_foreach( regionview, x, y, \n\t\t(regionview_rect_fn) regionview_rect_touching, expose ) )\n\t\treturn( TRUE );\n\n\t/* ... and the centre of the crosshairs.\n\t */\n\ttiny.left = x;\n\ttiny.top = y;\n\ttiny.width = 1;\n\ttiny.height = 1;\n\tim_rect_marginadjust( &tiny, regionview_crosshair_centre );\n\tif( regionview_rect_touching( regionview, &tiny, expose ) ) \n\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\n/* Test for rect intersects some part of region.\n */\nstatic gboolean\nregionview_rect_touches_region( Regionview *regionview, Rect *expose )\n{\n\tConversion *conv = regionview->ip->id->conv;\n\n\tRect canvas_area;\n\n\tif( regionview->classmodel && regionview_rect_touching( regionview, \n\t\t&regionview->label, expose ) )\n\t\treturn( TRUE );\n\n\tswitch( regionview->type ) {\n\tcase REGIONVIEW_REGION:\n\tcase REGIONVIEW_AREA:\n\tcase REGIONVIEW_BOX:\n\tcase REGIONVIEW_LINE:\n\t\tconversion_im_to_disp_rect( conv, \n\t\t\t&regionview->area, &canvas_area );\n\t\tim_rect_normalise( &canvas_area );\n\t\tif( regionview_border_foreach( regionview, &canvas_area, \n\t\t\t(regionview_rect_fn) regionview_rect_touching, \n\t\t\texpose ) )\n\t\t\treturn( TRUE );\n\t\tbreak;\n\n\tcase REGIONVIEW_MARK:\n\t\tif( regionview_rect_touches_mark( regionview,\n\t\t\tregionview->area.left, regionview->area.top, \n\t\t\texpose ) )\n\t\t\treturn( TRUE );\n\n\t\tbreak;\n\n\tcase REGIONVIEW_ARROW:\n\t\t/* Test two marks first.\n\t\t */\n\t\tif( regionview_rect_touches_mark( regionview,\n\t\t\tregionview->area.left, regionview->area.top, \n\t\t\texpose ) )\n\t\t\treturn( TRUE );\n\t\tif( regionview_rect_touches_mark( regionview,\n\t\t\tIM_RECT_RIGHT( &regionview->area ), \n\t\t\tIM_RECT_BOTTOM( &regionview->area ),\n\t\t\texpose ) )\n\t\t\treturn( TRUE );\n\n\t\t/* Spot in main area too ... for the dotted line. Also avoid\n\t\t * zero-width/height areas for h and v lines.\n\t\t */\n\t\tconversion_im_to_disp_rect( conv, \n\t\t\t&regionview->area, &canvas_area );\n\t\tim_rect_normalise( &canvas_area );\n\t\tim_rect_marginadjust( &canvas_area, 1 );\n\t\tif( regionview_rect_touching( regionview, \n\t\t\t&canvas_area, expose ) )\n\t\t\treturn( TRUE );\n\n\t\tbreak;\n\n\tcase REGIONVIEW_HGUIDE:\n\tcase REGIONVIEW_VGUIDE:\n\t\tconversion_im_to_disp_rect( conv, \n\t\t\t&regionview->area, &canvas_area );\n\t\tim_rect_marginadjust( &canvas_area, 5 );\n\n\t\tif( regionview_rect_touching( regionview, \n\t\t\t&canvas_area, expose ) )\n\t\t\treturn( TRUE );\n\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( FALSE );\n}\n\n/* From the expose event.\n */\nstatic void\nregionview_expose( Regionview *regionview, Rect *expose )\n{\n#ifdef DEBUG_PAINT\n\tprintf( \"regionview_expose: at %dx%d size %dx%d\\n\",\n\t\texpose->left, expose->top, expose->width, expose->height );\n#endif /*DEBUG_PAINT*/\n\n\tg_assert( expose->width >= 0 && expose->height >= 0 );\n\n\t/* If we've not finished init, don't paint.\n\t */\n\tif( regionview->first )\n\t\treturn;\n\n\t/* If the expose doesn't touch the region, don't bother painting.\n\t */\n\tif( !regionview_rect_touches_region( regionview, expose ) )\n\t\treturn;\n\n\tregionview_paint( regionview );\n}\n\nstatic void\nregionview_model_changed_cb( Classmodel *classmodel, Regionview *regionview )\n{\n\tvobject_refresh_queue( VOBJECT( regionview ) );\n}\n\nstatic gboolean\nregionview_expose_cb( Imagedisplay *id, GdkEventExpose *event,\n\tRegionview *regionview )\n{\n\tRect expose;\n\n\texpose.left = event->area.x;\n\texpose.top = event->area.y;\n\texpose.width = event->area.width;\n\texpose.height = event->area.height;\n\n\tregionview_expose( regionview, &expose );\n\n\treturn( FALSE );\n}\n\n/* Test for point is in the grab area of a region border or label.\n */\nstatic gboolean\nregionview_point_in_region( Regionview *regionview, int x, int y )\n{\n\tRect r;\n\n\tr.left = x;\n\tr.top = y;\n\tr.width = 1;\n\tr.height = 1;\n\treturn( regionview_rect_touches_region( regionview, &r ) );\n}\n\n/* Given a position, find the sort of resize we should allow.\n */\nstatic RegionviewResize\nregionview_find_resize( Regionview *regionview, int x, int y )\n{\n\tConversion *conv = regionview->ip->id->conv;\n\n\tRect canvas_area, tiny;\n\tint dx, dy; \n\n\tif( im_rect_includespoint( &regionview->label, x, y ) )\n\t\treturn( REGIONVIEW_RESIZE_EDIT );\n\n\tconversion_im_to_disp_rect( conv, &regionview->area, &canvas_area );\n\tdx = x - canvas_area.left;\n\tdy = y - canvas_area.top;\n\n\tswitch( regionview->type ) {\n\tcase REGIONVIEW_REGION:\n\t\tif( dx > canvas_area.width - 10 ) {\n\t\t\tif( dy > canvas_area.height - 10 )\n\t\t\t\treturn( REGIONVIEW_RESIZE_BOTTOMRIGHT );\n\t\t\telse if( dy < 10 )\n\t\t\t\treturn( REGIONVIEW_RESIZE_TOPRIGHT );\n\t\t\telse \n\t\t\t\treturn( REGIONVIEW_RESIZE_RIGHT );\n\t\t}\n\t\telse if( dx < 10 ) {\n\t\t\tif( dy > canvas_area.height - 10 )\n\t\t\t\treturn( REGIONVIEW_RESIZE_BOTTOMLEFT );\n\t\t\telse if( dy < 10 )\n\t\t\t\treturn( REGIONVIEW_RESIZE_TOPLEFT );\n\t\t\telse \n\t\t\t\treturn( REGIONVIEW_RESIZE_LEFT );\n\t\t}\n\t\telse {\n\t\t\tif( dy < canvas_area.height / 2 )\n\t\t\t\treturn( REGIONVIEW_RESIZE_TOP );\n\t\t\telse\n\t\t\t\treturn( REGIONVIEW_RESIZE_BOTTOM );\n\t\t}\n\t\tbreak;\n\n\tcase REGIONVIEW_MARK:\n\tcase REGIONVIEW_AREA:\n\t\treturn( REGIONVIEW_RESIZE_MOVE );\n\n\tcase REGIONVIEW_ARROW:\n\t\ttiny.left = x;\n\t\ttiny.top = y;\n\t\ttiny.width = 1;\n\t\ttiny.height = 1;\n\t\tif( regionview_crosshair_foreach( regionview,\n\t\t\tcanvas_area.left, canvas_area.top,\n\t\t\t(regionview_rect_fn) regionview_rect_touching, &tiny ) )\n\t\t\treturn( REGIONVIEW_RESIZE_TOPLEFT );\n\t\tif( regionview_crosshair_foreach( regionview,\n\t\t\tIM_RECT_RIGHT( &canvas_area ), \n\t\t\tIM_RECT_BOTTOM( &canvas_area ),\n\t\t\t(regionview_rect_fn) regionview_rect_touching, &tiny ) )\n\t\t\treturn( REGIONVIEW_RESIZE_BOTTOMRIGHT );\n\n\t\t/* Extra tests ... allow grabs in the centre of the crosshairs\n\t\t * too.\n\t\t */\n\t\ttiny.left = IM_RECT_RIGHT( &canvas_area );\n\t\ttiny.top = IM_RECT_BOTTOM( &canvas_area );\n\t\ttiny.width = 1;\n\t\ttiny.height = 1;\n\t\tim_rect_marginadjust( &tiny, regionview_crosshair_centre );\n\t\tif( im_rect_includespoint( &tiny, x, y ) )\n\t\t\treturn( REGIONVIEW_RESIZE_BOTTOMRIGHT );\n\n\t\ttiny.left = canvas_area.left;\n\t\ttiny.top = canvas_area.top;\n\t\ttiny.width = 1;\n\t\ttiny.height = 1;\n\t\tim_rect_marginadjust( &tiny, regionview_crosshair_centre );\n\t\tif( im_rect_includespoint( &tiny, x, y ) )\n\t\t\treturn( REGIONVIEW_RESIZE_TOPLEFT );\n\n\t\tbreak;\n\n\tcase REGIONVIEW_VGUIDE:\n\tcase REGIONVIEW_HGUIDE:\n\t\tim_rect_marginadjust( &canvas_area, 5 );\n\t\tif( im_rect_includespoint( &canvas_area, x, y ) )\n\t\t\treturn( REGIONVIEW_RESIZE_MOVE );\n\n\t\tbreak;\n\n\tcase REGIONVIEW_BOX:\n\tcase REGIONVIEW_LINE:\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( REGIONVIEW_RESIZE_NONE );\n}\n\n/* Right button press event.\n */\nstatic gint\nregionview_right_press( Regionview *regionview, GdkEvent *ev, int x, int y )\n{\n\tif( im_rect_includespoint( &regionview->label, x, y ) ) {\n\t\tpopup_show( GTK_WIDGET( regionview ), ev );\n\n\t\treturn( TRUE );\n\t}\n\n\treturn( FALSE );\n}\n\n/* Get ready to track this region. See imagepresent.c.\n */\nvoid\nregionview_attach( Regionview *regionview, int x, int y )\n{\n\tImagepresent *ip = regionview->ip;\n\tConversion *conv = ip->id->conv;\n\tint dx, dy;\n\n\tg_assert( !regionview->grabbed );\n\tg_assert( !regionview->ip->grabbed );\n\n#ifdef DEBUG_GRAB\n\tprintf( \"regionview_attach: %p\\n\", regionview );\n#endif /*DEBUG_GRAB*/\n\n\tswitch( regionview->resize ) {\n\tcase REGIONVIEW_RESIZE_NONE:\n\t\tregionview->resize = REGIONVIEW_RESIZE_BOTTOMRIGHT;\n\t\tregionview->state = REGIONVIEW_RESIZE;\n\t\tbreak;\n\n\tcase REGIONVIEW_RESIZE_MOVE:\n\tcase REGIONVIEW_RESIZE_EDIT:\n\t\tregionview->state = REGIONVIEW_MOVE;\n\t\tbreak;\n\n\tdefault:\n\t\tregionview->state = REGIONVIEW_RESIZE;\n\t\tbreak;\n\t}\n\n\tregionview->paint_state = GTK_STATE_ACTIVE;\n\n\tiwindow_cursor_context_set_cursor( regionview->cntxt, \n\t\tregionview_cursors[regionview->resize] );\n\n\tregionview->grabbed = TRUE;\n\tregionview->ip->grabbed = regionview;\n\n\tconversion_im_to_disp( conv, \n\t\tregionview->our_area.left, regionview->our_area.top, &dx, &dy );\n\tregionview->dx = dx - x;\n\tregionview->dy = dy - y;\n}\n\n/* Left button press event.\n */\nstatic gint\nregionview_left_press( Regionview *regionview, GdkEvent *ev, int x, int y )\n{\n\tgboolean handled = FALSE;\n\n\tif( !regionview_point_in_region( regionview, x, y ) ) \n\t\treturn( FALSE );\n\n\tswitch( regionview->state ) {\n\tcase REGIONVIEW_WAIT:\n\t\tregionview->resize = regionview_find_resize( regionview, x, y );\n\n\t\tif( regionview->resize != REGIONVIEW_RESIZE_NONE ) {\n\t\t\tregionview_attach( regionview, x, y );\n\t\t\thandled = TRUE;\n\t\t}\n\n\t\tbreak;\n\n\tcase REGIONVIEW_MOVE:\n\tcase REGIONVIEW_RESIZE:\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( handled );\n}\n\n/* Left button release event.\n */\nstatic gint\nregionview_left_release( Regionview *regionview, GdkEvent *ev )\n{\n\tswitch( regionview->state ) {\n\tcase REGIONVIEW_WAIT:\n\t\tbreak;\n\n\tcase REGIONVIEW_MOVE:\n\tcase REGIONVIEW_RESIZE:\n\t\tregionview_detach( regionview );\n\n\t\tif( !CALC_RECOMP_REGION )\n\t\t\tsymbol_recalculate_all();\n\n\t\tbreak;\n\t}\n\n\treturn( FALSE );\n}\n\nstatic void\nregionview_resize_area( Regionview *regionview, int ix, int iy )\n{\n\tImagepresent *ip = regionview->ip;\n\tConversion *conv = ip->id->conv;\n\tIMAGE *im = imageinfo_get( FALSE, conv->ii );\n\tRect *our_area = &regionview->our_area;\n\tint th = regionview_morph_threshold / conversion_dmag( conv->mag );\n\n\tint bot = our_area->top + our_area->height;\n\tint ri = our_area->left + our_area->width;\n\tint rx = ix - our_area->left;\n\tint ry = iy - our_area->top;\n\n\t/* If we're not frozen, do an unconstrained resize.\n\t */\n\tif( !regionview->frozen ) {\n\t\tswitch( regionview->resize ) {\n\t\tcase REGIONVIEW_RESIZE_RIGHT:\n\t\t\tour_area->width = IM_CLIP( -our_area->left,\n\t\t\t\trx, im->Xsize - our_area->left );\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_RESIZE_BOTTOM:\n\t\t\tour_area->height = IM_CLIP( -our_area->top, \n\t\t\t\try, im->Ysize - our_area->top );\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_RESIZE_MOVE:\n\t\t\t/* Get this for POINT on create ... treat as \n\t\t\t * BOTTOMRIGHT.\n\t\t\t */\n\t\tcase REGIONVIEW_RESIZE_BOTTOMRIGHT:\n\t\t\tour_area->width = IM_CLIP( -our_area->left,\n\t\t\t\trx, im->Xsize - our_area->left );\n\t\t\tour_area->height = IM_CLIP( -our_area->top, \n\t\t\t\try, im->Ysize - our_area->top );\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_RESIZE_LEFT:\n\t\t\tour_area->left = IM_CLIP( 0, ix, im->Xsize - 1 );\n\t\t\tour_area->width = ri - our_area->left;\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_RESIZE_TOP:\n\t\t\tour_area->top = IM_CLIP( 0, iy, im->Ysize - 1 );\n\t\t\tour_area->height = bot - our_area->top;\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_RESIZE_TOPLEFT:\n\t\t\tour_area->top = IM_CLIP( 0, iy, im->Ysize - 1 );\n\t\t\tour_area->left = IM_CLIP( 0, ix, im->Xsize - 1 );\n\t\t\tour_area->width = ri - our_area->left;\n\t\t\tour_area->height = bot - our_area->top;\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_RESIZE_TOPRIGHT:\n\t\t\tour_area->top = IM_CLIP( 0, iy, im->Ysize - 1 );\n\t\t\tour_area->height = bot - our_area->top;\n\t\t\tour_area->width = IM_CLIP( -our_area->left,\n\t\t\t\trx, im->Xsize - our_area->left );\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_RESIZE_BOTTOMLEFT:\n\t\t\tour_area->left = IM_CLIP( 0, ix, im->Xsize - 1 );\n\t\t\tour_area->width = ri - our_area->left;\n\t\t\tour_area->height = IM_CLIP( -our_area->top, \n\t\t\t\try, im->Ysize - our_area->top );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tg_assert( FALSE );\n\t\t}\n\n\t\tif( abs( our_area->width ) < th && \n\t\t\tabs( our_area->height - im->Ysize ) < th )\n\t\t\tregionview->type = REGIONVIEW_VGUIDE;\n\t\telse if( abs( our_area->height ) < th && \n\t\t\tabs( our_area->width - im->Xsize ) < th ) \n\t\t\tregionview->type = REGIONVIEW_HGUIDE;\n\t\telse if( abs( our_area->width ) < th && \n\t\t\tabs( our_area->height ) < th ) \n\t\t\tregionview->type = REGIONVIEW_MARK;\n\t\telse if( our_area->width > 0 && \n\t\t\tour_area->height > 0 ) \n\t\t\tregionview->type = REGIONVIEW_REGION;\n\t\telse\n\t\t\tregionview->type = REGIONVIEW_ARROW;\n\t}\n\telse {\n\t\t/* We're frozen ... resize should be tightly constrained.\n\t\t */\n\t\tswitch( regionview->type ) {\n\t\tcase REGIONVIEW_REGION:\n\t\t\tswitch( regionview->resize ) {\n\t\t\tcase REGIONVIEW_RESIZE_RIGHT:\n\t\t\t\tour_area->width = IM_CLIP( 1, rx, \n\t\t\t\t\tim->Xsize - our_area->left );\n\t\t\t\tbreak;\n\n\t\t\tcase REGIONVIEW_RESIZE_BOTTOM:\n\t\t\t\tour_area->height = IM_CLIP( 1, ry, \n\t\t\t\t\tim->Ysize - our_area->top );\n\t\t\t\tbreak;\n\n\t\t\tcase REGIONVIEW_RESIZE_BOTTOMRIGHT:\n\t\t\t\tour_area->width = IM_CLIP( 1, rx, \n\t\t\t\t\tim->Xsize - our_area->left );\n\t\t\t\tour_area->height = IM_CLIP( 1, ry, \n\t\t\t\t\tim->Ysize - our_area->top );\n\t\t\t\tbreak;\n\n\t\t\tcase REGIONVIEW_RESIZE_TOP:\n\t\t\t\tour_area->top = IM_CLIP( 0, iy, bot - 1 );\n\t\t\t\tour_area->height = bot - our_area->top;\n\t\t\t\tbreak;\n\n\t\t\tcase REGIONVIEW_RESIZE_LEFT:\n\t\t\t\tour_area->left = IM_CLIP( 0, ix, ri - 1 );\n\t\t\t\tour_area->width = ri - our_area->left;\n\t\t\t\tbreak;\n\n\t\t\tcase REGIONVIEW_RESIZE_TOPLEFT:\n\t\t\t\tour_area->left = IM_CLIP( 0, ix, ri - 1 );\n\t\t\t\tour_area->width = ri - our_area->left;\n\t\t\t\tour_area->top = IM_CLIP( 0, iy, bot - 1 );\n\t\t\t\tour_area->height = bot - our_area->top;\n\t\t\t\tbreak;\n\n\t\t\tcase REGIONVIEW_RESIZE_TOPRIGHT:\n\t\t\t\tour_area->top = IM_CLIP( 0, iy, bot - 1 );\n\t\t\t\tour_area->height = bot - our_area->top;\n\t\t\t\tour_area->width = IM_CLIP( 1, rx, \n\t\t\t\t\tim->Xsize - our_area->left );\n\t\t\t\tbreak;\n\n\t\t\tcase REGIONVIEW_RESIZE_BOTTOMLEFT:\n\t\t\t\tour_area->left = IM_CLIP( 0, ix, ri - 1 );\n\t\t\t\tour_area->width = ri - our_area->left;\n\t\t\t\tour_area->height = IM_CLIP( 1, ry, \n\t\t\t\t\tim->Ysize - our_area->top );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tg_assert( FALSE );\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_ARROW:\n\t\tcase REGIONVIEW_LINE:\n\t\tcase REGIONVIEW_BOX:\n\t\t\tswitch( regionview->resize ) {\n\t\t\tcase REGIONVIEW_RESIZE_TOPLEFT:\n\t\t\t\tour_area->left = IM_CLIP( 0, ix, im->Xsize );\n\t\t\t\tour_area->width = ri - our_area->left;\n\t\t\t\tour_area->top = IM_CLIP( 0, iy, im->Ysize );\n\t\t\t\tour_area->height = bot - our_area->top;\n\t\t\t\tbreak;\n\n\t\t\tcase REGIONVIEW_RESIZE_BOTTOMRIGHT:\n\t\t\t\tour_area->width = \n\t\t\t\t\tIM_CLIP( -our_area->left, rx, \n\t\t\t\t\t\tim->Xsize - our_area->left );\n\t\t\t\tour_area->height = \n\t\t\t\t\tIM_CLIP( -our_area->top, ry, \n\t\t\t\t\t\tim->Ysize - our_area->top );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tg_assert( FALSE );\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_MARK:\n\t\t\tour_area->left = IM_CLIP( 0, ix, im->Xsize - 1 );\n\t\t\tour_area->top = IM_CLIP( 0, iy, im->Ysize - 1 );\n\t\t\tour_area->width = 0;\n\t\t\tour_area->height = 0;\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_HGUIDE:\n\t\t\tour_area->top = IM_CLIP( 0, iy, im->Ysize - 1 );\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_VGUIDE:\n\t\t\tour_area->left = IM_CLIP( 0, ix, im->Xsize - 1 );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tg_assert( FALSE );\n\t\t}\n\t}\n}\n\n/* Change the state.\n */\nstatic void\nregionview_set_paint_state( Regionview *regionview, GtkStateType paint_state )\n{\n\tif( regionview->paint_state != paint_state ) {\n\t\tregionview->paint_state = paint_state;\n\t\tvobject_refresh_queue( VOBJECT( regionview ) );\n\t}\n}\n\n/* A motion event while we're grabbed.\n */\nstatic void\nregionview_motion_grab( Regionview *regionview, int x, int y )\n{\n\tImagepresent *ip = regionview->ip;\n\tImagemodel *imagemodel = ip->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tRect *visible = &imagemodel->visible;\n\tRect *our_area = &regionview->our_area;\n\tRect snap;\n\n\tIMAGE *im;\n\tint ix, iy;\n\n#ifdef DEBUG\n\tprintf( \"regionview_motion_grab:\\n\" );\n\tprintf( \"cods: %dx%d size %dx%d\\n\",\n\t\tour_area->left, our_area->top, \n\t\tour_area->width, our_area->height );\n#endif /*DEBUG*/\n\n\tswitch( regionview->state ) {\n\tcase REGIONVIEW_MOVE:\n\t\tconversion_disp_to_im( conv, \n\t\t\tx + regionview->dx, y + regionview->dy, &ix, &iy );\n\t\tim = imageinfo_get( FALSE, conv->ii );\n\n\t\tswitch( regionview->type ) {\n\t\tcase REGIONVIEW_REGION:\n\t\tcase REGIONVIEW_AREA:\n\t\t\tour_area->left = IM_CLIP( 0, ix, \n\t\t\t\tim->Xsize - our_area->width );\n\t\t\tour_area->top = IM_CLIP( 0, iy, \n\t\t\t\tim->Ysize - our_area->height );\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_ARROW:\n\t\t\tour_area->left = IM_CLIP( \n\t\t\t\tIM_MAX( 0, -our_area->width ), \n\t\t\t\tix, \n\t\t\t\tIM_MIN( im->Xsize - 1, \n\t\t\t\t\tim->Xsize - our_area->width ) );\n\t\t\tour_area->top = IM_CLIP( \n\t\t\t\tIM_MAX( 0, -our_area->height ), \n\t\t\t\tiy, \n\t\t\t\tIM_MIN( im->Ysize - 1, \n\t\t\t\t\tim->Ysize - our_area->height ) );\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_MARK:\n\t\tcase REGIONVIEW_HGUIDE:\n\t\tcase REGIONVIEW_VGUIDE:\n\t\t\tour_area->left = IM_CLIP( 0, ix, \n\t\t\t\tim->Xsize - our_area->width - 1 );\n\t\t\tour_area->top = IM_CLIP( 0, iy, \n\t\t\t\tim->Ysize - our_area->height - 1 );\n\t\t\tbreak;\n\n\t\tcase REGIONVIEW_LINE:\n\t\tcase REGIONVIEW_BOX:\n\t\t\tour_area->left = ix; \n\t\t\tour_area->top = iy;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tg_assert( FALSE );\n\t\t}\n\n\t\tsnap = *our_area;\n\t\tconversion_im_to_disp_rect( conv, &snap, &snap );\n\t\tif( imagepresent_snap_rect( ip, &snap, &snap ) ) {\n\t\t\tconversion_disp_to_im_rect( conv, &snap, &snap );\n\t\t\tour_area->left = snap.left;\n\t\t\tour_area->top = snap.top;\n\t\t}\n\n\t\tregionview_model_update( regionview );\n\n\t\tbreak;\n\n\tcase REGIONVIEW_RESIZE:\n\t\timagepresent_snap_point( ip, x, y, &x, &y );\n\t\tconversion_disp_to_im( conv, x, y, &ix, &iy );\n\t\tregionview_resize_area( regionview, ix, iy );\n\n\t\tregionview_model_update( regionview );\n\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\tif( !im_rect_includespoint( visible, x, y ) ) {\n\t\tint u, v;\n\n\t\tif( x < visible->left )\n\t\t\tu = -8;\n\t\telse if( x > IM_RECT_RIGHT( visible ) )\n\t\t\tu = 8;\n\t\telse\n\t\t\tu = 0;\n\t\tif( y < visible->top )\n\t\t\tv = -8;\n\t\telse if( y > IM_RECT_BOTTOM( visible ) )\n\t\t\tv = 8;\n\t\telse\n\t\t\tv = 0;\n\n\t\timagepresent_scroll_start( regionview->ip, u, v );\n\t}\n\telse\n\t\timagepresent_scroll_stop( regionview->ip );\n}\n\n#ifdef EVENT\nstatic char *\nresize_to_str( RegionviewResize resize )\n{\n\tswitch( resize ) { \n\tcase REGIONVIEW_RESIZE_NONE:\t\n\t\treturn( \"REGIONVIEW_RESIZE_NONE\" );\n\tcase REGIONVIEW_RESIZE_MOVE:\t\n\t\treturn( \"REGIONVIEW_RESIZE_MOVE\" ); \n\tcase REGIONVIEW_RESIZE_EDIT:\t\n\t\treturn( \"REGIONVIEW_RESIZE_EDIT\" ); \n\tcase REGIONVIEW_RESIZE_TOPLEFT:\t\n\t\treturn( \"REGIONVIEW_RESIZE_TOPLEFT\" ); \n\tcase REGIONVIEW_RESIZE_TOP:\t\n\t\treturn( \"REGIONVIEW_RESIZE_TOP\" ); \n\tcase REGIONVIEW_RESIZE_TOPRIGHT:\t\n\t\treturn( \"REGIONVIEW_RESIZE_TOPRIGHT\" ); \n\tcase REGIONVIEW_RESIZE_RIGHT:\t\n\t\treturn( \"REGIONVIEW_RESIZE_RIGHT\" ); \n\tcase REGIONVIEW_RESIZE_BOTTOMRIGHT:\t\n\t\treturn( \"REGIONVIEW_RESIZE_BOTTOMRIGHT\" ); \n\tcase REGIONVIEW_RESIZE_BOTTOM:\t\n\t\treturn( \"REGIONVIEW_RESIZE_BOTTOM\" ); \n\tcase REGIONVIEW_RESIZE_BOTTOMLEFT:\t\n\t\treturn( \"REGIONVIEW_RESIZE_BOTTOMLEFT\" ); \n\tcase REGIONVIEW_RESIZE_LEFT:\t\n\t\treturn( \"REGIONVIEW_RESIZE_LEFT\" ); \n\tcase REGIONVIEW_RESIZE_LAST:\t\n\t\treturn( \"REGIONVIEW_RESIZE_LAST\" );\n\n\tdefault:\n\t\tg_assert( 0 );\n\t}\n}\n#endif /*EVENT*/\n\n/* Motion event.\n */\nstatic gint\nregionview_motion( Regionview *regionview, GdkEvent *ev, int x, int y )\n{\n\tGdkWindow *win = GTK_WIDGET( regionview->ip->id )->window;\n\tRegionviewResize resize;\n\n#ifdef EVENT\n\tprintf( \"regionview_motion: %p, %d x %d\\n\", regionview, x, y );\n#endif /*EVENT*/\n\n\t/* We've got hints turned on, so we have to read the pointer.\n\t */\n\tgdk_window_get_pointer( win, &x, &y, NULL );\n\n\tswitch( regionview->state ) {\n\tcase REGIONVIEW_WAIT:\n\t\tif( regionview_point_in_region( regionview, x, y ) ) {\n\t\t\tresize = regionview_find_resize( regionview, x, y );\n\n\t\t\tiwindow_cursor_context_set_cursor( regionview->cntxt, \n\t\t\t\tregionview_cursors[resize] );\n\t\t\tregionview_set_paint_state( regionview, \n\t\t\t\tGTK_STATE_PRELIGHT );\n\t\t}\n\t\telse {\n\t\t\tiwindow_cursor_context_set_cursor( regionview->cntxt, \n\t\t\t\tIWINDOW_SHAPE_NONE );\n\t\t\tregionview_set_paint_state( regionview, \n\t\t\t\tGTK_STATE_NORMAL );\n\t\t}\n\n\t\tbreak;\n\n\tcase REGIONVIEW_MOVE:\n\tcase REGIONVIEW_RESIZE:\n\t\tif( regionview->grabbed ) \n\t\t\tregionview_motion_grab( regionview, x, y );\n\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( FALSE );\n}\n\n/* Main event loop.\n */\nstatic gint\nregionview_event_cb( GtkWidget *widget, GdkEvent *ev, Regionview *regionview )\n{\n\tImagepresent *ip = regionview->ip;\n\tImagemodel *imagemodel = ip->imagemodel;\n\tgboolean handled = FALSE;\n\n#ifdef EVENT\n\tif( ev->type == GDK_BUTTON_PRESS )\n\t\tprintf( \"regionview_event: GDK_BUTTON_PRESS\\n\" );\n\tif( ev->type == GDK_MOTION_NOTIFY )\n\t\tprintf( \"regionview_event: GDK_MOTION_NOTIFY\\n\" );\n#endif /*EVENT*/\n\n\t/* Only manipulate regions if we're in SELECT mode ... don't want to\n\t * drag regions while we're panning, for example. Exception ... we can\n\t * drag/resize floating regions any time.\n\t */\n\tif( imagemodel->state != IMAGEMODEL_SELECT && regionview->classmodel )\n\t\treturn( FALSE );\n\n\t/* If there's a regionview grabbed, only that regionview responds to\n\t * events.\n\t */\n\tif( regionview->ip->grabbed && regionview->ip->grabbed != regionview )\n\t\treturn( FALSE );\n\n\tswitch( ev->type ) {\n\tcase GDK_BUTTON_PRESS:\n\t\tswitch( ev->button.button ) {\n\t\tcase 1:\n\t\t\thandled = regionview_left_press( regionview, \n\t\t\t\tev, ev->button.x, ev->button.y );\n\t\t\tbreak;\n\n\t\tcase 3:\n\t\t\thandled = regionview_right_press( regionview, \n\t\t\t\tev, ev->button.x, ev->button.y );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t\tbreak;\n\n\tcase GDK_2BUTTON_PRESS:\n\t\tswitch( ev->button.button ) {\n\t\tcase 1:\n\t\t\tif( regionview->state == REGIONVIEW_MOVE &&\n\t\t\t\tregionview->resize == REGIONVIEW_RESIZE_EDIT &&\n\t\t\t\tregionview->classmodel ) {\n\t\t\t\tmodel_edit( GTK_WIDGET( ip ), \n\t\t\t\t\tMODEL( regionview->classmodel ) );\n\t\t\t\thandled = TRUE;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t\tbreak;\n\n\tcase GDK_BUTTON_RELEASE:\n\t\tswitch( ev->button.button ) {\n\t\tcase 1:\n\t\t\thandled = regionview_left_release( regionview, ev );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t\tbreak;\n\n\tcase GDK_MOTION_NOTIFY:\n\t\thandled = regionview_motion( regionview, \n\t\t\tev, ev->button.x, ev->button.y );\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn( handled );\n}\n\n/* The conversion on our image has changed ... eg. on zoom in/out we need to\n * rethink the label position.\n */\nstatic void\nregionview_changed_cb( Model *model, Regionview *regionview )\n{\n#ifdef DEBUG\n\tprintf( \"regionview_changed\\n\" );\n#endif /*DEBUG*/\n\n\tvobject_refresh_queue( VOBJECT( regionview ) );\n}\n\n/* The conversion on our image has been destroyed ... make sure we won't try\n * to disconnect when we go too.\n */\nstatic void\nregionview_conv_destroy_cb( Model *model, Regionview *regionview )\n{\n\tregionview->changed_sid = 0;\n\tregionview->conv_destroy_sid = 0;\n}\n\nstatic gboolean\nregionview_dash_crawl_cb( Regionview *regionview )\n{\n\t/* Don't for regions, areas and points ... no lines in 'em.\n\t */\n\tif( regionview->type != REGIONVIEW_REGION &&\n\t\tregionview->type != REGIONVIEW_MARK &&\n\t\tregionview->type != REGIONVIEW_AREA ) {\n\t\tregionview->dash_offset += 3;\n\n\t\t/* Don't repaint before the first expose. last_type etc.\n\t\t * won't have been inited properly yet.\n\t\t */\n\t\tif( !regionview->first )\n\t\t\tregionview_queue_draw( regionview );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic void\nregionview_setup( Regionview *regionview, \n\tClassmodel *classmodel, Rect *model_area, Imagepresent *ip )\n{\n\tiWindow *iwnd;\n\n\tregionview->classmodel = classmodel;\n\tregionview->ip = ip;\n\tregionview->model_area = model_area;\n\tregionview->our_area = *model_area;\n\tregionview->model_changed_sid = 0;\n\tip->regionviews = g_slist_prepend( ip->regionviews, regionview );\n\n\tif( classmodel ) {\n\t\tclassmodel->views = g_slist_prepend( classmodel->views, \n\t\t\tregionview );\n\n\t\tregionview->model_changed_sid = g_signal_connect( \n\t\t\tG_OBJECT( classmodel ), \"changed\",\n\t\t\tG_CALLBACK( regionview_model_changed_cb ), regionview );\n\t}\n\n\tregionview->expose_sid = g_signal_connect_after( \n\t\tGTK_OBJECT( ip->id ), \"expose_event\", \n\t\tGTK_SIGNAL_FUNC( regionview_expose_cb ), regionview );\n\tregionview->destroy_sid = gtk_signal_connect_object( \n\t\tGTK_OBJECT( ip->id ), \"destroy\", \n\t\tGTK_SIGNAL_FUNC( gtk_widget_destroy ), \n\t\tGTK_OBJECT( regionview ) );\n\tregionview->event_sid = gtk_signal_connect( \n\t\tGTK_OBJECT( ip->id ), \"event\",\n\t\tGTK_SIGNAL_FUNC( regionview_event_cb ), regionview );\n\tregionview->changed_sid = g_signal_connect( \n\t\tG_OBJECT( ip->id->conv ), \"changed\",\n\t\tG_CALLBACK( regionview_changed_cb ), regionview );\n\tregionview->conv_destroy_sid = g_signal_connect( \n\t\tG_OBJECT( ip->id->conv ), \"destroy\",\n\t\tG_CALLBACK( regionview_conv_destroy_cb ), regionview );\n\n\tiwnd = IWINDOW( gtk_widget_get_toplevel( GTK_WIDGET( ip ) ) );\t\n\tregionview->cntxt = iwindow_cursor_context_new( iwnd, \n\t\t1, \"regionview\" );\n\n\tpopup_link( GTK_WIDGET( regionview ), regionview_popup_menu, ip );\n\n\tregionview->dash_crawl = g_timeout_add( 200, \n\t\t(GSourceFunc) regionview_dash_crawl_cb, regionview );\n}\n\nRegionview *\nregionview_new( Classmodel *classmodel, Rect *model_area, Imagepresent *ip )\n{\n\tRegionview *regionview = gtk_type_new( TYPE_REGIONVIEW );\n\n\tregionview_setup( regionview, classmodel, model_area, ip );\n\n#ifdef DEBUG_MAKE\n\tprintf( \"regionview_new: %dx%d size %dx%d\\n\",\n\t\tmodel_area->left, model_area->top, \n\t\tmodel_area->width, model_area->height );\n#endif /*DEBUG_MAKE*/\n\n\treturn( regionview );\n}\n\n/* Type we display for each of the classes. Order is important!\n */\ntypedef struct {\n\tconst char *name;\n\tRegionviewType type;\n} RegionviewDisplay;\n\nstatic RegionviewDisplay regionview_display_table[] = {\n\t{ CLASS_HGUIDE, REGIONVIEW_HGUIDE },\n\t{ CLASS_VGUIDE, REGIONVIEW_VGUIDE },\n\t{ CLASS_MARK, REGIONVIEW_MARK },\n\t{ CLASS_AREA, REGIONVIEW_AREA },\n\t{ CLASS_REGION, REGIONVIEW_REGION },\n\t{ CLASS_ARROW, REGIONVIEW_ARROW }\n};\n\n/* Look at the class we are drawing, set the display type.\n */\nvoid \nregionview_set_type( Regionview *regionview, PElement *root )\n{\n\tgboolean result;\n\tint i;\n\n\tif( heap_is_class( root, &result ) && result )\n\t\tfor( i = 0; i < IM_NUMBER( regionview_display_table ); i++ ) {\n\t\t\tconst char *name = regionview_display_table[i].name;\n\n\t\t\tif( !heap_is_instanceof( name, root, &result ) )\n\t\t\t\tcontinue;\n\t\t\tif( result ) {\n\t\t\t\tregionview->type =\n\t\t\t\t\tregionview_display_table[i].type;\n\t\t\t\tvobject_refresh_queue( VOBJECT( regionview ) );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n}\n"
  },
  {
    "path": "src/regionview.h",
    "content": "/* draw a view of a region in an imageview\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_REGIONVIEW (regionview_get_type())\n#define REGIONVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_REGIONVIEW, Regionview ))\n#define REGIONVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_REGIONVIEW, RegionviewClass ))\n#define IS_REGIONVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_REGIONVIEW ))\n#define IS_REGIONVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_REGIONVIEW ))\n\n#define REGIONVIEW_LABEL_MAX (256)\n\n/* States for the region view.\n */\ntypedef enum {\n\tREGIONVIEW_WAIT,\t/* Waiting for left down */\n\tREGIONVIEW_MOVE,\t/* Dragging on label */\n\tREGIONVIEW_RESIZE\t/* Dragging on resize handle */\n} RegionviewState;\n\n/* Draw types.\n */\ntypedef enum {\n\tREGIONVIEW_REGION,\t/* width & height > 0 */\n\tREGIONVIEW_AREA,\t/* width & height > 0 and locked */\n\tREGIONVIEW_MARK,\t/* width & height == 0 */\n\tREGIONVIEW_ARROW,\t/* width & height unconstrained */\n\tREGIONVIEW_HGUIDE,\t/* width == image width, height == 0 */\n\tREGIONVIEW_VGUIDE,\t/* width == 0, height == image height */\n\tREGIONVIEW_LINE,\t/* floating dashed line for paintbox */\n\tREGIONVIEW_BOX\t\t/* floating dashed box for paintbox */\n} RegionviewType;\n\n/* Resize types.\n */\ntypedef enum {\n\tREGIONVIEW_RESIZE_NONE,\n\tREGIONVIEW_RESIZE_MOVE,\n\tREGIONVIEW_RESIZE_EDIT,\n\tREGIONVIEW_RESIZE_TOPLEFT,\n\tREGIONVIEW_RESIZE_TOP,\n\tREGIONVIEW_RESIZE_TOPRIGHT,\n\tREGIONVIEW_RESIZE_RIGHT,\n\tREGIONVIEW_RESIZE_BOTTOMRIGHT,\n\tREGIONVIEW_RESIZE_BOTTOM,\n\tREGIONVIEW_RESIZE_BOTTOMLEFT,\n\tREGIONVIEW_RESIZE_LEFT,\n\tREGIONVIEW_RESIZE_LAST\n} RegionviewResize;\n\nstruct _Regionview {\n\tView view;\n\n\tRegionviewType type;\n\tgboolean frozen;\t/* type is frozen ... not rethought on resize */\n\n\t/* State for resize/move etc.\n\t */\n\tRegionviewState state;\n\tRegionviewResize resize;/* Resize type */\n\tint dx, dy;\t\t/* Drag offset */\n\tgboolean grabbed;\t/* Currently tracking with mouse */\n\n\t/* The model we show.\n\t */\n\tClassmodel *classmodel;\n\tRect *model_area;\t/* What we read/write to talk to the model */\n\tRect our_area;\t\t/* Same, but our copy ... origin top left */\n\n\t/* The imagepresent we draw on.\n\t */\n\tImagepresent *ip;\n\tiWindowCursorContext *cntxt;\n\n\t/* The signals we've connected to.\n\t */\n\tguint expose_sid;\n\tguint destroy_sid;\n\tguint event_sid;\n\tguint changed_sid;\n\tguint conv_destroy_sid;\n\tguint model_changed_sid;\n\n\t/* Model info we read for display.\n\t */\n\tGtkStateType paint_state;/* prelight/normal/etc. */\n\n\t/* What's on the screen.\n\t */\n\tgboolean unpainting;\t/* We are unpainting */\n\tRect area;\t\t/* Area of region ... image coordinates */\n\tRect label;\t\t/* Area covered by label ... canvas cods */\n\tint ascent;\t\t/* Height of ascenders for text */\n\tint dash_offset;\n\tguint dash_crawl;\t/* Timer for dash crawl animation */\n\tGtkStateType last_paint_state;\n\tRegionviewType last_type;\n\tgboolean first;\t\t/* Initial draw (no old pos to remove) */\n\tgboolean label_geo;\t/* Redo the label geo on refresh, please */\n\n\t/* Text of label we display \n\t */\n\tVipsBuf caption;\n};\n\ntypedef struct _RegionviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} RegionviewClass;\n\nvoid regionview_attach( Regionview *regionview, int x, int y );\n\nGtkType regionview_get_type( void );\nRegionview *regionview_new( Classmodel *classmodel, \n\tRect *model_area, Imagepresent *ip );\n\nvoid regionview_set_type( Regionview *regionview, PElement *root );\n"
  },
  {
    "path": "src/rhs.c",
    "content": "/* the rhs of a tallyrow ... group together everything to the right of the\n * button\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* \n#define DEBUG\n */\n\nstatic HeapmodelClass *parent_class = NULL;\n\n/* child is about to be added ... update our graphic/scol/text shortcuts.\n */\nstatic void\nrhs_child_add( iContainer *parent, iContainer *child, int pos )\n{\n\tRhs *rhs = RHS( parent );\n\n\tif( IS_SUBCOLUMN( child ) ) {\n\t\tIDESTROY( rhs->scol );\n\t\trhs->scol = MODEL( child );\n\t}\n\telse if( IS_ITEXT( child ) ) {\n\t\tIDESTROY( rhs->itext );\n\t\trhs->itext = MODEL( child );\n\t}\n\telse {\n\t\tIDESTROY( rhs->graphic );\n\t\trhs->graphic = MODEL( child );\n\t}\n\n\tICONTAINER_CLASS( parent_class )->child_add( parent, child, pos );\n}\n\nstatic void\nrhs_child_remove( iContainer *parent, iContainer *child )\n{\n\tRhs *rhs = RHS( parent );\n\n\tif( (void *) child == (void *) rhs->graphic )\n\t\trhs->graphic = NULL;\n\telse if( (void *) child == (void *) rhs->scol )\n\t\trhs->scol = NULL;\n\telse if( (void *) child == (void *) rhs->itext )\n\t\trhs->itext = NULL;\n\n\tICONTAINER_CLASS( parent_class )->child_remove( parent, child );\n}\n\nstatic void\nrhs_parent_add( iContainer *child )\n{\n\tg_assert( IS_ROW( child->parent ) );\n\n\tICONTAINER_CLASS( parent_class )->parent_add( child );\n}\n\nstatic View *\nrhs_view_new( Model *model, View *parent )\n{\n\treturn( rhsview_new() );\n}\n\nstatic gboolean\nrhs_load( Model *model, \n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\tRhs *rhs = RHS( model );\n\n\tg_assert( IS_ROW( parent ) );\n\n\t/* Hmm. Is this guaranteed?\n\t */\n\tg_assert( sizeof( RhsFlags ) == sizeof( int ) );\n\n\tif( !get_iprop( xnode, \"vislevel\", &rhs->vislevel ) ||\n\t\t!get_iprop( xnode, \"flags\", (int *) &rhs->flags ) )\n\t\treturn( FALSE );\n\n\tif( !MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic xmlNode *\nrhs_save( Model *model, xmlNode *xnode )\n{\n\tRhs *rhs = RHS( model );\n\n\txmlNode *xthis;\n\n\tif( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )\n\t\treturn( NULL );\n\n\tif( !set_iprop( xthis, \"vislevel\", rhs->vislevel ) ||\n\t\t!set_iprop( xthis, \"flags\", rhs->flags ) )\n\t\treturn( NULL );\n\n\treturn( xthis );\n}\n\n/* How to spot and make a graphic display.\n */\ntypedef struct {\n\tconst char *name;\n\tGType (*type)( void );\n} RhsGraphic;\n\n/* All our graphicdisplay widgets. Order is important! Most-derived classes\n * first.\n */\nstatic RhsGraphic rhs_graphic[] = {\n\t{ CLASS_CLOCK, clock_get_type },\n\t{ CLASS_EXPRESSION, expression_get_type },\n\t{ CLASS_GROUP, group_get_type },\n\t{ CLASS_LIST, group_get_type },\n\t{ CLASS_PATHNAME, pathname_get_type },\n\t{ CLASS_FONTNAME, fontname_get_type },\n\t{ CLASS_TOGGLE, toggle_get_type },\n\t{ CLASS_SLIDER, slider_get_type },\n\t{ CLASS_COLOUR, colour_get_type },\n\t{ CLASS_OPTION, option_get_type },\n\t{ CLASS_MATRIX, matrix_get_type },\n\t{ CLASS_ARROW, iarrow_get_type },\n\t{ CLASS_REGION, iregion_get_type },\n\t{ CLASS_PLOT, plot_get_type },\n\t{ CLASS_IMAGE, iimage_get_type },\n\t{ CLASS_NUMBER, number_get_type },\n\t{ CLASS_REAL, real_get_type },\n\t{ CLASS_VECTOR, vector_get_type },\n\t{ CLASS_STRING, string_get_type }\n};\n\n/* Create/destroy the graphic display.\n */\nstatic gboolean\nrhs_refresh_graphic( Rhs *rhs, PElement *root )\n{\n\tgboolean result;\n\tRow *row = HEAPMODEL( rhs )->row;\n\tint i;\n\n\tif( !heap_is_class( root, &result ) ) \n\t\treturn( FALSE );\n\n\t/* Only for non-parameter class objects.\n\t */\n\tif( result && \n\t\trow->sym &&\n\t\trow->sym->type != SYM_PARAM ) {\n\t\tfor( i = 0; i < IM_NUMBER( rhs_graphic ); i++ ) {\n\t\t\tconst char *name = rhs_graphic[i].name;\n\n\t\t\tif( !heap_is_instanceof( name, root, &result ) ) \n\t\t\t\treturn( FALSE );\n\t\t\tif( result ) \n\t\t\t\tbreak;\n\t\t}\n\n\t\tif( i != IM_NUMBER( rhs_graphic ) ) {\n\t\t\tGType type = rhs_graphic[i].type();\n\n\t\t\tif( !rhs->graphic || !TYPE_EXACT( rhs->graphic, type ) )\n\t\t\t\tclassmodel_new_classmodel( type, rhs );\n\t\t}\n\t\telse\n\t\t\t/* Not a class we know about.\n\t\t\t */\n\t\t\tIDESTROY( rhs->graphic );\n\t}\n\telse\n\t\t/* Should be no graphic display.\n\t\t */\n\t\tIDESTROY( rhs->graphic );\n\n\treturn( TRUE );\n}\n\nstatic void *\nrhs_new_heap( Heapmodel *heapmodel, PElement *root )\n{\n\tgboolean result;\n\tRhs *rhs = RHS( heapmodel );\n\tRow *row = HEAPMODEL( rhs )->row;\n\n#ifdef DEBUG\n\tprintf( \"rhs_new_heap: \" );\n\trow_name_print( HEAPMODEL( rhs )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Create/reuse/destroy the graphic display.\n\t */\n\tif( !rhs_refresh_graphic( rhs, root ) )\n\t\treturn( rhs );\n\n\t/* Create/reuse/destroy class display. Only for non-param symbols.\n\t */\n\tif( !heap_is_class( root, &result ) ) \n\t\treturn( rhs );\n\tif( result && \n\t\trow->sym &&\n\t\trow->sym->type != SYM_PARAM ) {\n\t\tif( !rhs->scol || !IS_SUBCOLUMN( rhs->scol ) ) \n\t\t\tsubcolumn_new( rhs, NULL );\n\t}\n\telse \n\t\t/* Should be no klass display.\n\t\t */\n\t\tIDESTROY( rhs->scol );\n\n\t/* Create/reuse/destroy text display.\n\t */\n\tif( !rhs->itext )\n\t\titext_new( rhs );\n\n\t/* Recurse for children.\n\t */\n\tif( rhs->graphic )\n\t\tif( heapmodel_new_heap( HEAPMODEL( rhs->graphic ), root ) )\n\t\t\treturn( rhs );\n\n\tif( rhs->scol )\n\t\tif( heapmodel_new_heap( HEAPMODEL( rhs->scol ), root ) )\n\t\t\treturn( rhs );\n\n\tif( rhs->itext )\n\t\tif( heapmodel_new_heap( HEAPMODEL( rhs->itext ), root ) )\n\t\t\treturn( rhs );\n\n\treturn( HEAPMODEL_CLASS( parent_class )->new_heap( heapmodel, root ) );\n}\n\n/* Rethink child visibility.\n */\nvoid\nrhs_set_vislevel( Rhs *rhs, int vislevel )\n{\n\tvislevel = IM_MAX( 0, vislevel );\n\n#ifdef DEBUG\n\tprintf( \"rhs_set_vislevel: %d ...\\n\", vislevel );\n#endif /*DEBUG*/\n\n\tif( rhs->scol ) {\n\t\tSubcolumn *scol = SUBCOLUMN( rhs->scol );\n\n\t\tif( rhs->graphic ) {\n\t\t\tswitch( vislevel ) {\n\t\t\tcase 0:\n\t\t\t\trhs->flags = RHS_ITEXT;\n\t\t\t\tbreak;\n\n\t\t\tcase 1:\n\t\t\t\trhs->flags = RHS_GRAPHIC;\n\t\t\t\tbreak;\n\n\t\t\tcase 2:\n\t\t\t\trhs->flags = RHS_ITEXT | RHS_GRAPHIC;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\trhs->flags = RHS_ITEXT | RHS_GRAPHIC | RHS_SCOL;\n\t\t\t}\n\n\t\t\tsubcolumn_set_vislevel( scol, vislevel - 2 );\n\t\t\tif( vislevel < 3 )\n\t\t\t\trhs->vislevel = vislevel;\n\t\t\telse\n\t\t\t\trhs->vislevel = scol->vislevel + 2;\n\t\t}\n\t\telse {\n\t\t\tvislevel = IM_MAX( 1, vislevel );\n\n\t\t\tif( vislevel == 1 )\n\t\t\t\trhs->flags = RHS_ITEXT;\n\t\t\telse\n\t\t\t\trhs->flags = RHS_ITEXT | RHS_SCOL;\n\n\t\t\tsubcolumn_set_vislevel( scol, vislevel - 1 );\n\t\t\trhs->vislevel = scol->vislevel + 1;\n\t\t}\n\t}\n\telse {\n\t\trhs->flags = RHS_ITEXT;\n\t\trhs->vislevel = vislevel;\n\t}\n\n#ifdef DEBUG\n\tprintf( \"... set to: %d\\n\", rhs->vislevel );\n#endif /*DEBUG*/\n\n\tiobject_changed( IOBJECT( rhs ) );\n}\n\nvoid\nrhs_vislevel_up( Rhs *rhs )\n{\n\trhs_set_vislevel( rhs, rhs->vislevel + 1 );\n}\n\nvoid\nrhs_vislevel_down( Rhs *rhs )\n{\n\trhs_set_vislevel( rhs, rhs->vislevel - 1 );\n}\n\nstatic void *\nrhs_update_model( Heapmodel *heapmodel )\n{\n\tRhs *rhs = RHS( heapmodel );\n\n\t/* Update visibility.\n\t */\n\trhs_set_vislevel( rhs, rhs->vislevel );\n\n\treturn( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) );\n}\n\nstatic void\nrhs_class_init( RhsClass *class )\n{\n\tiContainerClass *icontainer_class = (iContainerClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tHeapmodelClass *heapmodel_class = (HeapmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\ticontainer_class->child_add = rhs_child_add;\n\ticontainer_class->child_remove = rhs_child_remove;\n\ticontainer_class->parent_add = rhs_parent_add;\n\n\tmodel_class->view_new = rhs_view_new;\n\tmodel_class->load = rhs_load;\n\tmodel_class->save = rhs_save;\n\n\theapmodel_class->new_heap = rhs_new_heap;\n\theapmodel_class->update_model = rhs_update_model;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\nrhs_init( Rhs *rhs )\n{\n#ifdef DEBUG\n\tprintf( \"rhs_init\\n\" );\n#endif /*DEBUG*/\n\n\t/* -1 means not set yet ... default vislevel set by row_new_heap()\n\t * when the class members become available.\n\t */\n        rhs->vislevel = -1;\n\n        rhs->graphic = NULL;\n        rhs->scol = NULL;\n        rhs->itext = NULL;\n}\n\nGType\nrhs_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( RhsClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) rhs_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Rhs ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) rhs_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_HEAPMODEL, \n\t\t\t\"Rhs\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nRhs *\nrhs_new( Row *row )\n{\n\tRhs *rhs = RHS( g_object_new( TYPE_RHS, NULL ) );\n\n\ticontainer_child_add( ICONTAINER( row ), ICONTAINER( rhs ), -1 );\n\n#ifdef DEBUG\n\tprintf( \"rhs_new: \" );\n\trow_name_print( HEAPMODEL( rhs )->row );\n\tprintf( \" (%p)\\n\", rhs );\n#endif /*DEBUG*/\n\n\treturn( rhs );\n}\n\nstatic void *\nrhs_child_edited_sub( Model *model )\n{\n\tRow *row = ROW( model );\n\n\tif( row->child_rhs && rhs_child_edited( row->child_rhs ) )\n\t\treturn( row );\n\n\treturn( NULL );\n}\n\n/* Does this RHS have any edited children? text, graphic, or recursive.\n */\ngboolean\nrhs_child_edited( Rhs *rhs )\n{\n\tif( rhs->itext && ITEXT( rhs->itext )->edited )\n\t\treturn( TRUE );\n\telse if( rhs->graphic && CLASSMODEL( rhs->graphic )->edited )\n\t\treturn( TRUE );\n\telse if( rhs->scol ) \n\t\treturn( icontainer_map( ICONTAINER( rhs->scol ),\n\t\t\t(icontainer_map_fn) rhs_child_edited_sub, \n\t\t\tNULL, NULL ) != NULL );\n\telse\n\t\treturn( FALSE );\n}\n"
  },
  {
    "path": "src/rhs.h",
    "content": "/* the rhs of a row ... group together everything to the right of the\n * button\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_RHS (rhs_get_type())\n#define RHS( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_RHS, Rhs ))\n#define RHS_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_RHS, RhsClass))\n#define IS_RHS( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_RHS ))\n#define IS_RHS_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_RHS ))\n#define RHS_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_RHS, RhsClass ))\n\n/* Which children are visible.\n */\ntypedef enum {\n\tRHS_GRAPHIC = 1,\t\t/* Graphical display */\n\tRHS_SCOL = 2,\t\t\t/* Class browser display */\n\tRHS_ITEXT = 4\t\t\t/* Textual display */\n} RhsFlags;\n\nstruct _Rhs {\n\tHeapmodel parent_class;\n\n\tint vislevel;\t\t/* Visibility level */\n\tRhsFlags flags;\t\t/* Which children we want visible */\n\n        Model *graphic;\t\t/* Graphic display ... toggle/slider/etc */\n        Model *scol;\t\t/* Class display */\n        Model *itext;\t\t/* Text display */\n};\n\ntypedef struct _RhsClass {\n\tHeapmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} RhsClass;\n\nGType rhs_get_type( void );\nRhs *rhs_new( Row *row );\n\nvoid rhs_set_vislevel( Rhs *rhs, int vislevel );\nvoid rhs_vislevel_up( Rhs *rhs );\nvoid rhs_vislevel_down( Rhs *rhs );\n\ngboolean rhs_child_edited( Rhs *rhs );\n"
  },
  {
    "path": "src/rhsview.c",
    "content": "/* the rhs of a tallyrow ... group together everything to the right of the\n * button\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\n/* Get this if ws->mode changes.\n */\nstatic void\nrhsview_reset( View *view )\n{\n\tRhsview *rhsview = RHSVIEW( view );\n\tRhs *rhs = RHS( VOBJECT( rhsview )->iobject );\n\tRow *row = HEAPMODEL( rhs )->row;\n\n\tmodel_display( rhs->itext, \n\t\trow->ws->mode == WORKSPACE_MODE_FORMULA || \n\t\trhs->flags & RHS_ITEXT );\n\n\tVIEW_CLASS( parent_class )->reset( view );\n}\n\nstatic void \nrhsview_refresh( vObject *vobject )\n{\n\tRhsview *rhsview = RHSVIEW( vobject );\n\tRhs *rhs = RHS( VOBJECT( rhsview )->iobject );\n\tRow *row = HEAPMODEL( rhs )->row;\n\n#ifdef DEBUG\n\tprintf( \"rhsview_refresh: \" );\n\trow_name_print( HEAPMODEL( rhs )->row );\n\tprintf( \" \" );\n\tif( rhs->flags & RHS_GRAPHIC )\n\t\tprintf( \"RHS_GRAPHIC \" );\n\tif( rhs->flags & RHS_SCOL )\n\t\tprintf( \"RHS_SCOL \" );\n\tif( rhs->flags & RHS_ITEXT )\n\t\tprintf( \"RHS_ITEXT \" );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Add/remove children according to rhs->flags. \n\t */\n\tmodel_display( rhs->graphic, rhs->flags & RHS_GRAPHIC );\n\tmodel_display( rhs->scol, rhs->flags & RHS_SCOL );\n\n\tswitch( row->ws->mode ) {\n\tcase WORKSPACE_MODE_REGULAR:\n\t\tmodel_display( rhs->itext, rhs->flags & RHS_ITEXT );\n\t\tbreak;\n\n\tcase WORKSPACE_MODE_FORMULA:\n\t\tmodel_display( rhs->itext, TRUE );\n\t\tbreak;\n\n\tcase WORKSPACE_MODE_NOEDIT:\n\t\t/* Only show the text if it's the only this we have for this\n\t\t * row.\n\t\t */\n\t\tif( rhs->graphic &&\n\t\t\trhs->flags & RHS_GRAPHIC )\n\t\t\tmodel_display( rhs->itext, FALSE );\n\t\telse if( rhs->scol &&\n\t\t\trhs->flags & RHS_SCOL )\n\t\t\tmodel_display( rhs->itext, FALSE );\n\t\telse\n\t\t\tmodel_display( rhs->itext, \n\t\t\t\trhs->flags & RHS_ITEXT );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( 0 );\n\t}\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\nrhsview_link( View *view, Model *model, View *parent )\n{\n\tRhsview *rhsview = RHSVIEW( view );\n\tRowview *rview = ROWVIEW( parent );\n\n#ifdef DEBUG\n\tprintf( \"rhsview_link: \" );\n\trow_name_print( ROW( VOBJECT( rview )->iobject ) );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\trhsview->rview = rview;\n}\n\nstatic void\nrhsview_child_add( View *parent, View *child )\n{\n\tRhsview *rhsview = RHSVIEW( parent );\n\n\tif( IS_SUBCOLUMNVIEW( child ) ) {\n\t\tgtk_table_attach_defaults( GTK_TABLE( rhsview->table ),\n\t\t\tGTK_WIDGET( child ), 0, 1, 1, 2 );\n\t\trhsview->scol = child;\n\t}\n\telse if( IS_ITEXTVIEW( child ) ) {\n\t\tgtk_table_attach_defaults( GTK_TABLE( rhsview->table ),\n\t\t\tGTK_WIDGET( child ), 0, 1, 2, 3 );\n\t\trhsview->itext = child;\n\t}\n\telse {\n\t\tgtk_table_attach_defaults( GTK_TABLE( rhsview->table ),\n\t\t\tGTK_WIDGET( child ), 0, 1, 0, 1 );\n\t\trhsview->graphic = child;\n\t\tg_assert( IS_GRAPHICVIEW( child ) );\n\t}\n\n\tVIEW_CLASS( parent_class )->child_add( parent, child );\n}\n\nstatic void\nrhsview_child_remove( View *parent, View *child )\n{\n\tRhsview *rhsview = RHSVIEW( parent );\n\n\tif( IS_SUBCOLUMNVIEW( child ) ) \n\t\trhsview->scol = NULL;\n\telse if( IS_ITEXTVIEW( child ) ) \n\t\trhsview->itext = NULL;\n\telse \n\t\trhsview->graphic = NULL;\n\n\tVIEW_CLASS( parent_class )->child_remove( parent, child );\n}\n\nstatic void\nrhsview_class_init( RhsviewClass *class )\n{\n\tvObjectClass *vobject_class = (vObjectClass*) class;\n\tViewClass *view_class = (ViewClass*) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = rhsview_refresh;\n\n\tview_class->link = rhsview_link;\n\tview_class->child_add = rhsview_child_add;\n\tview_class->child_remove = rhsview_child_remove;\n\tview_class->reset = rhsview_reset;\n}\n\nstatic void\nrhsview_init( Rhsview *rhsview )\n{\n\trhsview->rview = NULL;\n\n\t/* Attached on refresh. \n\t */\n\trhsview->graphic = NULL;\n\trhsview->scol = NULL;\n\trhsview->itext = NULL;\n\n\trhsview->table = gtk_table_new( 3, 1, FALSE );\n        gtk_box_pack_start( GTK_BOX( rhsview ), \n\t\trhsview->table, TRUE, FALSE, 0 );\n        gtk_widget_show( rhsview->table );\n\trhsview->flags = 0;\n\n        gtk_widget_show( GTK_WIDGET( rhsview ) );\n}\n\nGtkType\nrhsview_get_type( void )\n{\n\tstatic GtkType rhsview_type = 0;\n\n\tif( !rhsview_type ) {\n\t\tstatic const GtkTypeInfo rhsview_info = {\n\t\t\t\"Rhsview\",\n\t\t\tsizeof( Rhsview ),\n\t\t\tsizeof( RhsviewClass ),\n\t\t\t(GtkClassInitFunc) rhsview_class_init,\n\t\t\t(GtkObjectInitFunc) rhsview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\trhsview_type = gtk_type_unique( TYPE_VIEW, &rhsview_info );\n\t}\n\n\treturn( rhsview_type );\n}\n\nView *\nrhsview_new( void )\n{\n\tRhsview *rhsview = gtk_type_new( TYPE_RHSVIEW );\n\n\treturn( VIEW( rhsview ) );\n}\n"
  },
  {
    "path": "src/rhsview.h",
    "content": "/* the rhs of a tallyrow ... group together everything to the right of the\n * button\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_RHSVIEW (rhsview_get_type())\n#define RHSVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_RHSVIEW, Rhsview ))\n#define RHSVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_RHSVIEW, RhsviewClass ))\n#define IS_RHSVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_RHSVIEW ))\n#define IS_RHSVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_RHSVIEW ))\n\nstruct _Rhsview {\n\tView item;\n\n\tRowview *rview;\n\n\tView *graphic;\t\t\t/* Our three elements */\n\tView *scol;\n\tView *itext;\n\n        GtkWidget *table;\t\t/* Lay out elements in this */\n\tRhsFlags flags;\t\t\t/* Last vis set we set */\n};\n\ntypedef struct _RhsviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} RhsviewClass;\n\nGtkType rhsview_get_type( void );\nView *rhsview_new( void );\n"
  },
  {
    "path": "src/row.c",
    "content": "/* A row in a workspace ... not a widget, part of subcolumn\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* Mad detail.\n#define DEBUG\n */\n\n/* Show each row being calculated.\n#define DEBUG_ROW\n */\n\n/* Making and removing links between rows.\n#define DEBUG_LINK\n */\n\n/* Time row recomp.\n#define DEBUG_TIME_SORT\n */\n\n/* Trace create/destroy.\n#define DEBUG_NEW\n */\n\n/* Dirty/clean stuff.\n#define DEBUG_DIRTY\n */\n\n/* Error set/clear.\n#define DEBUG_ERROR\n */\n\n/* Show row recomp order decisions.\n#define DEBUG_SORT_VERBOSE\n#define DEBUG_SORT\n */\n\n#include \"ip.h\"\n\nstatic HeapmodelClass *parent_class = NULL;\n\nstatic void *\nrow_map_all_sub( Model *model, row_map_fn fn, void *a, void *b, void *c )\n{\n\tif( IS_ROW( model ) )\n\t\treturn( fn( ROW( model ), a, b, c ) );\n\n\treturn( NULL );\n}\n\nstatic void *\nrow_map_all( Row *row, row_map_fn fn, void *a, void *b, void *c )\n{\n\treturn( icontainer_map4_all( ICONTAINER( row ),\n\t\t(icontainer_map4_fn) row_map_all_sub, (void *) fn, a, b, c ) );\n}\n\nconst char *\nrow_name( Row *row )\n{\n\tif( row->sym )\n\t\treturn( IOBJECT( row->sym )->name );\n\telse\n\t\treturn( IOBJECT( row )->name );\n}\n\nstatic Row *\nrow_get_parent( Row *row )\n{\n\treturn( HEAPMODEL( row )->row );\n}\n\n/* Make a fully-qualified name for a row's symbol ... walk back up the tally\n * hierarchy. eg. \"A1.fred.x\" ... produce a name which will find this row from\n * a local of context.\n */\nvoid\nrow_qualified_name_relative( Symbol *context, Row *row, VipsBuf *buf )\n{\n\tif( !row_get_parent( row ) ) {\n\t\tif( !row->sym )\n\t\t\tvips_buf_appends( buf, \"(null)\" );\n\t\telse\n\t\t\tsymbol_qualified_name_relative( context, \n\t\t\t\trow->sym, buf );\n\t}\n\telse {\n\t\t/* Qualify our parents, then do us.\n\t\t */\n\t\trow_qualified_name_relative( context, \n\t\t\trow_get_parent( row ), buf );\n\t\tvips_buf_appends( buf, \".\" );\n\t\tvips_buf_appends( buf, row_name( row ) );\n\t}\n}\n\n/* Make a fully-qualified name for a row's symbol ... walk back up the tally\n * hierarchy. eg. \"A1.fred.x\".\n */\nvoid\nrow_qualified_name( Row *row, VipsBuf *buf )\n{\n\tif( row->ws )\n\t\trow_qualified_name_relative( row->ws->sym, row, buf );\n}\n\n/* Convenience ... print a row name out, identifying by tally heirarchy.\n */\nvoid *\nrow_name_print( Row *row )\n{\n\tif( row ) {\n\t\tchar txt[100];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\trow_qualified_name( row, &buf );\n\t\tprintf( \"%s \", vips_buf_all( &buf ) );\n\t}\n\telse\n\t\tprintf( \"(null)\" );\n\n\treturn( NULL );\n}\n\nstatic void *\nrow_dirty_clear( Row *row )\n{\n#ifdef DEBUG_DIRTY\n{\n\tRow *top_row = row->top_row;\n\n\tif( row->dirty )\n\t\tg_assert( g_slist_find( top_row->recomp, row ) );\n}\n#endif /*DEBUG_DIRTY*/\n\n\tif( row->dirty ) {\n\t\tRow *top_row = row->top_row;\n\n\t\trow->dirty = FALSE;\n\t\ttop_row->recomp = g_slist_remove( top_row->recomp, row );\n\n#ifdef DEBUG_DIRTY\n\t\tprintf( \"row_dirty_clear: \" );\n\t\trow_name_print( row );\n\t\tprintf( \"\\n\" );\n#endif /*DEBUG_DIRTY*/\n\n\t\tiobject_changed( IOBJECT( row ) );\n\t}\n\n\treturn( NULL );\n}\n\n/* Set a single row dirty.\n */\nstatic void *\nrow_dirty_set_single( Row *row, gboolean clear_error )\n{\n#ifdef DEBUG_DIRTY\n{\n\tRow *top_row = row->top_row;\n\n\tif( row->dirty )\n\t\tg_assert( g_slist_find( top_row->recomp, row ) );\n\tif( !row->dirty )\n\t\tg_assert( !g_slist_find( top_row->recomp, row ) );\n}\n#endif /*DEBUG_DIRTY*/\n\n\tif( !row->dirty ) {\n\t\tRow *top_row = row->top_row;\n\n\t\trow->dirty = TRUE;\n\t\ttop_row->recomp = g_slist_prepend( top_row->recomp, row );\n\n\t\tiobject_changed( IOBJECT( row ) );\n\n#ifdef DEBUG_DIRTY\n\t\tprintf( \"row_dirty_set_single: \" );\n\t\trow_name_print( row );\n\t\tprintf( \" clear_error = %s\\n\", bool_to_char( clear_error ) );\n#endif /*DEBUG_DIRTY*/\n\n\t\t/* Make sure error is clear ... we want to recomp.\n\t\t */\n\t\tif( row->expr && clear_error )\n\t\t\texpr_error_clear( row->expr );\n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\nrow_dirty_set_sub( Model *model, gboolean clear_error )\n{\n\tif( IS_ROW( model ) ) {\n\t\tRow *row = ROW( model );\n\t\tRhs *rhs = row->child_rhs;\n\n\t\tg_assert( !rhs || IS_RHS( rhs ) );\n\n\t\tif( rhs && rhs->itext && ITEXT( rhs->itext )->edited )\n\t\t\trow_dirty_set_single( row, clear_error );\n\t\telse if( rhs && rhs->graphic && \n\t\t\tCLASSMODEL( rhs->graphic )->edited )\n\t\t\trow_dirty_set_single( row, clear_error );\n\t}\n\n\treturn( NULL );\n}\n\n/* When we mark a row dirty, we need to mark any subrows with non-default\n * values dirty too so that they will get a chance to reapply their edits over\n * the top of the new value we will make for this row.\n */\nstatic void *\nrow_dirty_set( Row *row, gboolean clear_error )\n{\n\trow_dirty_set_single( row, clear_error );\n\n\treturn( icontainer_map_all( ICONTAINER( row ),\n\t\t(icontainer_map_fn) row_dirty_set_sub, \n\t\t\tGINT_TO_POINTER( clear_error ) ) );\n}\n\n/* Mark a row as containing an error ... called from expr_error_set()\n * ... don't call this directly.\n */\nvoid\nrow_error_set( Row *row )\n{\n\tif( !row->err ) {\n\t\tWorkspace *ws = row->ws;\n\t\tgboolean was_clear = ws->errors == NULL;\n\n\t\tws->errors = g_slist_prepend( ws->errors, row );\n\t\trow->err = TRUE;\n\n#ifdef DEBUG_ERROR\n\t\tprintf( \"row_error_set: \" );\n\t\trow_name_print( row );\n\t\tprintf( \"\\n\" );\n#endif /*DEBUG_ERROR*/\n\n\t\tiobject_changed( IOBJECT( row ) );\n\n\t\t/* First error? State change on workspace.\n\t\t */\n\t\tif( was_clear )\n\t\t\tiobject_changed( IOBJECT( ws ) );\n\n\t\t/* If this is a local row, mark the top row in error too to end\n\t\t * recomp on this tree.\n\t\t */\n\t\tif( row != row->top_row ) {\n\t\t\tchar txt[100];\n\t\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\t\trow_qualified_name( row, &buf );\n\n\t\t\terror_top( _( \"Error in row.\" ) );\n\t\t\t/* Elements are name of row, principal error,\n\t\t\t * secondary error.\n\t\t\t */\n\t\t\terror_sub( _( \"Error in row %s: %s\\n%s\" ),\t\n\t\t\t\tvips_buf_all( &buf ),\n\t\t\t\trow->expr->error_top,\n\t\t\t\trow->expr->error_sub );\n\n\t\t\texpr_error_set( row->top_row->expr );\n\t\t}\n\t}\n}\n\n/* Clear error state ... called from expr_error_clear() ... don't call this\n * directly.\n */\nvoid\nrow_error_clear( Row *row )\n{\n\tif( row->err ) {\n\t\tWorkspace *ws = row->ws;\n\n\t\tws->errors = g_slist_remove( ws->errors, row );\n\t\trow->err = FALSE;\n\n\t\tiobject_changed( IOBJECT( row ) );\n\n#ifdef DEBUG_ERROR\n\t\tprintf( \"row_error_clear: \" );\n\t\trow_name_print( row );\n\t\tprintf( \"\\n\" );\n#endif /*DEBUG_ERROR*/\n\n\t\t/* Mark our text modified to make sure we reparse and compile.\n\t\t * The code may contain pointers to dead symbols if we were in\n\t\t * error because they were undefined.\n\t\t */\n\t\tif( row->child_rhs && row->child_rhs->itext )\n\t\t\theapmodel_set_modified( \n\t\t\t\tHEAPMODEL( row->child_rhs->itext ), TRUE );\n\n\t\t/* All errors gone? Ws changed too.\n\t\t */\n\t\tif( !ws->errors )\n\t\t\tiobject_changed( IOBJECT( ws ) );\n\n\t\t/* Is this a local row? Clear the top row error as well, in\n\t\t * case it's in error because of us.\n\t\t */\n\t\tif( row != row->top_row && row->top_row->expr ) {\n\t\t\texpr_error_clear( row->top_row->expr );\n\t\t\trow_dirty_set( row->top_row, TRUE );\n\t\t}\n\t}\n}\n\n/* Break a dependency.\n */\nstatic void *\nrow_link_break( Row *parent, Row *child )\n{\n\t/* Must be there.\n\t */\n\tg_assert( g_slist_find( parent->children, child ) &&\n\t\tg_slist_find( child->parents, parent ) );\n\n\tparent->children = g_slist_remove( parent->children, child );\n\tchild->parents = g_slist_remove( child->parents, parent );\n\n#ifdef DEBUG_LINK\n\tprintf( \"row_link_break: breaking link from \" );\n\trow_name_print( parent );\n\tprintf( \"to \" );\n\trow_name_print( child );\n\tprintf( \"\\n\" );\n#endif /*DEBUG_LINK*/\n\n\treturn( NULL );\n}\n\nstatic void *\nrow_link_break_rev( Row *child, Row *parent )\n{\n\treturn( row_link_break( parent, child ) );\n}\n\nstatic void\nrow_dispose( GObject *gobject )\n{\n\tRow *row = ROW( gobject );\n\n#ifdef DEBUG_NEW\n\t/* Can't use row_name_print(), we may not have a parent.\n\t */\n\tprintf( \"row_dispose: %s\", NN( IOBJECT( row )->name ) );\n\tif( row->sym ) \n\t\tprintf( \" (%s)\", symbol_name( row->sym ) );\n\tprintf( \"\\n\" );\n#endif /*DEBUG_NEW*/\n\n\t/* Reset state. Also see row_parent_remove().\n\t */\n\trow_hide_dependents( row );\n\tif( row->expr )\n\t\texpr_error_clear( row->expr );\n\tif( row->top_col && row->top_col->last_select == row )\n\t\trow->top_col->last_select = NULL;\n\trow_deselect( row );\n\n\t/* Break all recomp links.\n\t */\n\tslist_map( row->parents, (SListMapFn) row_link_break, row );\n\tslist_map( row->children, (SListMapFn) row_link_break_rev, row );\n\tg_assert( !row->parents && !row->children );\n\t(void) slist_map( row->recomp, (SListMapFn) row_dirty_clear, NULL );\n\tif( row->top_row )\n\t\trow->top_row->recomp_save = \n\t\t\tg_slist_remove( row->top_row->recomp_save, row );\n\tIM_FREEF( g_slist_free, row->recomp_save );\n\n\tg_assert( !row->recomp );\n\n\tif( row->expr ) {\n\t\tg_assert( row->expr->row == row );\n\n\t\t/* If we're a local row, we will have a private expr \n\t\t * allocated for us. Junk it.\n\t\t */\n\t\tif( row != row->top_row ) \n\t\t\ticontainer_child_remove( ICONTAINER( row->expr ) );\n\t\telse {\n\t\t\t/* Top-level row, we were zapping the sym's expr.\n\t\t\t * Break the link to it.\n\t\t\t */\n\t\t\trow->expr->row = NULL;\n\t\t\trow->expr = NULL;\n\t\t}\n\t}\n\n\t/* Is this a top-level row? Kill the symbol too. Need to do this after\n\t * sorting out row->expr, since otherwise killing the symbol will kill\n\t * us again in turn.\n\t */\n\tif( row == row->top_row ) \n\t\tIDESTROY( row->sym );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void *\nrow_add_parent_name( Link *link, VipsBuf *buf )\n{\n\tRow *row;\n\n\tif( link->parent->expr && \n\t\t(row = link->parent->expr->row) ) {\n\t\trow_qualified_name_relative( link->child, row, buf );\n\t\tvips_buf_appends( buf, \" \" );\n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\nrow_add_child_name( Link *link, VipsBuf *buf )\n{\n\tRow *row;\n\n\tif( link->child->expr && \n\t\t(row = link->child->expr->row) ) {\n\t\trow_qualified_name_relative( link->parent, row, buf );\n\t\tvips_buf_appends( buf, \" \" );\n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\nrow_add_dirty_child_name( Link *link, VipsBuf *buf )\n{\n\tif( link->child->dirty ) {\n\t\tsymbol_qualified_name_relative( link->parent, \n\t\t\tlink->child, buf );\n\t\tvips_buf_appends( buf, \" \" );\n\t}\n\n\treturn( NULL );\n}\n\nstatic void\nrow_info( iObject *iobject, VipsBuf *buf )\n{\n\tRow *row = ROW( iobject );\n\n\tvips_buf_appends( buf, _( \"Name\" ) );\n\tvips_buf_appends( buf, \": \" );\n\trow_qualified_name( row, buf );\n\tvips_buf_appends( buf, \"\\n\" );\n\n\tif( row->expr ) \n\t\tiobject_info( IOBJECT( row->expr ), buf );\n\tif( row->child_rhs &&\n\t\trow->child_rhs->itext ) \n\t\tiobject_info( IOBJECT( row->child_rhs->itext ), buf );\n\tif( row->child_rhs &&\n\t\trow->child_rhs->graphic ) \n\t\tiobject_info( IOBJECT( row->child_rhs->graphic ), buf );\n\tif( row->top_row->sym ) {\n\t\tif( row->top_row->sym->topchildren ) {\n\t\t\trow_qualified_name( row, buf );\n\t\t\tvips_buf_appends( buf, \" \" );\n\t\t\t/* Expands to eg. \"B1 refers to: B2, B3\".\n\t\t\t */\n\t\t\tvips_buf_appends( buf, _( \"refers to\" ) );\n\t\t\tvips_buf_appends( buf, \": \" );\n\t\t\tslist_map_rev( row->top_row->sym->topchildren, \n\t\t\t\t(SListMapFn) row_add_child_name, buf );\n\t\t\tvips_buf_appends( buf, \"\\n\" );\n\t\t}\n\t\tif( row->top_row->sym->topparents ) {\n\t\t\trow_qualified_name( row, buf );\n\t\t\tvips_buf_appends( buf, \" \" );\n\t\t\t/* Expands to eg. \"B1 is referred to by: B2, B3\".\n\t\t\t */\n\t\t\tvips_buf_appends( buf, _( \"is referred to by\" ) );\n\t\t\tvips_buf_appends( buf, \": \" );\n\t\t\tslist_map_rev( row->top_row->sym->topparents, \n\t\t\t\t(SListMapFn) row_add_parent_name, buf );\n\t\t\tvips_buf_appends( buf, \"\\n\" );\n\t\t}\n\t}\n\tif( row == row->top_row && \n\t\trow->sym &&\n\t\trow->sym->dirty ) {\n\t\tSymbol *sym = row->sym;\n\n\t\tif( sym->ndirtychildren ) {\n\t\t\trow_qualified_name( row, buf );\n\t\t\tvips_buf_appends( buf, \" \" );\n\t\t\tvips_buf_appends( buf, _( \"is blocked on\" ) );\n\t\t\tvips_buf_appends( buf, \": \" );\n\t\t\tslist_map_rev( sym->topchildren,\n\t\t\t\t(SListMapFn) row_add_dirty_child_name, buf );\n\t\t\tvips_buf_appends( buf, \"\\n\" );\n\t\t}\n\t}\n}\n\nstatic Rhs *\nrow_get_rhs( Row *row )\n{\n\tg_assert( g_slist_length( ICONTAINER( row )->children ) == 1 );\n\n\treturn( RHS( ICONTAINER( row )->children->data ) );\n}\n\nstatic void\nrow_child_add( iContainer *parent, iContainer *child, int pos )\n{\n\tRow *row = ROW( parent );\n\n\tICONTAINER_CLASS( parent_class )->child_add( parent, child, pos );\n\n\t/* Update our context.\n\t */\n\trow->child_rhs = row_get_rhs( row );\n}\n\nstatic Subcolumn *\nrow_get_subcolumn( Row *row )\n{\n\treturn( SUBCOLUMN( ICONTAINER( row )->parent ) );\n}\n\nstatic Column *\nrow_get_column( Row *row )\n{\n\tSubcolumn *scol = row_get_subcolumn( row );\n\n\tif( scol )\n\t\treturn( scol->top_col ); \n\telse\n\t\treturn( NULL ); \n}\n\n/* Search back up the widget hierarchy for the base row for this\n * row ... eg \"A7\"->expr->row.\n */\nstatic Row *\nrow_get_root( Row *row )\n{\n\tRow *enclosing = row_get_parent( row );\n\n\tif( !enclosing )\n\t\treturn( row );\n\telse\n\t\treturn( row_get_root( enclosing ) );\n}\n\nWorkspace *\nrow_get_workspace( Row *row )\n{\n\tColumn *col = row_get_column( row );\n\n\tif( col )\n\t\treturn( col->ws );\n\telse\n\t\treturn( NULL );\n}\n\nstatic void\nrow_parent_add( iContainer *child )\n{\n\tRow *row = ROW( child );\n\n\tg_assert( IS_SUBCOLUMN( child->parent ) );\n\n\tICONTAINER_CLASS( parent_class )->parent_add( child );\n\n\t/* Update our context.\n\t */\n\trow->scol = row_get_subcolumn( row );\n\trow->top_col = row_get_column( row );\n\trow->ws = row_get_workspace( row );\n\trow->top_row = row_get_root( row );\n}\n\nstatic void\nrow_parent_remove( iContainer *child )\n{\n\tRow *row = ROW( child );\n\n\t/* Reset the parts of state which touch our parent.\n\t */\n\trow_dirty_clear( row );\n\trow_deselect( row );\n\n\t/* Don't clear error ... we may no longer have the link to expr. See\n\t * row_dispose() for that.\n\t */\n\n\tICONTAINER_CLASS( parent_class )->parent_remove( child );\n}\n\nstatic View *\nrow_view_new( Model *model, View *parent )\n{\n\treturn( rowview_new() );\n}\n\nstatic void\nrow_scrollto( Model *model, ModelScrollPosition position )\n{\n\tRow *row = ROW( model );\n\tColumn *col = row->top_col;\n\n\t/* If our column is closed, there won't be a view to scrollto, ouch!\n\t * Need to open the column first, then scroll to that column. We can't\n\t * scroll to the exact row, since there's no view for it, and won't be\n\t * for a while after we hit the idle loop again.\n\t */\n\tif( !col->open ) {\n\t\tcolumn_set_open( col, TRUE );\n\t\tcolumn_scrollto( col, position );\n\t}\n\n\tMODEL_CLASS( parent_class )->scrollto( model, position );\n}\n\nstatic gboolean\nrow_load( Model *model, \n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\tRow *row = ROW( model );\n\tSubcolumn *scol = SUBCOLUMN( parent );\n\n\tchar name[256];\n\n\tg_assert( IS_SUBCOLUMN( parent ) );\n\n\tif( !get_sprop( xnode, \"name\", name, 256 ) ) \n\t\treturn( FALSE );\n\tIM_SETSTR( IOBJECT( row )->name, name );\n\n#ifdef DEBUG\n\tprintf( \"row_load: loading row %s (xmlNode %p)\\n\", name, xnode );\n#endif /*DEBUG*/\n\n\t/* Popup is optional (top level only)\n\t */\n\t(void) get_bprop( xnode, \"popup\", &row->popup );\n\n\tif( scol->is_top ) {\n\t\tColumn *col = scol->top_col;\n\t\tWorkspace *ws = col->ws;\n\n\t\tSymbol *sym;\n\n\t\tsym = symbol_new( ws->sym->expr->compile, name );\n\t\tsymbol_user_init( sym );\n\t\t(void) compile_new_local( sym->expr );\n\t\trow_link_symbol( row, sym, NULL );\n\n\t\t/* We can't symbol_made() here, we've not parsed our value\n\t\t * yet. See below ... we just make sure we're on the recomp\n\t\t * lists.\n\t\t */\n\t}\n\n\tif( !MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) )\n\t\treturn( FALSE );\n\n\t/* If we've loaded a complete row system, mark this row plus any \n\t * edited subrows dirty, and make sure this sym is dirty too.\n\t */\n\tif( scol->is_top ) {\n\t\trow_dirty_set( row, TRUE );\n\t\texpr_dirty( row->sym->expr, link_serial_new() );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Should we display this row. Non-displayed rows don't have rhs, don't\n * appear on the screen, and aren't saved. They do have rows though, so their\n * dependencies are tracked.\n *\n * We work off sym rather than row so that we can work before the row is fully\n * built.\n */\nstatic gboolean\nrow_is_displayable( Symbol *sym )\n{\n\tif( is_system( sym ) )\n\t\treturn( FALSE );\n\tif( sym->expr && sym->expr->compile && sym->expr->compile->nparam > 0 )\n\t\treturn( FALSE );\n\tif( is_super( sym ) && sym->expr ) {\n\t\tExpr *expr = sym->expr;\n\t\tPElement *root = &expr->root;\n\n\t\t/* Empty superclass.\n\t\t */\n\t\tif( PEISELIST( root ) )\n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic xmlNode *\nrow_save( Model *model, xmlNode *xnode )\n{\n\tRow *row = ROW( model );\n\n\txmlNode *xthis;\n\n\t/* Don't save system rows, or empty superclasses.\n\t */\n\tif( row->sym ) {\n\t\tif( !row_is_displayable( row->sym ) )\n\t\t\t/* Need to return non-NULL for abort with no error.\n\t\t\t */\n\t\t\treturn( (xmlNode *) -1 );\n\t}\n\n\tif( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )\n\t\treturn( NULL );\n\n\t/* Top-level only.\n\t */\n\tif( row->top_row == row ) \n\t\tif( !set_sprop( xthis, \"popup\", bool_to_char( row->popup ) ) )\n\t\t\treturn( NULL );\n\tif( !set_sprop( xthis, \"name\", IOBJECT( row )->name ) )\n\t\treturn( NULL );\n\n\treturn( xthis );\n}\n\nstatic void *\nrow_clear_to_save( Model *model )\n{\n\tif( IS_ROW( model ) ) \n\t\tROW( model )->to_save = FALSE;\n\n\treturn( NULL );\n}\n\nstatic void *\nrow_set_to_save( Row *row )\n{\n\tRow *enclosing;\n\n\tif( !row->to_save ) {\n\t\trow->to_save = TRUE;\n\n\t\t/* All peers must be saved. When we reload, we want to keep\n\t\t * row ordering. If we just save modded row, they'll move to\n\t\t * the front of the row list on reload, since they'll be made\n\t\t * first.\n\t\t */\n\t\ticontainer_map( ICONTAINER( row->scol ),\n\t\t\t(icontainer_map_fn) row_set_to_save, NULL, NULL );\n\n\t\t/* All rows back up to the top level must also be saved.\n\t\t */\n\t\tfor( enclosing = row; enclosing != row->top_row; \n\t\t\tenclosing = row_get_parent( enclosing ) )\n\t\t\trow_set_to_save( enclosing );\n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\nrow_calculate_to_save( Model *model )\n{\n\tif( IS_ROW( model ) ) {\n\t\tRow *row = ROW( model );\n\t\tRhs *rhs = row->child_rhs;\n\n\t\tif( row != row->top_row && rhs && !row->to_save ) {\n\t\t\tif( rhs->itext && ITEXT( rhs->itext )->edited )\n\t\t\t\trow_set_to_save( row );\n\t\t\telse if( rhs->graphic && \n\t\t\t\tCLASSMODEL( rhs->graphic )->edited )\n\t\t\t\trow_set_to_save( row );\n\t\t}\n\t}\n\n\treturn( NULL );\n}\n\nstatic gboolean\nrow_save_test( Model *model )\n{\n\tRow *row = ROW( model );\n\tWorkspace *ws = row->ws;\n\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\n\tgboolean save;\n\n\tif( row == row->top_row ) {\n\t\t/* This is a top-level row ... save unless we're in\n\t\t * only-save-selected mode.\n\t\t */\n\t\tif( wsg->save_type == WORKSPACEGROUP_SAVE_SELECTED )\n\t\t\tsave = row->selected;\n\t\telse\n\t\t\tsave = TRUE;\n\n\t\t/* If we're going to save this row, clear all the to_save\n\t\t * flags, then walk the tree working out which bits we will need\n\t\t * to write.\n\t\t */\n\t\tif( save ) {\n\t\t\ticontainer_map_all( ICONTAINER( row ),\n\t\t\t\t(icontainer_map_fn) row_clear_to_save, NULL );\n\t\t\ticontainer_map_all( ICONTAINER( row ),\n\t\t\t\t(icontainer_map_fn) row_calculate_to_save, \n\t\t\t\tNULL );\n\t\t}\n\t}\n\telse \n\t\tsave = row->to_save;\n\n\treturn( save );\n}\n\nstatic void *\nrow_new_heap( Heapmodel *heapmodel, PElement *root )\n{\n\tRow *row = ROW( heapmodel );\n\tExpr *expr = row->expr;\n\n#ifdef DEBUG\n\tprintf( \"row_new_heap: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n\n\tprintf( \"row_new_heap: new value is \" );\n\tpgraph( root );\n\n\tprintf( \"row_new_heap: top value is \" );\n\tpgraph( &row->top_row->expr->root );\n#endif /*DEBUG*/\n\n\tif( row_is_displayable( row->sym ) ) {\n\t\t/* Hide superclasses whose constructor starts with \"_\".\n\t\t */\n\t\tif( is_super( row->sym ) && PEISCLASS( root ) &&\n\t\t\t*IOBJECT( PEGETCLASSCOMPILE( root )->sym )->name == \n\t\t\t'_' )\n\t\t\tmodel_display( MODEL( row ), FALSE );\n\t}\n\n\t/* New value ... reset error state.\n\t */\n\texpr_error_clear( expr );\n\texpr->root = *root;\n\texpr_new_value( expr );\n\n\tif( row->child_rhs &&\n\t\theapmodel_new_heap( HEAPMODEL( row->child_rhs ), root ) )\n\t\treturn( row );\n\n\t/* Class display only for non-param classes.\n\t */\n\trow->is_class = PEISCLASS( root ) && row->sym->type != SYM_PARAM;\n\n\t/* Set the default vis level.\n\t */\n\tif( row->child_rhs && row->child_rhs->vislevel == -1 ) {\n\t\tPElement member;\n\t\tdouble value;\n\t\tgboolean is_class;\n\n\t\tif( !heap_is_class( root, &is_class ) )\n\t\t\treturn( row );\n\n\t\t/* If it's a class with a vis hint, use that.\n\t\t */\n\t\tif( is_class && \n\t\t\tclass_get_member( root, MEMBER_VISLEVEL, \n\t\t\t\tNULL, &member ) &&\n\t\t\theap_get_real( &member, &value ) ) \n\t\t\trhs_set_vislevel( row->child_rhs, value );\n\n\t\t/* Non-parameter rows get higher vislevel, except for super. \n\t\t */\n\t\telse if( row->sym->type != SYM_PARAM && !is_super( row->sym ) )\n\t\t\trhs_set_vislevel( row->child_rhs, 1 );\n\t\telse \n\t\t\trhs_set_vislevel( row->child_rhs, 0 );\n\t}\n\n\treturn( HEAPMODEL_CLASS( parent_class )->new_heap( heapmodel, root ) ); }\n\nstatic void *\nrow_update_model( Heapmodel *heapmodel )\n{\n\tRow *row = ROW( heapmodel );\n\n\tif( row->expr )\n\t\texpr_new_value( row->expr );\n\n\treturn( HEAPMODEL_CLASS( parent_class )->update_model( heapmodel ) );\n}\n\nstatic void\nrow_class_init( RowClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tiContainerClass *icontainer_class = (iContainerClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tHeapmodelClass *heapmodel_class = (HeapmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->dispose = row_dispose;\n\n\tiobject_class->info = row_info;\n\n\ticontainer_class->child_add = row_child_add;\n\ticontainer_class->parent_add = row_parent_add;\n\ticontainer_class->parent_remove = row_parent_remove;\n\n\tmodel_class->view_new = row_view_new;\n\tmodel_class->scrollto = row_scrollto;\n\tmodel_class->load = row_load;\n\tmodel_class->save = row_save;\n\tmodel_class->save_test = row_save_test;\n\n\theapmodel_class->new_heap = row_new_heap;\n\theapmodel_class->update_model = row_update_model;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\nrow_init( Row *row )\n{\n#ifdef DEBUG\n\tprintf( \"row_init\\n\" );\n#endif /*DEBUG*/\n\n\trow->scol = NULL;\n\trow->child_rhs = NULL;\n\trow->top_col = NULL;\n\trow->ws = NULL;\n\trow->top_row = NULL;\n\n\trow->sym = NULL;\n\n\trow->expr = NULL;\n\trow->err = FALSE;\n\n\trow->selected = FALSE;\n\trow->is_class = FALSE;\n\trow->popup = POPUP_NEW_ROWS;\n\trow->to_save = FALSE;\n\n\t/* Init recomp stuff.\n\t */\n\trow->parents = NULL;\n\trow->children = NULL;\n\trow->dirty = FALSE;\n\trow->recomp = NULL;\n\trow->recomp_save = NULL;\n\n\trow->depend = FALSE;\n\n\trow->show = ROW_SHOW_NONE;\n}\n\nGType\nrow_get_type( void )\n{\n\tstatic GType row_type = 0;\n\n\tif( !row_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( RowClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) row_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Row ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) row_init,\n\t\t};\n\n\t\trow_type = g_type_register_static( TYPE_HEAPMODEL, \n\t\t\t\"Row\", &info, 0 );\n\t}\n\n\treturn( row_type );\n}\n\n/* After making a row and adding it to model tree ... attach the symbol and\n * value this row displays.\n */\nvoid\nrow_link_symbol( Row *row, Symbol *sym, PElement *root )\n{\n\tg_assert( !row->sym );\n\tg_assert( !row->expr );\n\tg_assert( !sym->expr || !sym->expr->row );\n\n\trow->sym = sym;\n\n\t/* Code we display/update ... if this is a top-level row, we\n\t * directly change the symbol's expr. If it's a sub-row, we need a\n\t * cloned expr for us to fiddle with.\n\t */\n\tif( is_top( sym ) ) {\n\t\trow->expr = sym->expr;\n\t\tg_assert( !row->expr->row );\n\t\trow->expr->row = row;\n\t}\n\telse {\n\t\trow->expr = expr_clone( sym );\n\t\trow->expr->row = row;\n\n\t\tif( root ) {\n\t\t\trow->expr->root = *root;\n\t\t\texpr_new_value( row->expr );\n\t\t}\n\t}\n}\n\nRow *\nrow_new( Subcolumn *scol, Symbol *sym, PElement *root )\n{\n\tRow *row = g_object_new( TYPE_ROW, NULL );\n\n#ifdef DEBUG_NEW\n\tprintf( \"row_new: \" );\n\tdump_tiny( sym );\n\tprintf( \"\\n\" );\n#endif /*DEBUG_NEW*/\n\n\t/* Don't make a display or a RHS for invisible rows.\n\t */\n\tif( !row_is_displayable( sym ) )\n\t\tMODEL( row )->display = FALSE;\n\telse \n\t\t(void) rhs_new( row ); \n\n\tiobject_set( IOBJECT( row ), IOBJECT( sym )->name, NULL );\n\ticontainer_child_add( ICONTAINER( scol ), ICONTAINER( row ), -1 );\n\n\trow_link_symbol( row, sym, root );\n\n\treturn( row );\n}\n\n/* Make a dependency. parent is displaying an expression which \n * refers to the symbol being displayed by child.\n */\nstatic void *\nrow_link_make( Row *parent, Row *child )\n{\n\t/* Already a dependency? Don't make a second link.\n\t */\n\tif( g_slist_find( parent->children, child ) ) \n\t\treturn( NULL );\n\n\t/* Don't link to self (harmless, but pointless too).\n\t */\n\tif( parent == child )\n\t\treturn( NULL );\n\t\n\t/* New link, each direction.\n\t */\n\tparent->children = g_slist_prepend( parent->children, child );\n\tchild->parents = g_slist_prepend( child->parents, parent );\n\n#ifdef DEBUG_LINK\n\tprintf( \"row_link_make: \" );\n\trow_name_print( parent );\n\tprintf( \"refers to \" );\n\trow_name_print( child );\n\tprintf( \"\\n\" );\n#endif /*DEBUG_LINK*/\n\n\treturn( NULL );\n}\n\nstatic void *\nrow_link_build4( Expr *child_expr, Row *row )\n{\n\tif( child_expr->row && child_expr->row->top_row == row )\n\t\treturn( child_expr->row );\n\n\treturn( NULL );\n}\n\n/* Does child have a display in the same tally heirarchy as row? Make a link!\n */\nstatic void *\nrow_link_build3( Symbol *child, Row *row )\n{\n\tRow *child_row;\n\n\tchild_row = (Row *) icontainer_map( ICONTAINER( child ),\n\t\t(icontainer_map_fn) row_link_build4, row->top_row, NULL );\n\n\tif( child_row ) \n\t\t(void) row_link_make( row, child_row );\n\n\treturn( NULL );\n}\n\nstatic void *row_link_build2( Expr *expr, Row *row );\n\nstatic void *\nrow_link_build2_sym( Symbol *sym, Row *row )\n{\n\tif( sym->expr && row_link_build2( sym->expr, row ) )\n\t\treturn( row );\n\t\n\treturn( NULL );\n}\n\nstatic void *\nrow_link_build2( Expr *expr, Row *row )\n{\n\t/* Make links to anything expr refers to in this tree.\n\t */\n\tif( expr->compile &&\n\t\tslist_map( expr->compile->children, \n\t\t\t(SListMapFn) row_link_build3, row ) )\n\t\treturn( expr );\n\n\t/* Recurse for any locals of expr. \n\t * Exception: \n\t * \n\t *\tf = class {\n\t *\t\tg = class {\n\t *\t\t\ta = 12;\n\t *\t\t}\n\t *\t}\n\t *\n\t * zero-arg local classes will have rows anyway, so we don't need to\n\t * check inside them for locals, since we'll do them anyway at the top\n\t * level.\n\t *\n\t * zero-arg hidden classes do need to be checked inside though :-(\n\t * since we will only have a row for the top element.\n\t */\n\tif( expr->compile && \n\t\t!(is_class( expr->compile ) && expr->compile->nparam == 0 &&\n\t\t\texpr->row && MODEL( expr->row )->display) &&\n\t\ticontainer_map( ICONTAINER( expr->compile ),\n\t\t\t(icontainer_map_fn) row_link_build2_sym, row, NULL ) )\n\t\treturn( expr );\n\n\treturn( NULL );\n}\n\n/* Scan a row, adding links for any dependencies we find.\n */\nstatic void *\nrow_link_build( Row *row )\n{\n#ifdef DEBUG_LINK\n\tprintf( \"row_link_build: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG_LINK*/\n\n\t/* Build new recomp list. Only for class displays.\n\t */\n\tif( !row->scol->is_top && row->expr && \n\t\trow_link_build2( row->expr, row ) )\n\t\treturn( row );\n\n\treturn( NULL );\n}\n\n/* Remove any links on a row.\n */\nstatic void *\nrow_link_destroy( Row *row )\n{\n\tslist_map( row->children, \n\t\t(SListMapFn) row_link_break_rev, row );\n\n\treturn( NULL );\n}\n\nstatic void *row_dependent_map_sub( Row *row, row_map_fn fn, void *a );\n\n/* Do this row, and any that depend on it.\n */\nstatic void *\nrow_dependent_mark( Row *row, row_map_fn fn, void *a )\n{\n\tvoid *res;\n\n\t/* Done this one already?\n\t */\n\tif( row->depend )\n\t\treturn( NULL );\n\n\trow->depend = TRUE;\n\tif( (res = fn( row, a, NULL, NULL )) )\n\t\treturn( res );\n\n\treturn( row_dependent_map_sub( row, fn, a ) );\n}\n\n/* Apply to all dependents of row.\n */\nstatic void *\nrow_dependent_map_sub( Row *row, row_map_fn fn, void *a )\n{\n\tRow *i;\n\tvoid *res;\n\n\t/* Things that refer to us.\n\t */\n\tif( (res = slist_map2( row->parents, \n\t\t(SListMap2Fn) row_dependent_mark, (void *) fn, a )) )\n\t\treturn( res );\n\n\t/* Things that refer to our enclosing syms ... eg. if A1.fred.x \n\t * changes, we don't want to recalc A1.fred, we do want to recalc \n\t * anything that refers to A1.fred.\n\t */\n\tfor( i = row; (i = HEAPMODEL( i )->row); ) \n\t\tif( (res = row_dependent_map_sub( i, fn, a )) )\n\t\t\treturn( res );\n\n\t/* We are not going to spot things that refer to this.us :-( we could\n\t * say anything that depends on \"this\" depends on us, but that's much \n\t * too broad (and much too slow).\n\n\t \tFIXME ... could use dynamic dependency stuff to find things\n\t\tthat refer to this.us?\n\t */\n\n\treturn( NULL );\n}\n\nstatic void *\nrow_dependent_clear( Row *row )\n{\n\trow->depend = FALSE;\n\n\treturn( NULL );\n}\n\n/* Apply a function to all rows in this tree which depend on this row.\n */\nvoid *\nrow_dependent_map( Row *row, row_map_fn fn, void *a )\n{\n\t/* Clear the flags we use to spot loops.\n\t */\n\trow_map_all( row->top_row,\n\t\t(row_map_fn) row_dependent_clear, NULL, NULL, NULL );\n\n\treturn( row_dependent_map_sub( row, fn, a ) );\n}\n\n/* This row has changed ... mark all dependents (direct and indirect) \n * dirty.\n */\nvoid *\nrow_dirty( Row *row, gboolean clear_error )\n{\n\t(void) row_dirty_set( row, clear_error );\n\t(void) row_dependent_map( row, \n\t\t(row_map_fn) row_dirty_set, GINT_TO_POINTER( clear_error ) );\n\n\treturn( NULL );\n}\n\n/* This tally has changed ... mark all dependents (but not this one!)\n * dirty.\n */\nvoid *\nrow_dirty_intrans( Row *row, gboolean clear_error )\n{\n\t(void) row_dependent_map( row, \n\t\t(row_map_fn) row_dirty_set, GINT_TO_POINTER( clear_error ) );\n\n\treturn( NULL );\n}\n\n/* Find the 'depth' of a row ... 0 is top level.\n */\nstatic int\nrow_recomp_depth( Row *row )\n{\n\tif( row == row->top_row )\n\t\treturn( 0 );\n\n\treturn( 1 + row_recomp_depth( row_get_parent( row ) ) );\n}\n\n/* Compare func for row recomp sort.\n */\nstatic int\nrow_recomp_sort_func( Row *a, Row *b )\n{\n\tint order;\n#ifdef DEBUG_TIME_SORT\n\tstatic GTimer *sort_func_timer = NULL;\n\n\tif( !sort_func_timer )\n\t\tsort_func_timer = g_timer_new();\n\n\tg_timer_reset( sort_func_timer );\n#endif /*DEBUG_TIME_SORT*/\n\n#ifdef DEBUG_SORT_VERBOSE\n\tprintf( \"row_recomp_sort_func: \" );\n#endif /*DEBUG_SORT_VERBOSE*/\n\n\t/* If b depends on a, want a first.\n\t */\n\tif( row_dependent_map( a, (row_map_fn) map_equal, b ) ) {\n#ifdef DEBUG_SORT_VERBOSE\n\t\trow_name_print( a );\n\t\tprintf( \"before \" );\n\t\trow_name_print( b );\n\t\tprintf( \"(2nd depends on 1st)\\n\" );\n#endif /*DEBUG_SORT_VERBOSE*/\n\n\t\torder = -1;\n\t}\n\telse if( row_dependent_map( b, (row_map_fn) map_equal, a ) ) {\n#ifdef DEBUG_SORT_VERBOSE\n\t\trow_name_print( b );\n\t\tprintf( \"before \" );\n\t\trow_name_print( a );\n\t\tprintf( \"(2nd depends on 1st #2)\\n\" );\n#endif /*DEBUG_SORT_VERBOSE*/\n\n\t\torder = 1;\n\t}\n\telse {\n\t\tint adepth = row_recomp_depth( a );\n\t\tint bdepth = row_recomp_depth( b );\n\n#ifdef DEBUG_SORT_VERBOSE\n\t\tif( adepth < bdepth ) {\n\t\t\trow_name_print( a );\n\t\t\tprintf( \"before \" );\n\t\t\trow_name_print( b );\n\t\t\tprintf( \"(1st shallower)\\n\" );\n\t\t}\n\t\telse if( bdepth < adepth ) {\n\t\t\trow_name_print( b );\n\t\t\tprintf( \"before \" );\n\t\t\trow_name_print( a );\n\t\t\tprintf( \"(1st shallower)\\n\" );\n\t\t}\n\t\telse {\n\t\t\trow_name_print( a );\n\t\t\tprintf( \"and \" );\n\t\t\trow_name_print( b );\n\t\t\tprintf( \"independent\\n\" );\n\t\t}\n#endif /*DEBUG_SORT_VERBOSE*/\n\n\t\t/* No dependency ... want shallower first.\n\t\t */\n\t\torder = adepth - bdepth;\n\t}\n\n#ifdef DEBUG_TIME_SORT\n\tprintf( \"row_recomp_sort_func: took %gs\\n\",  \n\t\tg_timer_elapsed( sort_func_timer, NULL ) );\n#endif /*DEBUG_TIME_SORT*/\n\n\treturn( order );\n}\n\n/* Insert-sort an slist.\n */\nstatic GSList *\nrow_recomp_sort_slist( GSList *old )\n{\n\tGSList *new;\n\tGSList *p;\n\n\tnew = NULL;\n\n\tfor( p = old; p; p = p->next ) {\n\t\tRow *a = (Row *) p->data;\n\t\tRow *b;\n\t\tGSList *q;\n\n\t\tfor( q = new; q; q = q->next ) {\n\t\t\tb = (Row *) q->data;\n\n\t\t\tif( row_recomp_sort_func( a, b ) < 0 )\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif( q ) {\n\t\t\tq->data = a;\n\t\t\tq->next = g_slist_prepend( q->next, b );\n\t\t}\n\t\telse\n\t\t\tnew = g_slist_append( new, a );\n\t}\n\n\tg_slist_free( old );\n\n\treturn( new );\n}\n\n/* Sort dirties into recomp order.\n */\nstatic void\nrow_recomp_sort( Row *row )\n{\n#ifdef DEBUG_TIME_SORT\n\tstatic GTimer *sort_timer = NULL;\n\n\tif( !sort_timer )\n\t\tsort_timer = g_timer_new();\n\n\tg_timer_reset( sort_timer );\n#endif /*DEBUG_TIME_SORT*/\n\n\tg_assert( row == row->top_row );\n\n\t/* Nope, can't use g_slist_sort(). We have a partial order and\n\t * g_slist_sort() uses an algorithm that assumes a full order. Do a\n\t * simple insert-sort, it'll do enough comparisons that we won't miss\n\t * things.\n\n\t\trow->recomp = g_slist_sort( row->recomp, \n\t\t\t(GCompareFunc) row_recomp_sort_func );\n\n\t */\n\trow->recomp = row_recomp_sort_slist( row->recomp );\n\n#ifdef DEBUG_TIME_SORT\n\tprintf( \"row_recomp_sort: took %gs\\n\",  \n\t\tg_timer_elapsed( sort_timer, NULL ) );\n#endif /*DEBUG_TIME_SORT*/\n\n#ifdef DEBUG_SORT\n\tprintf( \"row_recomp: sorted dirties are: \" );\n\tslist_map( row->recomp, (SListMapFn) row_name_print, NULL );\n\tprintf( \"\\n\" );\n#endif /*DEBUG_SORT*/\n}\n\nstatic gboolean\nrow_regenerate( Row *row )\n{\n\tExpr *expr = row->expr;\n\tPElement base;\n\n\t/* Regenerate any compiled code.\n\t */\n\tif( expr->compile ) {\n\t\tPEPOINTE( &base, &expr->compile->base );\n\n\t\tif( !PEISNOVAL( &base ) ) {\n\t\t\tPElement *root = &expr->root;\n\n\t\t\tif( row == row->top_row ) {\n\t\t\t\t/* Recalcing base of tally display ... not a \n\t\t\t\t * class member, must be a sym with a value.\n\t\t\t\t */\n\t\t\t\tgboolean res;\n\n\t\t\t\tres = reduce_regenerate( expr, root );\n\t\t\t\texpr_new_value( expr );\n\n\t\t\t\tif( !res )\n\t\t\t\t\treturn( FALSE );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t/* Recalcing a member somewhere inside ... \n\t\t\t\t * regen (member this) pair. Get the \"this\"\n\t\t\t\t * for the enclosing class instance ... the\n\t\t\t\t * top one won't always be right (eg. for\n\t\t\t\t * local classes); the enclosing one should\n\t\t\t\t * be the same as the most enclosing this.\n\t\t\t\t */\n\t\t\t\tRow *this = row->scol->this;\n\t\t\t\tgboolean res;\n\n\t\t\t\tres = reduce_regenerate_member( expr, \n\t\t\t\t\t&this->expr->root, root );\n\t\t\t\texpr_new_value( expr );\n\n\t\t\t\tif( !res )\n\t\t\t\t\treturn( FALSE );\n\t\t\t}\n\n\t\t\t/* We may have made a new class instance ... all our \n\t\t\t * children need to update their heap pointers.\n\t\t\t */\n\t\t\tif( heapmodel_new_heap( HEAPMODEL( row ), root ) ) \n\t\t\t\treturn( FALSE );\n\t\t}\n\t}\n\n\treturn( TRUE );\n}\n\nstatic gboolean\nrow_recomp_row( Row *row )\n{\n\tRhs *rhs = row->child_rhs;\n\n#ifdef DEBUG\n\tprintf( \"row_recomp_row: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Not much we can do. \n\t */\n\tif( !row->expr )\n\t\treturn( TRUE );\n\n\t/* Clear old error state.\n\t */\n\texpr_error_clear( row->expr );\n\n\t/* Parse and compile any changes to our text since we last came through.\n\t */\n\tif( rhs && rhs->itext && \n\t\theapmodel_update_heap( HEAPMODEL( rhs->itext ) ) ) \n\t\treturn( FALSE );\n\n\t/* We're about to zap the graph: make sure this tree of rows has a\n\t * private copy.\n\t */\n\tif( !subcolumn_make_private( row->scol ) )\n\t\treturn( FALSE );\n\n\t/* Regenerate from the expr.\n\t */\n\tif( !row_regenerate( row ) ) \n\t\treturn( FALSE );\n\n\t/* Reapply any graphic mods.\n\t */\n\tif( rhs && rhs->graphic ) {\n\t\tClassmodel *classmodel = CLASSMODEL( rhs->graphic );\n\n\t\t/* If the graphic is non-default, need to set modified to make\n\t\t * sure we reapply the changes.\n\t\t */\n\t\tif( classmodel->edited )\n\t\t\theapmodel_set_modified( HEAPMODEL( classmodel ), TRUE );\n\n\t\tif( heapmodel_update_heap( HEAPMODEL( classmodel ) ) )\n\t\t\treturn( FALSE );\n\t}\n\n\tprogress_update_tick();\n\n\treturn( TRUE );\n}\n\nstatic void\nrow_recomp_all( Row *top_row )\n{\n\t/* Rebuild all dirty rows.\n\t */\n\twhile( !top_row->err && top_row->recomp ) {\n\t\tRow *dirty_row = ROW( top_row->recomp->data );\n\n#ifdef DEBUG_ROW\n\t\tstatic GTimer *timer = NULL;\n\n\t\tif( !timer )\n\t\t\ttimer = g_timer_new();\n\t\tg_timer_reset( timer );\n#endif /*DEBUG_ROW*/\n\n#ifdef DEBUG_ROW\n\t\tprintf( \"row_recomp_all: starting \" );\n\t\trow_name_print( dirty_row );\n\t\tprintf( \"\\n\" ); \n#endif /*DEBUG_ROW*/\n\n\t\tif( !row_recomp_row( dirty_row ) ) {\n\t\t\t/* This will set top_row->err and end the loop.\n\t\t\t */\n\t\t\tif( dirty_row->expr ) \n\t\t\t\texpr_error_set( dirty_row->expr );\n\t\t}\n\t\telse\n\t\t\trow_dirty_clear( dirty_row );\n\n#ifdef DEBUG_ROW\n\t\tprintf( \"\\t%gs\\n\", g_timer_elapsed( timer, NULL ) );\n#endif /*DEBUG_ROW*/\n\n#ifdef DEBUG\n\t\tprintf( \"row_recomp_all: after row recomp, top value now \" );\n\t\tpgraph( &top_row->expr->root );\n#endif /*DEBUG*/\n\t}\n}\n\nvoid\nrow_recomp( Row *row )\n{\n\tRow *top_row = row->top_row;\n\n\tstatic GTimer *recomp_timer = NULL;\n\n\tif( !recomp_timer )\n\t\trecomp_timer = g_timer_new();\n\n\tg_timer_reset( recomp_timer );\n\n\t/* Sort dirties into recomp order.\n\t */\n\trow_recomp_sort( top_row );\n\n\t/* Take a copy of the recomp list for later testing.\n\t */\n\tIM_FREEF( g_slist_free, top_row->recomp_save );\n\ttop_row->recomp_save = g_slist_copy( top_row->recomp );\n\n\t/* Remove all top-level dependencies.\n\t */\n\tsymbol_link_destroy( top_row->sym );\n\n\t/* Remove any row recomp links we have.\n\t */\n\t(void) row_map_all( top_row,\n\t\t(row_map_fn) row_link_destroy, NULL, NULL, NULL );\n\n\t/* Rebuild all dirty rows. This may add some dynamic top links.\n\t */\n\trow_recomp_all( top_row );\n\n\t/* Our workspace may have been closed in a callback: bail out.\n\t */\n\tif( !top_row->sym )\n\t\treturn;\n\n\t/* Add all static row links. Have to do this after any \n\t * parsing in row_recomp_all().\n\t */\n\t(void) row_map_all( top_row,\n\t\t(row_map_fn) row_link_build, NULL, NULL, NULL );\n\n\t/* Remake all static top-level links.\n\t */\n\t(void) symbol_link_build( top_row->sym );\n\n\t/* Now we know dependencies ... mark everything dirty again. This may\n\t * pick up stuff we missed last time and may change the order we\n\t * recomp rows in.\n\t *\n\t * Be careful not to wipe out any errors we found on this first pass.\n\t */\n\tslist_map( top_row->recomp_save, (SListMapFn) row_dirty, FALSE );\n\n\t/* Is this topsym still a leaf? We may have discovered an external \n\t * reference to another dirty top-level sym. We can come back here\n\t * later.\n\t */\n\tif( top_row->sym->ndirtychildren != 0 ) {\n\t\tIM_FREEF( g_slist_free, top_row->recomp_save );\n\t\treturn;\n\t}\n\n\t/* Sort dirties into recomp order.\n\t */\n\trow_recomp_sort( top_row );\n\n\t/* Now: if the recomp list is the same as last time, we don't need to\n\t * recalc again.\n\t */\n\tif( slist_equal( top_row->recomp_save, top_row->recomp ) ) {\n\t\t/* Provided we didn't abandon recomp on an error, we can \n\t\t * just mark all rows clean.\n\t\t */\n\t\tif( !top_row->err )\n\t\t\tslist_map( top_row->recomp, \n\t\t\t\t(SListMapFn) row_dirty_clear, NULL );\n\t}\n\telse {\n#ifdef DEBUG_DIRTY\n\t\tprintf( \"row_recomp: recomp list has changed ... pass 2\\n\" );\n#endif /*DEBUG_DIRTY*/\n\n\t\t/* Rebuild all dirty rows in a second pass.\n\t\t */\n\t\trow_recomp_all( top_row );\n\n\t\t/* Our workspace may have been closed in a callback: bail out.\n\t\t */\n\t\tif( !top_row->sym )\n\t\t\treturn;\n\t}\n\n\tIM_FREEF( g_slist_free, top_row->recomp_save );\n\n\t/* The symbol can be cleared as well.\n\t */\n\tif( !top_row->err )\n\t\tsymbol_dirty_clear( top_row->sym );\n\n\t/* Now we're clean, all models can update from the heap. Rows\n\t * containing errors can have bad pointers in, so careful.\n\t */\n\tif( !top_row->err && icontainer_map_all( ICONTAINER( top_row ),\n\t\t(icontainer_map_fn) heapmodel_update_model, NULL ) )\n\t\texpr_error_set( top_row->expr );\n\n\tif( main_option_profile ) { \n\t\tchar txt[100];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\t\tSymbol *context = symbol_get_parent( top_row->ws->sym );\n\n\t\trow_qualified_name_relative( context, top_row, &buf );\n\t\tprintf( \"%s\\t%g\\n\", vips_buf_all( &buf ), \n\t\t\tg_timer_elapsed( recomp_timer, NULL ) );\n\t}\n\n#ifdef DEBUG\n\tprintf( \"row_recomp: value of \" );\n\trow_name_print( top_row );\n\tprintf( \"is \" );\n\tpgraph( &top_row->expr->root );\n#endif /*DEBUG*/\n}\n\n/* Test, suitable for mapping.\n */\nvoid *\nrow_is_selected( Row *row )\n{\n\tif( row->selected )\n\t\treturn( row );\n\n\treturn( NULL );\n}\n\n/* Deselect a row. \n */\nvoid *\nrow_deselect( Row *row )\n{\n\tWorkspace *ws = row->ws;\n\n\tif( !row->selected )\n\t\treturn( NULL );\n\n\tg_assert( ws && IS_WORKSPACE( ws ) );\n\tg_assert( g_slist_find( ws->selected, row ) );\n\n\tws->selected = g_slist_remove( ws->selected, row );\n\trow->selected = FALSE;\n\n\t/* Hack: if this is a matrix with selected cells, deselect the matrix\n\t * sellection too. We should really have a row method for this I\n\t * guess :-( See also workspace_selected_names_sub().\n\t */\n\tif( row->child_rhs && row->child_rhs->graphic &&\n\t\tIS_MATRIX( row->child_rhs->graphic ) &&\n\t\tMATRIX( row->child_rhs->graphic )->selected ) \n\t\tmatrix_deselect( MATRIX( row->child_rhs->graphic ) );\n\n\tiobject_changed( IOBJECT( row ) );\n\tiobject_changed( IOBJECT( ws ) );\n\n\treturn( NULL );\n}\n\n/* Select a row. \n */\nstatic void\nrow_select2( Row *row )\n{\n\tif( !row->selected ) {\n\t\tWorkspace *ws = row->ws;\n\n\t\trow->selected = TRUE;\n\t\tws->selected = g_slist_append( ws->selected, row );\n\n\t\tiobject_changed( IOBJECT( row ) );\n\t\tiobject_changed( IOBJECT( ws ) );\n\t}\n}\n\n/* Make sure a row is selected ... used for (eg.) select changed on gktsheet.\n * No deselection.\n */\nvoid *\nrow_select_ensure( Row *row )\n{\n\trow_select2( row );\n\n\t/* Note for extend select.\n\t */\n\trow->top_col->last_select = row;\n\n\treturn( NULL );\n}\n\n/* Select a row, deselecting others first.\n */\nvoid *\nrow_select( Row *row )\n{\n\tWorkspace *ws = row->ws;\n\n\tworkspace_deselect_all( ws );\n\trow_select2( row );\n\n\t/* Note for extend select.\n\t */\n\trow->top_col->last_select = row;\n\n\treturn( NULL );\n}\n\n/* Extend the previous selection.\n */\nvoid *\nrow_select_extend( Row *row )\n{\n\tColumn *col = row->top_col;\n\tRow *last_select = col->last_select;\n\n\t/* Range select if there was a previous selection, and it was in the\n\t * same subcolumn.\n\t */\n\tif( last_select && row->scol == last_select->scol ) {\n\t\tSubcolumn *scol = row->scol;\n\t\tGSList *rows = ICONTAINER( scol )->children;\n\t\tint pos = g_slist_index( rows, row );\n\t\tint pos_last = g_slist_index( rows, last_select );\n\t\tint step = pos > pos_last ? 1 : -1;\n\t\tint i;\n\n\t\tg_assert( pos != -1 && pos_last != -1 );\n\n\t\tfor( i = pos_last; i != pos + step; i += step )\n\t\t\trow_select2( ROW( g_slist_nth_data( rows, i ) ) );\n\t}\n\telse \n\t\trow_select2( row );\n\n\t/* Note for extend select.\n\t */\n\tcol->last_select = row;\n\n\treturn( NULL );\n}\n\n/* Toggle a selection.\n */\nvoid *\nrow_select_toggle( Row *row )\n{\n\tif( row->selected ) {\n\t\trow_deselect( row );\n\t\trow->top_col->last_select = NULL;\n\t}\n\telse {\n\t\trow_select2( row );\n\t\trow->top_col->last_select = row;\n\t}\n\n\treturn( NULL );\n}\n\n/* Do a select action using a modifier.\n */\nvoid \nrow_select_modifier( Row *row, guint state )\n{\n\tif( state & GDK_CONTROL_MASK ) \n\t\trow_select_toggle( row );\n\telse if( state & GDK_SHIFT_MASK ) \n\t\trow_select_extend( row );\n\telse \n\t\trow_select( row );\n}\n\nstatic void\nrow_set_show( Row *row, RowShowState show )\n{\n\tif( row->show != show ) {\n\t\trow->show = show;\n\t\tiobject_changed( IOBJECT( row ) );\n\t}\n}\n\nstatic void *\nrow_show_parent( Link *link, RowShowState show )\n{\n\tif( link->parent->expr && link->parent->expr->row ) \n\t\trow_set_show( link->parent->expr->row, show );\n\n\treturn( NULL );\n}\n\nstatic void *\nrow_show_child( Link *link, RowShowState show )\n{\n\tif( link->child->expr && link->child->expr->row ) \n\t\trow_set_show( link->child->expr->row, show );\n\n\treturn( NULL );\n}\n\nvoid\nrow_show_dependents( Row *row )\n{\n\tSymbol *topsym = row->top_row->sym;\n\n#ifdef DEBUG\n\tprintf( \"row_show_dependents: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( topsym ) {\n\t\tslist_map( topsym->topparents,\n\t\t\t(SListMapFn) row_show_parent, \n\t\t\tGUINT_TO_POINTER( ROW_SHOW_PARENT ) );\n\t\tslist_map( topsym->topchildren,\n\t\t\t(SListMapFn) row_show_child, \n\t\t\tGUINT_TO_POINTER( ROW_SHOW_CHILD ) );\n\t}\n}\n\nvoid\nrow_hide_dependents( Row *row )\n{\n\tSymbol *topsym;\n\n#ifdef DEBUG\n\tprintf( \"row_hide_dependents: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tif( row->top_row && (topsym = row->top_row->sym) ) {\n\t\tslist_map( topsym->topparents,\n\t\t\t(SListMapFn) row_show_parent, \n\t\t\tGUINT_TO_POINTER( ROW_SHOW_NONE ) );\n\t\tslist_map( topsym->topchildren,\n\t\t\t(SListMapFn) row_show_child, \n\t\t\tGUINT_TO_POINTER( ROW_SHOW_NONE ) );\n\t}\n}\n\n/* Set help for a row. Used by rowview and itextview etc. on mouseover.\n */\nvoid\nrow_set_status( Row *row )\n{\n\tExpr *expr = row->expr;\n\n\tchar txt[MAX_LINELENGTH];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t/* No symbol? eg. on load error.\n\t */\n\tif( !expr )\n\t\treturn;\n\n\trow_qualified_name( row, &buf );\n\n\tif( expr->err ) {\n\t\tvips_buf_appends( &buf, \": \" );\n\t\tvips_buf_appends( &buf, expr->error_top );\n\t}\n\telse if( row->child_rhs->itext ) {\n\t\tiText *itext = ITEXT( row->child_rhs->itext );\n\n\t\tvips_buf_appends( &buf, \" = \" );\n\n\t\tif( row->ws && \n\t\t\trow->ws->mode != WORKSPACE_MODE_FORMULA )\n\t\t\tvips_buf_appends( &buf, NN( itext->formula ) );\n\t\telse \n\t\t\tvips_buf_appends( &buf, vips_buf_all( &itext->value ) );\n\t}\n\n\tworkspace_set_status( row->ws, \"%s\", vips_buf_firstline( &buf ) );\n}\n\n/* Sub fn of below ... search inside a row hierarcy. Context is (eg.) row\n * \"A1\", path is (eg.) \"super.name\".\n */\nstatic Row *\nrow_parse_name_row( Row *context, const char *path )\n{\n\tchar name[256];\n\tchar *tail;\n\tRow *row;\n\tSubcolumn *scol;\n\n#ifdef DEBUG\n\tprintf( \"row_parse_name_row: \\\"%s\\\"\\n\", path );\n#endif /*DEBUG*/\n\n\t/* Break the name into \"thing.tail\", where tail could contain other\n\t * \".\" qualifiers.\n\t */\n\tim_strncpy( name, path, 256 );\n\tif( !(tail = break_token( name, \".\" )) )\n\t\t/* Passed empty string.\n\t\t */\n\t\treturn( context );\n\n\t/* Needs to be a subcolumn to look inside. We could search the value,\n\t * but it's safer to look inside the model we've built from the value.\n\t */\n\tif( !context->child_rhs ||\n\t\t!context->child_rhs->scol ||\n\t\t!(scol = SUBCOLUMN( context->child_rhs->scol )) )\n\t\treturn( NULL );\n\n\tif( !(row = subcolumn_map( scol, \n\t\t(row_map_fn) iobject_test_name, name, NULL )) )\n\t\treturn( NULL );\n\n\treturn( row_parse_name_row( row, tail ) );\n}\n\n/* Parse a qualified name .. eg. \"untitled.A1.name\" and find the row. Find\n * relative to context. Context is a sym, so we can have workspaceroot etc.\n */\nRow *\nrow_parse_name( Symbol *context, const char *path )\n{\n\tchar name[256];\n\tchar *tail;\n\tSymbol *sym;\n\tRow *row;\n\n#ifdef DEBUG\n\tprintf( \"row_parse_name: \\\"%s\\\"\\n\", path );\n#endif /*DEBUG*/\n\n\t/* Break the name into \"thing.tail\", where tail could contain other\n\t * \".\" qualifiers.\n\t */\n\tim_strncpy( name, path, 256 );\n\tif( !(tail = break_token( name, \".\" )) ) {\n\t\t/* Run out of names ... return this row, if we've found one.\n\t\t */\n\t\tif( context->expr )\n\t\t\treturn( context->expr->row );\n\t\telse\n\t\t\treturn( NULL );\n\t}\n\n\t/* Try to look up name in context. For scopes, we can do it\n\t * statically. For other syms, look up in the value of the symbol.\n\t */\n\tswitch( context->type ) {\n\tcase SYM_WORKSPACE:\n\tcase SYM_WORKSPACEROOT:\n\tcase SYM_ROOT:\n\t\tif( !(sym = compile_lookup( context->expr->compile, name )) ) \n\t\t\treturn( NULL );\n\t\tbreak;\n\n\tcase SYM_VALUE:\n\t\tif( !(row = context->expr->row) )\n\t\t\treturn( NULL );\n\n\t\t/* Hand off to the row searcher.\n\t\t */\n\t\treturn( row_parse_name_row( row, path ) );\n\n\tcase SYM_ZOMBIE:\n\tcase SYM_PARAM:\n\tcase SYM_EXTERNAL:\n\tcase SYM_BUILTIN:\n\tdefault:\n\t\t/* How odd.\n\t\t */\n\t\treturn( NULL );\n\t}\n\n\treturn( row_parse_name( sym, tail ) );\n}\n"
  },
  {
    "path": "src/row.h",
    "content": "/* a row in a workspace ... part of a subcolumn\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_ROW (row_get_type())\n#define ROW( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_ROW, Row ))\n#define ROW_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_ROW, RowClass))\n#define IS_ROW( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_ROW ))\n#define IS_ROW_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_ROW ))\n#define ROW_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_ROW, RowClass ))\n\n/* For when we're flashing the showstate up.\n */\ntypedef enum {\n\tROW_SHOW_NONE,\n\tROW_SHOW_PARENT,\n\tROW_SHOW_CHILD\n} RowShowState;\n\nstruct _Row {\n\tHeapmodel parent_class;\n\n\t/* Our context.\n\t */\n\tSubcolumn *scol;\t/* Enclosing subcolumn */\n\tRhs *child_rhs;\t\t/* Child RHS */\n\tColumn *top_col;\t/* Enclosing top level column */\n\tWorkspace *ws;\t\t/* Enclosing workspace */\n\tRow *top_row;\t\t/* Enclosing root row */\n\n\tSymbol *sym;\t\t/* Symbol we represent */\n\n\tExpr *expr;\t\t/* The expr we edit */\n\tgboolean err;\t\t/* Set if this row is on the error list */\n\n\tgboolean selected;\t/* Selected or not */\n\tgboolean is_class;\t/* Display spin buttons */\n\tgboolean popup;\t\t/* Set to pop up view on 1st display */\n\tgboolean to_save;\t/* Should be saved (part of only-save-modded) */\n\n\tGSList *parents;\t/* rows which depend on us */\n\tGSList *children;\t/* rows we depend on */\n\tgboolean dirty;\t\t/* If we're marked for recomp */\n\tGSList *recomp;\t\t/* If root of class display, subs to recomp */\n\tGSList *recomp_save;\t/* Previous recomp list */\n\n\tgboolean depend;\t/* For spotting dependency loops */\n\n\tRowShowState show;\t/* For showing parent/child stuff */\n};\n\ntypedef struct _RowClass {\n\tHeapmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} RowClass;\n\nconst char *row_name( Row *row );\nvoid row_qualified_name_relative( Symbol *context, Row *row, VipsBuf *buf );\nvoid row_qualified_name( Row *row, VipsBuf *buf );\nvoid *row_name_print( Row *row );\n\nvoid row_error_set( Row *row );\nvoid row_error_clear( Row *row );\n\nWorkspace *row_get_workspace( Row *row );\n\nGType row_get_type( void );\nvoid row_link_symbol( Row *row, Symbol *sym, PElement *root );\nRow *row_new( Subcolumn *scol, Symbol *sym, PElement *root );\n\nvoid *row_dirty( Row *row, gboolean clear_dirty );\nvoid *row_dirty_intrans( Row *row, gboolean clear_dirty );\n\nvoid row_recomp( Row *row );\n\nvoid *row_is_selected( Row *row );\nvoid *row_deselect( Row *row );\nvoid *row_select_ensure( Row *row );\nvoid *row_select( Row *row );\nvoid *row_select_extend( Row *row );\nvoid *row_select_toggle( Row *row );\nvoid row_select_modifier( Row *row, guint state );\n\nvoid row_show_dependents( Row *row );\nvoid row_hide_dependents( Row *row );\nvoid row_set_status( Row *row );\n\nRow *row_parse_name( Symbol *context, const char *path );\n\n"
  },
  {
    "path": "src/rowview.c",
    "content": "/* A rowview in a workspace ... not a widget, part of column\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ModelClass *parent_class = NULL;\n\nenum {\n\tROWVIEW_TARGET_STRING,\n};\n\nstatic GtkTargetEntry rowview_target_table[] = {\n\t{ \"STRING\", 0, ROWVIEW_TARGET_STRING },\n\t{ \"text/plain\", 0, ROWVIEW_TARGET_STRING }\n};\n\n/* Just one popup for all tally buttons.\n */\nstatic GtkWidget *rowview_popup_menu = NULL;\n\nstatic void \nrowview_destroy( GtkObject *object )\n{\n\tRowview *rview;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_ROWVIEW( object ) );\n\n\trview = ROWVIEW( object );\n\n#ifdef DEBUG\n\tprintf( \"rowview_destroy: \" );\n\trow_name_print( ROW( VOBJECT( rview )->iobject ) );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tIM_FREE( rview->last_tooltip );\n\n\t/* Kill children ... must do this ourselves, since we are not a\n\t * self-contained widget.\n\t */\n\tDESTROY_GTK( rview->but );\n\tDESTROY_GTK( rview->spin );\n\tDESTROY_GTK( rview->led );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\nrowview_attach( Rowview *rview, GtkWidget *child, int x, \n\tGtkAttachOptions xoptions, GtkAttachOptions yoptions )\n{\n\tSubcolumnview *sview = rview->sview;\n\n\tgtk_widget_ref( child );\n\n\tif( child->parent )\n\t\tgtk_container_remove( GTK_CONTAINER( sview->table ), child );\n\tgtk_table_attach( GTK_TABLE( sview->table ), child,\n\t\tx, x + 1, rview->rnum, rview->rnum + 1, \n\t\txoptions, yoptions, 0, 0 );\n\n\tgtk_widget_unref( child );\n}\n\nstatic void\nrowview_update_widgets( Rowview *rview )\n{\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\tint pos = ICONTAINER( row )->pos;\n\tgboolean editable = row->ws->mode != WORKSPACE_MODE_NOEDIT;\n\n#ifdef DEBUG\n\tprintf( \"rowview_refresh: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n\tprintf( \"\\teditable == %d\\n\", editable ); \n#endif /*DEBUG*/\n\n\t/* Attach widgets to parent in new place.\n\t */\n        if( rview->rnum != pos ) {\n#ifdef DEBUG\n\t\tprintf( \"rowview_refresh: move from row %d to row %d\\n\", \n\t\t\trview->rnum, pos );\n#endif /*DEBUG*/\n\n\t\trview->rnum = pos;\n\n\t\trowview_attach( rview, rview->spin, \n\t\t\t0, GTK_FILL, GTK_FILL );\n\t\trowview_attach( rview, rview->but, \n\t\t\t1, GTK_FILL, GTK_EXPAND | GTK_FILL );\n\t\trowview_attach( rview, rview->led, \n\t\t\t2, GTK_FILL, GTK_EXPAND | GTK_FILL );\n\t\tif( rview->rhsview )\n\t\t\trowview_attach( rview, GTK_WIDGET( rview->rhsview ), \n\t\t\t\t3, \n\t\t\t\tGTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL );\n\t}\n\n        /* Set colours.\n         */\n\tif( CALC_DISPLAY_LED ) {\n\t\tchar *stock_id;\n\n\t\tstock_id = STOCK_LED_OFF;\n\t\tif( row->selected )\n\t\t\tstock_id = STOCK_LED_GREEN;\n\t\telse if( row->show == ROW_SHOW_PARENT )\n\t\t\tstock_id = STOCK_LED_CYAN;\n\t\telse if( row->show == ROW_SHOW_CHILD )\n\t\t\tstock_id = STOCK_LED_BLUE;\n\t\telse if( row->err )\n\t\t\tstock_id = STOCK_LED_RED;\n\t\telse if( row->dirty )\n\t\t\tstock_id = STOCK_LED_YELLOW;\n\n\t\tgtk_image_set_from_stock( GTK_IMAGE( rview->led ), \n\t\t\tstock_id, GTK_ICON_SIZE_MENU );\n\t}\n\telse {\n\t\tgchar *name = \"\";\n\n\t\tif( row->selected )\n\t\t\tname = \"selected_widget\";\n\t\telse if( row->show == ROW_SHOW_PARENT )\n\t\t\tname = \"parent_widget\";\n\t\telse if( row->show == ROW_SHOW_CHILD )\n\t\t\tname = \"child_widget\";\n\t\telse if( row->err )\n\t\t\tname = \"error_widget\";\n\t\telse if( row->dirty )\n\t\t\tname = \"dirty_widget\";\n\n\t\tgtk_widget_set_name( rview->but, name );\n\t}\n\twidget_visible( rview->led, \n\t\trview->visible && CALC_DISPLAY_LED && editable );\n\n\t/* Update button.\n\t */\n        set_glabel( rview->label, \"%s\", row_name( row ) );\n\twidget_visible( rview->but, rview->visible && editable );\n\n\t/* Spin visible only if this is a class. \n\t */\n\twidget_visible( rview->spin, \n\t\trview->visible && row->is_class && editable );\n\n\tif( rview->rhsview )\n\t\twidget_visible( GTK_WIDGET( rview->rhsview ), rview->visible );\n}\n\nstatic void \nrowview_reset( View *view )\n{\n\tRowview *rview = ROWVIEW( view );\n\n\trowview_update_widgets( rview );\n\n\tVIEW_CLASS( parent_class )->reset( view );\n}\n\nstatic void \nrowview_refresh( vObject *vobject )\n{\n\tRowview *rview = ROWVIEW( vobject );\n\n\trowview_update_widgets( rview );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\n/* Single click on button callback.\n */\nstatic void\nrowview_single_cb( GtkWidget *wid, GdkEvent *event, Rowview *rview )\n{\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\n\trow_select_modifier( row, event->button.state );\n}\n\n/* Edit our object.\n */\nstatic gboolean\nrowview_edit( Rowview *rview )\n{\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\tModel *graphic = row->child_rhs->graphic;\n\n\tif( graphic )\n\t\tmodel_edit( GTK_WIDGET( rview->sview ), graphic );\n\n\treturn( TRUE );\n}\n\n/* Double click on button callback.\n */\nstatic void\nrowview_double_cb( GtkWidget *button, GdkEvent *event, Rowview *rview )\n{\n\tif( !rowview_edit( rview ) ) \n\t\tiwindow_alert( button, GTK_MESSAGE_ERROR );\n}\n\n/* Edit in menu.\n */\nstatic void\nrowview_edit_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview )\n{\n\tif( !rowview_edit( rview ) ) \n\t\tiwindow_alert( button, GTK_MESSAGE_ERROR );\n}\n\n/* Show info.\n */\nstatic gboolean\nrowview_header( Rowview *rview )\n{\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\tModel *graphic = row->child_rhs->graphic;\n\n\tif( graphic )\n\t\tmodel_header( GTK_WIDGET( rview->sview ), graphic );\n\n\treturn( TRUE );\n}\n\n/* Info in menu.\n */\nstatic void\nrowview_header_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview )\n{\n\tif( !rowview_header( rview ) ) \n\t\tiwindow_alert( button, GTK_MESSAGE_ERROR );\n}\n\n/* Clone the current item.\n */\nstatic void\nrowview_clone_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview )\n{\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\tWorkspace *ws = row->top_col->ws;\n\n\t/* Only allow clone of top level rows.\n\t */\n\tif( row->top_row != row ) {\n\t\terror_top( _( \"Can't duplicate.\" ) );\n\t\terror_sub( \"%s\", \n\t\t\t_( \"You can only duplicate top level rows.\" ) );\n\t\tiwindow_alert( button, GTK_MESSAGE_INFO );\n\t\treturn;\n\t}\n\n        workspace_deselect_all( ws );\n        row_select( row );\n        if( !workspace_selected_duplicate( ws ) )\n\t\tiwindow_alert( button, GTK_MESSAGE_ERROR );\n        workspace_deselect_all( ws );\n\n        symbol_recalculate_all();\n}\n\n/* Ungroup the current item.\n */\nstatic void\nrowview_ungroup_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview )\n{\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\n        workspace_deselect_all( row->ws );\n        row_select( row );\n        if( !workspace_selected_ungroup( row->ws ) )\n\t\tiwindow_alert( button, GTK_MESSAGE_ERROR );\n        symbol_recalculate_all();\n}\n\n/* Save the current item.\n */\nstatic void\nrowview_save_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview )\n{\n\tiWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( rview ) ) );\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\tModel *graphic = row->child_rhs->graphic;\n\n\tif( graphic )\n\t\tclassmodel_graphic_save( CLASSMODEL( graphic ),\n\t\t\tGTK_WIDGET( iwnd ) ); \n}\n\n/* Replace the current item.\n */\nstatic void\nrowview_replace_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview )\n{\n\tiWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( rview ) ) );\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\tModel *graphic = row->child_rhs->graphic;\n\n\tif( graphic )\n\t\tclassmodel_graphic_replace( CLASSMODEL( graphic ),\n\t\t\tGTK_WIDGET( iwnd ) ); \n}\n\n/* Recalculate the current item.\n */\nstatic void\nrowview_recalc_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview )\n{\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\tWorkspace *ws = row->top_col->ws;\n\n\t/* Mark dirty from this sym on, and force a recalc even if recalc is\n\t * off.\n\t */\n        workspace_deselect_all( ws );\n        row_select( row );\n        if( !workspace_selected_recalc( ws ) )\n\t\tiwindow_alert( button, GTK_MESSAGE_ERROR );\n        workspace_deselect_all( ws );\n\n\t/* Now ... pick up any errors.\n\t */\n\tif( row->sym &&\n\t\t!symbol_recalculate_check( row->sym ) )\n\t\tiwindow_alert( button, GTK_MESSAGE_ERROR );\n}\n\n/* Reset the current item.\n */\nstatic void\nrowview_clear_edited_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview )\n{\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\n\t(void) icontainer_map_all( ICONTAINER( row ),\n\t\t(icontainer_map_fn) model_clear_edited, NULL );\n\tsymbol_recalculate_all();\n}\n\n/* Remove the current item.\n */\nstatic void\nrowview_remove_cb( GtkWidget *menu, GtkWidget *button, Rowview *rview )\n{\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\tWorkspace *ws = row->top_col->ws;\n\n\tworkspace_deselect_all( ws );\n\trow_select( row );\n\tworkspace_selected_remove_yesno( ws, button );\n}\n\n/* Callback for up/down spin button.\n */\nstatic void\nrowview_spin_up_cb( GtkWidget *widget, gpointer client )\n{\n\tRowview *rview = ROWVIEW( client );\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\tRhs *rhs = row->child_rhs;\n\n\trhs_vislevel_down( rhs );\n\tworkspace_set_modified( row->ws, TRUE );\n}\n\nstatic void\nrowview_spin_down_cb( GtkWidget *widget, gpointer client )\n{\n\tRowview *rview = ROWVIEW( client );\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\tRhs *rhs = row->child_rhs;\n\n\trhs_vislevel_up( rhs );\n\tworkspace_set_modified( row->ws, TRUE );\n}\n\n/* Scroll to make tally entry visible. \n */\nstatic void\nrowview_scrollto( View *view, ModelScrollPosition position )\n{\n\tRowview *rview = ROWVIEW( view );\n\tColumnview *cview = view_get_columnview( VIEW( rview ) );\n\tWorkspaceview *wview = cview->wview;\n\n        int x, y, w, h;\n\n        /* Extract position of tally row in RC widget.\n         */\n        rowview_get_position( rview, &x, &y, &w, &h );\n        workspaceview_scroll( wview, x, y, w, h );\n}\n\nstatic void\nrowview_drag( Rowview *rview_from, Rowview *rview_to )\n{\n\tRow *row_from = ROW( VOBJECT( rview_from )->iobject );\n\tRow *row_to = ROW( VOBJECT( rview_to )->iobject );\n\n\tif( row_from->top_col != row_to->top_col ) {\n\t\terror_top( _( \"Not implemented.\" ) );\n\t\terror_sub( _( \"Drag between columns not yet implemented.\" ) );\n\t\tiwindow_alert( GTK_WIDGET( rview_from ), GTK_MESSAGE_ERROR );\n\t\treturn;\n\t}\n\n\ticontainer_child_move( ICONTAINER( row_from ), \n\t\tICONTAINER( row_to )->pos );\n\n\t/* Refresh all the rows, to make sure we move all rows to their new\n\t * slots.\n\t */\n\ticontainer_map( ICONTAINER( row_from->scol ),\n\t\t(icontainer_map_fn) iobject_changed, NULL, NULL );\n\n        workspace_deselect_all( row_from->ws );\n}\n\nstatic void\nrowview_drag_data_get( GtkWidget *but,\n\tGdkDragContext *context, GtkSelectionData *selection_data,\n\tguint info, guint time, Rowview *rview )\n{\n\tif( info == ROWVIEW_TARGET_STRING ) {\n\t\t/* Send a pointer to us.\n \t\t */\n\t\tgtk_selection_data_set( selection_data,\n\t\t\tselection_data->target,\n\t\t\t8, (const guchar *) &rview, sizeof( Rowview * ) );\n\t}\n}\n\nstatic void\nrowview_drag_data_received( GtkWidget *but,\n\tGdkDragContext *context, gint x, gint y,\n\tGtkSelectionData *data, guint info, guint time, Rowview *rview_to )\n{\n\tif( data->length == sizeof( Rowview * ) && data->format == 8 && \n\t\tinfo == ROWVIEW_TARGET_STRING ) {\n\t\tRowview *rview_from = *((Rowview **) data->data);\n\n\t\tif( IS_ROWVIEW( rview_from ) ) {\n\t\t\trowview_drag( rview_from, rview_to );\n\t\t\tgtk_drag_finish( context, TRUE, FALSE, time );\n\t\t\treturn;\n\t\t}\n\t}\n\n\tgtk_drag_finish( context, FALSE, FALSE, time );\n}\n\n/* Attach the rowview menu to a widget ... also used by iimageview\n */\nguint\nrowview_menu_attach( Rowview *rview, GtkWidget *widget )\n{\n\treturn( popup_attach( widget, rowview_popup_menu, rview ) );\n}\n\nstatic void\nrowview_link( View *view, Model *model, View *parent )\n{\n\tRow *row = ROW( model );\n\tRowview *rview = ROWVIEW( view );\n\tSubcolumnview *sview = SUBCOLUMNVIEW( parent );\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\trview->sview = sview;\n\n\t/* Only drag n drop top level rows.\n\t */\n\tif( row->top_row == row ) {\n\t\tgtk_drag_source_set( rview->but, GDK_BUTTON1_MASK, \n\t\t\trowview_target_table, IM_NUMBER( rowview_target_table ),\n\t\t\tGDK_ACTION_COPY );\n\t\tgtk_signal_connect( GTK_OBJECT( rview->but ), \"drag_data_get\",\n\t\t\tGTK_SIGNAL_FUNC( rowview_drag_data_get ), rview );\n\n\t\tgtk_drag_dest_set( rview->but, GTK_DEST_DEFAULT_ALL,\n\t\t\trowview_target_table, IM_NUMBER( rowview_target_table ),\n\t\t\tGDK_ACTION_COPY );\n\t\tgtk_signal_connect( GTK_OBJECT( rview->but ), \n\t\t\t\"drag_data_received\",\n\t\t\tGTK_SIGNAL_FUNC( rowview_drag_data_received ), rview );\n\t}\n\n\trowview_menu_attach( rview, rview->but );\n}\n\nstatic void\nrowview_child_add( View *parent, View *child )\n{\n\tRowview *rowview = ROWVIEW( parent );\n\n\tg_assert( IS_RHSVIEW( child ) );\n\tg_assert( !rowview->rhsview );\n\n\trowview->rhsview = RHSVIEW( child );\n\n\tVIEW_CLASS( parent_class )->child_add( parent, child );\n}\n\nstatic void\nrowview_child_remove( View *parent, View *child )\n{\n\tRowview *rowview = ROWVIEW( parent );\n\n\tg_assert( IS_RHSVIEW( child ) );\n\tg_assert( rowview->rhsview );\n\n\trowview->rhsview = NULL;\n\n\tVIEW_CLASS( parent_class )->child_remove( parent, child );\n}\n\nstatic void\nrowview_class_init( RowviewClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tGtkWidget *pane;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tobject_class->destroy = rowview_destroy;\n\n\tvobject_class->refresh = rowview_refresh;\n\n\tview_class->link = rowview_link;\n\tview_class->child_add = rowview_child_add;\n\tview_class->child_remove = rowview_child_remove;\n\tview_class->reset = rowview_reset;\n\tview_class->scrollto = rowview_scrollto;\n\n        /* Other init.\n         */\n\tpane = rowview_popup_menu = popup_build( _( \"Row menu\" ) );\n\tpopup_add_but( pane, _( \"_Edit\" ), \n\t\tPOPUP_FUNC( rowview_edit_cb ) );\n\tpopup_add_but( pane, _( \"_Header\" ), \n\t\tPOPUP_FUNC( rowview_header_cb ) );\n\tpopup_add_but( pane, STOCK_DUPLICATE,\n\t\tPOPUP_FUNC( rowview_clone_cb ) );\n\tpopup_add_but( pane, _( \"U_ngroup\" ), \n\t\tPOPUP_FUNC( rowview_ungroup_cb ) );\n\tpopup_add_but( pane, GTK_STOCK_SAVE_AS,\n\t\tPOPUP_FUNC( rowview_save_cb ) );\n\tpopup_add_but( pane, _( \"Replace From _File\" ), \n\t\tPOPUP_FUNC( rowview_replace_cb ) );\n\tpopup_add_but( pane, _( \"_Recalculate\" ), \n\t\tPOPUP_FUNC( rowview_recalc_cb ) );\n\tpopup_add_but( pane, _( \"Re_set\" ), \n\t\tPOPUP_FUNC( rowview_clear_edited_cb ) );\n\tmenu_add_sep( pane );\n\tpopup_add_but( pane, GTK_STOCK_DELETE,\n\t\tPOPUP_FUNC( rowview_remove_cb ) );\n}\n\nstatic void\nrowview_enter_cb( GtkWidget *widget, Rowview *rview )\n{\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\n\trow_set_status( row );\n\trow_show_dependents( row );\n}\n\nstatic void\nrowview_leave_cb( GtkWidget *widget, Rowview *rview )\n{\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\n\trow_hide_dependents( row );\n}\n\nstatic gboolean\nrowview_focus_cb( GtkWidget *widget, GtkDirectionType dir, Rowview *rview )\n{\n        view_scrollto( VIEW( rview ), MODEL_SCROLL_TOP );\n\n        return( FALSE );\n}\n\nstatic void\nrowview_tooltip_generate( GtkWidget *widget, VipsBuf *buf, Rowview *rview )\n{\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\n\tiobject_info( IOBJECT( row ), buf );\n\tvips_buf_removec( buf, '\\n' );\n}\n\nstatic void\nrowview_init( Rowview *rview )\n{\n        rview->visible = TRUE; \n\trview->rnum = -1;\n        rview->last_tooltip = NULL; \n\n\t/* Make leds.\n\t */\n\trview->led = gtk_image_new_from_stock( STOCK_LED_OFF, \n\t\tGTK_ICON_SIZE_MENU );\n\tgtk_misc_set_alignment( GTK_MISC( rview->led ), 0.5, 0.0 );\n\tgtk_misc_set_padding( GTK_MISC( rview->led ), 2, 2 );\n\n        /* Make fold/unfold button.\n         */\n\trview->spin = spin_new();\n        gtk_signal_connect( GTK_OBJECT( rview->spin ), \"up_click\",\n                GTK_SIGNAL_FUNC( rowview_spin_up_cb ), rview );\n        gtk_signal_connect( GTK_OBJECT( rview->spin ), \"down_click\",\n                GTK_SIGNAL_FUNC( rowview_spin_down_cb ), rview );\n        gtk_widget_show( rview->spin );\n\tset_tooltip( rview->spin, _( \"Click to open or close class\" ) );\n\n        /* Make name button.\n         */\n        rview->but = gtk_button_new();\n        gtk_widget_show( rview->but );\n        doubleclick_add( rview->but, FALSE,\n                DOUBLECLICK_FUNC( rowview_single_cb ), rview, \n\t\tDOUBLECLICK_FUNC( rowview_double_cb ), rview );\n        rview->label = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( rview->label ), 1, 0 );\n        gtk_misc_set_padding( GTK_MISC( rview->label ), 2, 0 );\n        gtk_container_add( GTK_CONTAINER( rview->but ), rview->label );\n        gtk_widget_show( rview->label );\n        gtk_signal_connect( GTK_OBJECT( rview->but ), \"enter\",\n                GTK_SIGNAL_FUNC( rowview_enter_cb ), rview );\n        gtk_signal_connect( GTK_OBJECT( rview->but ), \"leave\",\n                GTK_SIGNAL_FUNC( rowview_leave_cb ), rview );\n        gtk_signal_connect( GTK_OBJECT( rview->but ), \"focus\",\n                GTK_SIGNAL_FUNC( rowview_focus_cb ), rview );\n\tset_tooltip_generate( rview->but, \n\t\t(TooltipGenerateFn) rowview_tooltip_generate, rview, NULL );\n}\n\nGtkType\nrowview_get_type( void )\n{\n\tstatic GtkType rowview_type = 0;\n\n\tif( !rowview_type ) {\n\t\tstatic const GtkTypeInfo rview_info = {\n\t\t\t\"Rowview\",\n\t\t\tsizeof( Rowview ),\n\t\t\tsizeof( RowviewClass ),\n\t\t\t(GtkClassInitFunc) rowview_class_init,\n\t\t\t(GtkObjectInitFunc) rowview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\trowview_type = gtk_type_unique( TYPE_VIEW, &rview_info );\n\t}\n\n\treturn( rowview_type );\n}\n\nView *\nrowview_new( void )\n{\n\tRowview *rview = gtk_type_new( TYPE_ROWVIEW );\n\n\treturn( VIEW( rview ) );\n}\n\n/* Find the position and size of a row in the enclosing GtkFixed.\n */\nvoid\nrowview_get_position( Rowview *rview, int *x, int *y, int *w, int *h )\n{\n        Columnview *cview = view_get_columnview( VIEW( rview ) );\n\n        if( GTK_WIDGET_VISIBLE( rview->spin ) ) {\n                *x = rview->spin->allocation.x;\n                *y = rview->spin->allocation.y;\n                *w = rview->spin->allocation.width;\n                *h = rview->spin->allocation.height;\n        }\n        else {\n                *x = rview->but->allocation.x;\n                *y = rview->but->allocation.y;\n                *w = 0;\n                *h = 0;\n        }\n\n        *w += rview->but->allocation.width;\n        *h = IM_MAX( rview->but->allocation.height, *h );\n\n        if( GTK_WIDGET_VISIBLE( rview->led ) ) {\n                *w += rview->led->allocation.width;\n                *h = IM_MAX( rview->led->allocation.height, *h );\n        }\n\n        *w += GTK_WIDGET( rview->rhsview )->allocation.width;\n        *h = IM_MAX( GTK_WIDGET( rview->rhsview )->allocation.height, *h );\n\n        /* Title bar, plus separator.\n         */\n        *y += cview->title->allocation.height + 2;\n\n        *x += cview->main->allocation.x;\n        *y += cview->main->allocation.y;\n\n#ifdef DEBUG\n        printf( \"rowview_get_position: \" );\n        row_name_print( ROW( VOBJECT( rview )->iobject ) );\n        printf( \": x = %d, y = %d, w = %d, h = %d\\n\", *x, *y, *w, *h );\n#endif /*DEBUG*/\n}\n\n/* Hide/show a row. \n */\nvoid \nrowview_set_visible( Rowview *rview, gboolean visible )\n{\n\tif( rview->visible != visible ) {\n\t\trview->visible = visible;\n\t\trowview_update_widgets( rview );\n\t}\n}\n\ngboolean \nrowview_get_visible( Rowview *rview )\n{\n\treturn( rview->visible );\n}\n"
  },
  {
    "path": "src/rowview.h",
    "content": "/* a rowview in a workspace ... part of a tallycolumn, not a separate widget\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_ROWVIEW (rowview_get_type())\n#define ROWVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_ROWVIEW, Rowview ))\n#define ROWVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_ROWVIEW, RowviewClass ))\n#define IS_ROWVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_ROWVIEW ))\n#define IS_ROWVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_ROWVIEW ))\n\nstruct _Rowview {\n\tView view;\n\n\tSubcolumnview *sview;\t/* Enclosing subcolumnview */\n\n\tRhsview *rhsview;\t/* Our rhs */\n\n\tgboolean visible;\t/* Currently visible */\n        int rnum;\t\t/* Row of tallycolumn we are in */\n\n        GtkWidget *spin;   \t/* Class display open/close widgets */\n        GtkWidget *but;   \t/* Name button */\n        GtkWidget *led;      \t/* Indicators */\n        GtkWidget *label;   \t/* Name label */\n\n\tchar *last_tooltip;\t/* Last tooltip we set */\n};\n\ntypedef struct _RowviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} RowviewClass;\n\nguint rowview_menu_attach( Rowview *rview, GtkWidget *widget );\n\nGtkType rowview_get_type( void );\nView *rowview_new( void );\n\nvoid rowview_get_position( Rowview *rview, int *x, int *y, int *w, int *h );\nvoid rowview_set_visible( Rowview *rview, gboolean visible );\ngboolean rowview_get_visible( Rowview *rview );\n"
  },
  {
    "path": "src/secret.c",
    "content": "/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n/* Just show secrets we added\n#define DEBUG_ADD\n */\n\n#include \"ip.h\"\n\n/* build secret sets for exprs\n\ncases:\n\n\tfred a \n\t\t= jim 12\n\t{\n\t\tjim b = a + b;\n\t}\n\njim refers to a parameter in an enclosing scope ... we add extra secret\nparameters to jim like this:\n\n\tfred a \n\t\t= jim [a] 12\n\t{\n\t\tjim [a] b = a + b;\n\t}\n\nacross class boundaries:\n\n\tfred a\n\t\t= jim\n\t{\n\t\tjim = class {\n\t\t\tb = a;\n\t\t}\n\t}\n\nnow fred.jim.b refers to fred.a ... a needs to be added to the secrets on\njim's constructor like this:\n\n\tfred a\n\t\t= jim [a]\n\t{\n\t\tjim [a] = class {\n\t\t\tb = a;\n\t\t}\n\t}\n\nif the secret is a class member, pass \"this\" instead and the inner thing then\ngets from that\n\n\tfred a = class\n\t{\n\t\tjim [fred.this] b = fred.this.a + b;\n\t}\n\nif the inner thing is also a class, need to get in two stages ... first get\nthe right this, then get from that\n\n\tfred a = class\n\t{\n\t\tjim [fred.this] = class {\n\t\t\tb = jim.this.fred.this.a;\n\t\t}\n\t}\n\nneed to work for any sort of nesting of functions and classes\n\n\tfred = class {\n\t\tb = c\n\t\t{\n\t\t\tc = this;\n\t\t}\n\t}\n\nnot just params ... can involve locals of parents\n\n */\n\n/* Add a secret. Set changed if we make a change.\n */\nstatic void *\nsecret_add( Symbol *secret, Compile *compile, gboolean *changed )\n{\n\tCompile *parent = compile_get_parent( compile );\n\n#ifdef DEBUG\n\tprintf( \"secret_add: considering secret \" );\n\tsymbol_name_print( secret );\n\tprintf( \"for \" );\n\tcompile_name_print( compile );\n\tprintf( \" ...\\n\" );\n#endif /*DEBUG*/\n\n\t/* If expr is a class, don't add our own this.\n\t */\n\tif( is_class( compile ) && secret == compile->this )\n\t\treturn( NULL );\n\n\t/* If expr already has secret as a param or secret, don't add again.\n\t */\n\tif( g_slist_find( compile->secret, secret ) ||\n\t\tg_slist_find( compile->param, secret ) )\n\t\treturn( NULL );\n\n\t/* If secret is a member (param, func, whatever), add secret's\n\t * enclosing \"this\" instead ... expr can then get secret from there.\n\t * Unless the secret is already a \"this\", of course.\n\t */\n\tif( is_class( COMPILE( ICONTAINER( secret )->parent ) ) &&\n\t\t!is_this( secret ) )\n\t\tsecret = COMPILE( ICONTAINER( secret )->parent )->this;\n\n\t/* If compile is a member (and not a class itself), add the secret to \n\t * compile's constructor instead ... compile can get from \"this\".\n\t */\n\tif( is_class( parent ) && secret != parent->this && \n\t\t!is_class( compile ) ) \n\t\tcompile = parent;\n\n\t/* We may have moved stuff about ... check for dupes again.\n\t */\n\tif( g_slist_find( compile->secret, secret ) ||\n\t\tg_slist_find( compile->param, secret ) )\n\t\treturn( NULL );\n\n#ifdef DEBUG_ADD\n\tprintf( \"secret_add: adding secret \" );\n\tsymbol_name_print( secret );\n\tprintf( \"to \" );\n\tcompile_name_print( compile );\n\tprintf( \"\\n\" );\n#endif /*DEBUG_ADD*/\n\n\tcompile->secret = g_slist_append( compile->secret, secret );\n\tcompile->nsecret += 1;\n\t*changed = TRUE;\n\n\treturn( NULL );\n}\n\n/* If compile is a member, then secret lists are easy ... just use \"this\".\n */\nstatic void *\nsecret_set_class( Compile *compile ) \n{\n\tif( is_class( compile_get_parent( compile ) ) ) {\n\t\tCompile *parent = compile_get_parent( compile );\n\t\tSymbol *ths = parent->this;\n\t\tgboolean changed;\n\n\t\tif( secret_add( ths, compile, &changed ) )\n\t\t\treturn( (void *) ths );\n\t}\n\n\treturn( NULL );\n}\n\n/* child is one of compile's children ...  is it reference to a parameter \n * in an enclosing scope? If yes, we've found a secret!\n */\nstatic void *\nsecret_is_nonlocal( Symbol *child, Compile *compile )\n{\n\tgboolean changed;\n\n\tif( child->type == SYM_PARAM && \n\t\tCOMPILE( ICONTAINER( child )->parent ) != compile ) {\n\t\tif( secret_add( child, compile, &changed ) )\n\t\t\treturn( child );\n\t}\n\n\treturn( NULL );\n}\n\n/* Make initial secret list ... if this is a member/function, search for \n * references to symbols in an enclosing scope.\n */\nstatic void *\nsecret_find_nonlocal( Compile *compile )\n{\n\t/* Look for any secrets.\n\t */\n\tif( slist_map( compile->children,\n\t\t(SListMapFn) secret_is_nonlocal, compile ) )\n\t\treturn( compile );\n\n\treturn( NULL );\n}\n\n/* Does child have any secrets that compile does not?\n */\nstatic void *\nsecret_test( Symbol *child, Compile *compile, gboolean *changed )\n{\n\t/* If this is a parameter or a zombie, nothing to do.\n\t */\n\tif( !is_value( child ) )\n\t\treturn( NULL );\n\n\tif( child->expr->compile )\n\t\tif( slist_map2( child->expr->compile->secret, \n\t\t\t(SListMap2Fn) secret_add, compile, changed ) )\n\t\t\treturn( child );\n\n\treturn( NULL );\n}\n\n/* Close secret list ... if sym has a child with a secret sym does not have,\n * sym needs child's secret too.\n */\nstatic void *\nsecret_close( Compile *compile, gboolean *changed )\n{\n\tif( is_class( compile ) ) {\n\t\t/* For classes, need to consider all of their locals. Any\n\t\t * secrets our locals have, we need too.\n\t\t */\n\t\tif( icontainer_map( ICONTAINER( compile ),\n\t\t\t(icontainer_map_fn) secret_test, compile, changed ) )\n\t\t\treturn( compile );\n\t}\n\telse {\n\t\t/* Look at our immediate children, any of them have secrets \n\t\t * we don't?\n\t\t */\n\t\tif( slist_map2( compile->children,\n\t\t\t(SListMap2Fn) secret_test, compile, changed ) )\n\t\t\treturn( compile );\n\t}\n\n\treturn( NULL );\n}\n\n#ifdef DEBUG\n/* Sub-fn of below ... add param as a secret to sym.\n */\nstatic void *\nsecret_all_add( Compile *compile, Symbol *param )\n{\n\tgboolean changed;\n\n\treturn( secret_add( param, compile, &changed ) );\n}\n\n/* Sub-fn of below ... add param as a secret for all of compile's locals.\n */\nstatic void *\nsecret_all_sym( Symbol *param, Compile *compile )\n{\n\treturn( compile_map_all( compile,\n\t\t(map_compile_fn) secret_all_add, param ) );\n}\n\n/* Make syms params and secrets secrets for all sub-syms. Only handy for\n * debugging.\n */\nstatic void *\nsecret_all( Compile *compile ) \n{\n\tif( slist_map( compile->param,\n\t\t(SListMapFn) secret_all_sym, compile ) ||\n\t\tslist_map( compile->secret, \n\t\t\t(SListMapFn) secret_all_sym, compile ) )\n\t\treturn( compile );\n\n\treturn( NULL );\n}\n#endif /*DEBUG*/\n\n/* Make secret param lists for compile and all of it's sub-defs.\n */\nvoid\nsecret_build( Compile *compile )\n{\n\tgboolean changed;\n\n#ifdef DEBUG_ADD\n\tprintf( \"secret_build: \" );\n\tsymbol_name_print( compile->sym );\n\tprintf( \"\\n\" );\n#endif /*DEBUG_ADD*/\n\n\t/* Look for class definitions ... all members of a\n\t * class should take a single secret, their \"this\" parameter. \n\t * When they in turn call their locals, they can get the \n\t * secrets they need from \"this\".\n\t */\n\t(void) compile_map_all( compile, \n\t\t(map_compile_fn) secret_set_class, NULL );\n\n\t/* Now look for non-member functions ... if they reference \n\t * parameters in an enclosing scope, add that parameter to \n\t * the secret list.\n\t */\n\t(void) compile_map_all( compile, \n\t\t(map_compile_fn) secret_find_nonlocal, NULL );\n\n\t/* Now take the closure of the secret lists ... have to \n\t * fix() this to get limit of secret_close().\n\t */\n\tdo {\n\t\tchanged = FALSE;\n\t\t(void) compile_map_all( compile,\n\t\t\t(map_compile_fn) secret_close, &changed );\n\t} while( changed ); \n}\n\n"
  },
  {
    "path": "src/secret.h",
    "content": "/* Decls for secret.c \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\nvoid secret_build( Compile *compile );\n"
  },
  {
    "path": "src/slider.c",
    "content": "/* an input slider ... put/get methods\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic View *\nslider_view_new( Model *model, View *parent )\n{\n\treturn( sliderview_new() );\n}\n\n/* Members of slider we automate.\n */\nstatic ClassmodelMember slider_members[] = {\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_CAPTION, \"caption\", N_( \"Caption\" ),\n\t\tG_STRUCT_OFFSET( iObject, caption ) },\n\t{ CLASSMODEL_MEMBER_DOUBLE, NULL, 0,\n\t\tMEMBER_FROM, \"from\", N_( \"From\" ),\n\t\tG_STRUCT_OFFSET( Slider, from ) },\n\t{ CLASSMODEL_MEMBER_DOUBLE, NULL, 0,\n\t\tMEMBER_TO, \"to\", N_( \"To\" ),\n\t\tG_STRUCT_OFFSET( Slider, to ) },\n\t{ CLASSMODEL_MEMBER_DOUBLE, NULL, 0,\n\t\tMEMBER_VALUE, \"value\", N_( \"Value\" ),\n\t\tG_STRUCT_OFFSET( Slider, value ) }\n};\n\nstatic void\nslider_class_init( SliderClass *class )\n{\n\tModelClass *model_class = (ModelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tmodel_class->view_new = slider_view_new;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n\n\tclassmodel_class->members = slider_members;\n\tclassmodel_class->n_members = IM_NUMBER( slider_members );\n}\n\nstatic void\nslider_init( Slider *slider )\n{\n\t/* Overridden later. Just something sensible.\n\t */\n        slider->from = 0;\n\tslider->to = 255;\n\tslider->value = 128;\n\n\t/* Need to set caption to something too, since it's an automated\n\t * member.\n\t */\n\tiobject_set( IOBJECT( slider ), CLASS_SLIDER, \"\" );\n}\n\nGType\nslider_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( SliderClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) slider_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Slider ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) slider_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"Slider\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/slider.h",
    "content": "/* a slider in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_SLIDER (slider_get_type())\n#define SLIDER( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_SLIDER, Slider ))\n#define SLIDER_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_SLIDER, SliderClass))\n#define IS_SLIDER( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_SLIDER ))\n#define IS_SLIDER_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_SLIDER ))\n#define SLIDER_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_SLIDER, SliderClass ))\n\ntypedef struct _Slider {\n\tClassmodel parent_object;\n\n\tdouble from, to, value;\n} Slider;\n\ntypedef struct _SliderClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} SliderClass;\n\nGType slider_get_type( void );\n"
  },
  {
    "path": "src/sliderview.c",
    "content": "/* run the display for a slider in a workspace \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GraphicviewClass *parent_class = NULL;\n\nstatic void \nsliderview_refresh( vObject *vobject )\n{\n\tSliderview *sliderview = SLIDERVIEW( vobject );\n\tSlider *slider = SLIDER( VOBJECT( sliderview )->iobject );\n\tTslider *tslider = sliderview->tslider;\n\n        const double range = slider->to - slider->from;\n        const double lrange = log10( range );\n\tconst char *caption = IOBJECT( slider )->caption;\n\n#ifdef DEBUG\n\tprintf( \"sliderview_refresh\\n\" );\n#endif /*DEBUG*/\n\n\t/* Compatibility ... we used to not have a caption. Don't display\n\t * anything if there's o caption.\n\t */\n\tif( caption ) {\n\t\tif( strcmp( caption, \"\" ) != 0 )\n\t\t\tset_glabel( sliderview->label, _( \"%s:\" ), \n\t\t\t\tcaption );\n\t\telse\n\t\t\tset_glabel( sliderview->label, \"%s\", \"\" );\n\t}\n\n\ttslider->from = slider->from;\n\ttslider->to = slider->to;\n\ttslider->svalue = slider->value;\n\ttslider->value = slider->value;\n\n\ttslider->digits = IM_MAX( 0, ceil( 2 - lrange ) );\n\n\tif( CALC_RECOMP_SLIDER )\n\t\tgtk_range_set_update_policy( GTK_RANGE( tslider->slider ), \n\t\t\tGTK_UPDATE_CONTINUOUS );\n\telse\n\t\tgtk_range_set_update_policy( GTK_RANGE( tslider->slider ),\n\t\t\tGTK_UPDATE_DISCONTINUOUS );\n\n#ifdef DEBUG\n\tgtk_range_set_update_policy( GTK_RANGE( tslider->slider ),\n\t\tGTK_UPDATE_DISCONTINUOUS );\n#endif /*DEBUG*/\n\n\ttslider_changed( tslider );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void *\nsliderview_scan( View *view )\n{\n\tSliderview *sliderview = SLIDERVIEW( view );\n\tSlider *slider = SLIDER( VOBJECT( sliderview )->iobject );\n\tClassmodel *classmodel = CLASSMODEL( slider );\n\tExpr *expr = HEAPMODEL( classmodel )->row->expr;\n\n\tdouble value;\n\n\tif( !get_geditable_double( sliderview->tslider->entry, &value ) ) {\n\t\texpr_error_set( expr );\n\t\treturn( view );\n\t}\n\n\tif( slider->value != value ) {\n\t\tslider->value = value;\n\t\tclassmodel_update( classmodel );\n\t}\n\n\treturn( VIEW_CLASS( parent_class )->scan( view ) );\n}\n\nstatic void\nsliderview_link( View *view, Model *model, View *parent )\n{\n\tSliderview *sliderview = SLIDERVIEW( view );\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\tif( GRAPHICVIEW( view )->sview )\n\t\tgtk_size_group_add_widget( GRAPHICVIEW( view )->sview->group,   \n\t\t\tsliderview->label );\n}\n\nstatic void\nsliderview_class_init( SliderviewClass *class )\n{\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = sliderview_refresh;\n\n\tview_class->scan = sliderview_scan;\n\tview_class->link = sliderview_link;\n}\n\n/* Drag on slider.\n */\nstatic void\nsliderview_change_cb( Tslider *tslider, Sliderview *sliderview )\n{\n\tSlider *slider = SLIDER( VOBJECT( sliderview )->iobject );\n\n#ifdef DEBUG\n\tprintf( \"sliderview_change_cb\\n\" );\n#endif /*DEBUG*/\n\n\tif( slider->value != tslider->svalue ) {\n\t\tslider->value = tslider->svalue;\n\n\t\tclassmodel_update( CLASSMODEL( slider ) );\n\t\tsymbol_recalculate_all();\n\t}\n}\n\nstatic void\nsliderview_init( Sliderview *sliderview )\n{\n\tGtkWidget *hbox;\n\n\thbox = gtk_hbox_new( FALSE, 12 );\n        gtk_box_pack_start( GTK_BOX( sliderview ), hbox, TRUE, FALSE, 0 );\n\n        sliderview->label = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( sliderview->label ), 0, 0.5 );\n        gtk_misc_set_padding( GTK_MISC( sliderview->label ), 2, 1 );\n\tgtk_box_pack_start( GTK_BOX( hbox ), sliderview->label, \n\t\tFALSE, FALSE, 0 );\n\n\tsliderview->tslider = tslider_new();\n\ttslider_set_conversions( sliderview->tslider, NULL, NULL );\n        gtk_box_pack_start( GTK_BOX( hbox ), \n\t\tGTK_WIDGET( sliderview->tslider ), TRUE, TRUE, 6 );\n\n        gtk_signal_connect_object( GTK_OBJECT( sliderview->tslider ), \n\t\t\"text_changed\",\n                GTK_SIGNAL_FUNC( view_changed_cb ), \n\t\tGTK_OBJECT( sliderview ) );\n        gtk_signal_connect_object( GTK_OBJECT( sliderview->tslider ), \n\t\t\"activate\",\n                GTK_SIGNAL_FUNC( view_activate_cb ), \n\t\tGTK_OBJECT( sliderview ) );\n        gtk_signal_connect( GTK_OBJECT( sliderview->tslider ), \n\t\t\"slider_changed\", \n\t\tGTK_SIGNAL_FUNC( sliderview_change_cb ), sliderview );\n\n        gtk_widget_show_all( GTK_WIDGET( sliderview ) );\n}\n\nGtkType\nsliderview_get_type( void )\n{\n\tstatic GtkType sliderview_type = 0;\n\n\tif( !sliderview_type ) {\n\t\tstatic const GtkTypeInfo sinfo = {\n\t\t\t\"Sliderview\",\n\t\t\tsizeof( Sliderview ),\n\t\t\tsizeof( SliderviewClass ),\n\t\t\t(GtkClassInitFunc) sliderview_class_init,\n\t\t\t(GtkObjectInitFunc) sliderview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tsliderview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &sinfo );\n\t}\n\n\treturn( sliderview_type );\n}\n\nView *\nsliderview_new( void )\n{\n\tSliderview *sliderview = gtk_type_new( TYPE_SLIDERVIEW );\n\n\treturn( VIEW( sliderview ) );\n}\n"
  },
  {
    "path": "src/sliderview.h",
    "content": "/* a sliderview in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_SLIDERVIEW (sliderview_get_type())\n#define SLIDERVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_SLIDERVIEW, Sliderview ))\n#define SLIDERVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_SLIDERVIEW, SliderviewClass ))\n#define IS_SLIDERVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_SLIDERVIEW ))\n#define IS_SLIDERVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_SLIDERVIEW ))\n\ntypedef struct _Sliderview {\n\tGraphicview parent_object;\n\n\t/* My instance vars.\n\t */\n\tGtkWidget *label;\n\tTslider *tslider;\n} Sliderview;\n\ntypedef struct _SliderviewClass {\n\tGraphicviewClass parent_class;\n\n\t/* My methods.\n\t */\n} SliderviewClass;\n\nGtkType sliderview_get_type( void );\nView *sliderview_new( void );\n"
  },
  {
    "path": "src/spin.c",
    "content": "/* a pair of spin buttons, with no entry ... don't actually use buttons,\n * since we may have lots and lots of these, and we don't want to make an X\n * window for each one\n *\n * we do the event handling ourselves ... our enclosing view passes the ev \n * to spin_event(), this triggers signals as required\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\n/* Our signals. Up and down click.\n */\nenum {\n\tUP_CLICK,\n\tDOWN_CLICK,\n\tLAST_SIGNAL\n};\n\nstatic guint spin_signals[LAST_SIGNAL] = { 0 };\n\n/* Default up and down signal handlers.\n */\nstatic void\nspin_real_up_click( Spin *spin )\n{\n#ifdef DEBUG\n\tprintf( \"spin_real_up_click\\n\" );\n#endif /*DEBUG*/\n}\n\nstatic void\nspin_real_down_click( Spin *spin )\n{\n#ifdef DEBUG\n\tprintf( \"spin_real_down_click\\n\" );\n#endif /*DEBUG*/\n}\n\nstatic void\nspin_class_init( SpinClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n         */\n\tspin_signals[UP_CLICK] = g_signal_new( \"up_click\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( SpinClass, up_click ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\tspin_signals[DOWN_CLICK] = g_signal_new( \"down_click\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( SpinClass, down_click ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\n\tclass->up_click = spin_real_up_click;\n\tclass->down_click = spin_real_down_click;\n}\n\ntypedef struct {\n\tSpin *spin;\n\tint x, y;\t\t/* Click position */\n\tgboolean handled;\n} SpinEvent;\n\nstatic void\nallocation2rect( GtkAllocation *from, Rect *to )\n{\n        to->left = from->x;\n        to->top = from->y;\n        to->width = from->width;\n        to->height = from->height;\n}\n\nstatic void\nspin_button_press_event_test( GtkWidget *widget, gpointer data )\n{\n\tSpinEvent *sev = (SpinEvent *) data;\n\tRect pos;\n\n\tif( sev->handled )\n\t\treturn;\n\n\tallocation2rect( &widget->allocation, &pos );\n\tif( im_rect_includespoint( &pos, sev->x, sev->y ) ) {\n\t\tif( GTK_IS_ARROW( widget ) ) {\n\t\t\tsev->handled = TRUE;\n\n\t\t\tif( GTK_ARROW( widget )->arrow_type == GTK_ARROW_UP )\n\t\t\t\tg_signal_emit( GTK_OBJECT( sev->spin ), \n\t\t\t\t\tspin_signals[UP_CLICK], 0 );\n\t\t\telse\n\t\t\t\tg_signal_emit( GTK_OBJECT( sev->spin ), \n\t\t\t\t\tspin_signals[DOWN_CLICK], 0 );\n\t\t}\n\t}\n}\n\n/* Event in us somewhere.\n */\nstatic gboolean\nspin_button_press_event_cb( GtkWidget *widget, GdkEventButton *event, \n\tSpin *spin ) \n{\n\tgboolean handled = FALSE;\n\n\tif( event->type == GDK_BUTTON_PRESS ) {\n\t\tSpinEvent sev;\n\n\t\tif( event->button == 1 ) {\n\t\t\tsev.spin = spin;\n\t\t\t/* Find button x/y relative to top LH corner of spin.\n\t\t\t */\n\t\t\tsev.x = event->x + GTK_WIDGET( spin )->allocation.x;\n\t\t\tsev.y = event->y + GTK_WIDGET( spin )->allocation.y;\n\t\t\tsev.handled = FALSE;\n\t\t\tspin_button_press_event_test( spin->up, &sev );\n\t\t\tspin_button_press_event_test( spin->down, &sev );\n\n\t\t\thandled = sev.handled;\n\t\t}\n\t}\n\n\treturn( handled );\n}       \n\nstatic gboolean \nspin_button_enter_notify_event_cb( GtkWidget *widget, GdkEventCrossing *event,\n\tSpin *spin )\n{\n\tgboolean handled = FALSE;\n\n\tif( event->detail != GDK_NOTIFY_INFERIOR ) \n\t\tgtk_widget_set_state( widget, GTK_STATE_PRELIGHT );\n\n\treturn( handled );\n}\n\nstatic gboolean \nspin_button_leave_notify_event_cb( GtkWidget *widget, GdkEventCrossing *event,\n\tSpin *spin )\n{\n\tgboolean handled = FALSE;\n\n\tif( event->detail != GDK_NOTIFY_INFERIOR ) \n\t\tgtk_widget_set_state( widget, GTK_STATE_NORMAL );\n\n\treturn( handled );\n}\n\nstatic void\nspin_init( Spin *spin )\n{\n\tGtkWidget *ebox;\n\tGtkWidget *vbox;\n\n\tebox = gtk_event_box_new();\n\tset_tooltip( ebox, _( \"Expand or collapse row\" ) );\n\tgtk_event_box_set_visible_window( GTK_EVENT_BOX( ebox ), FALSE );\n        gtk_signal_connect( GTK_OBJECT( ebox ), \"button_press_event\",\n                GTK_SIGNAL_FUNC( spin_button_press_event_cb ), spin );\n        gtk_signal_connect( GTK_OBJECT( ebox ), \"enter_notify_event\",\n                GTK_SIGNAL_FUNC( spin_button_enter_notify_event_cb ), spin );\n        gtk_signal_connect( GTK_OBJECT( ebox ), \"leave_notify_event\",\n                GTK_SIGNAL_FUNC( spin_button_leave_notify_event_cb ), spin );\n        gtk_box_pack_start( GTK_BOX( spin ), ebox, FALSE, FALSE, 0 );\n\tgtk_widget_show( ebox );\n\n\tvbox = gtk_vbox_new( 0, FALSE );\n\tgtk_container_add( GTK_CONTAINER( ebox ), vbox );\n\tgtk_widget_show( vbox );\n\n\tspin->up = gtk_arrow_new( GTK_ARROW_UP, GTK_SHADOW_OUT );\n        spin->down = gtk_arrow_new( GTK_ARROW_DOWN, GTK_SHADOW_OUT );\n        gtk_box_pack_start( GTK_BOX( vbox ), spin->up, FALSE, FALSE, 0 );\n        gtk_box_pack_end( GTK_BOX( vbox ), spin->down, FALSE, FALSE, 0 );\n\tgtk_widget_show( spin->up );\n        gtk_widget_show( spin->down );\n}\n\nGtkType\nspin_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Spin\",\n\t\t\tsizeof( Spin ),\n\t\t\tsizeof( SpinClass ),\n\t\t\t(GtkClassInitFunc) spin_class_init,\n\t\t\t(GtkObjectInitFunc) spin_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_VIEW, &info );\n\t}\n\n\treturn( type );\n}\n\nGtkWidget *\nspin_new( void )\n{\n\tSpin *spin = (Spin *) gtk_type_new( TYPE_SPIN );\n\n\treturn( GTK_WIDGET( spin ) );\n}\n"
  },
  {
    "path": "src/spin.h",
    "content": "/* a pair of spin buttons\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_SPIN (spin_get_type())\n#define SPIN( obj ) (GTK_CHECK_CAST( (obj), TYPE_SPIN, Spin ))\n#define SPIN_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_SPIN, SpinClass ))\n#define IS_SPIN( obj ) (GTK_CHECK_TYPE( (obj), TYPE_SPIN ))\n#define IS_SPIN_CLASS( klass ) (GTK_CHECK_CLASS_TYPE( (klass), TYPE_SPIN ))\n\ntypedef struct _Spin {\n\tView view;\n\n\t/* My instance vars.\n\t */\n\tGtkWidget *up;\t\t\t\t/* Arrow buttons */\n\tGtkWidget *down;\n} Spin;\n\ntypedef struct _SpinClass {\n\tViewClass parent_class;\n\n\tvoid (*up_click)( Spin * );\n\tvoid (*down_click)( Spin * );\n} SpinClass;\n\nGtkType spin_get_type( void );\nGtkWidget *spin_new( void );\n"
  },
  {
    "path": "src/statusview.c",
    "content": "/* widgets for the status bar\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GtkFrameClass *parent_class = NULL;\n\n/* The popup menu.\n */\nstatic GtkWidget *statusview_menu = NULL;\n\n/* Sub. fn. of below. Junk the widgets inside a band display.\n */\nstatic void *\nstatusviewband_destroy_sub( StatusviewBand *svb )\n{\n\tDESTROY_GTK( svb->val );\n\tIM_FREE( svb );\n\n\treturn( NULL );\n}\n\n/* Junk the widgets inside a band display.\n */\nstatic void\nstatusviewband_destroy( Statusview *sv )\n{\t\n\tslist_map( sv->bands, \n\t\t(SListMapFn) statusviewband_destroy_sub, NULL );\n\tIM_FREEF( g_slist_free, sv->bands );\n}\n\nstatic void\nstatusview_destroy( GtkObject *object )\n{\n\tStatusview *sv;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_STATUSVIEW( object ) );\n\n\tsv = STATUSVIEW( object );\n\n#ifdef DEBUG\n\tprintf( \"statusview_destroy\\n\" );\n#endif /*DEBUG*/\n\n\tstatusviewband_destroy( sv );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\n/* Hide this statusview.\n */\nstatic void\nstatusview_hide_cb( GtkWidget *menu, GtkWidget *host, Statusview *sv )\n{\n\tsv->imagemodel->show_status = FALSE;\n\tiobject_changed( IOBJECT( sv->imagemodel ) );\n}\n\nstatic void\nstatusview_class_init( StatusviewClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\n\tGtkWidget *pane;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = statusview_destroy;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\n\tpane = statusview_menu = popup_build( _( \"Status bar menu\" ) );\n\tpopup_add_but( pane, GTK_STOCK_CLOSE, \n\t\tPOPUP_FUNC( statusview_hide_cb ) );\n}\n\nstatic void\nstatusview_init( Statusview *sv )\n{\n\tGtkWidget *vb, *hb;\n\tGtkWidget *eb;\n\n\tsv->imagemodel = NULL;\n\tsv->bands = NULL;\n\tsv->fmt = -1;\n\tsv->nb = -1;\n\n        gtk_frame_set_shadow_type( GTK_FRAME( sv ), GTK_SHADOW_OUT );\n\n\teb = gtk_event_box_new();\n        gtk_container_add( GTK_CONTAINER( sv ), eb );\n        popup_attach( eb, statusview_menu, sv );\n\n\tvb = gtk_vbox_new( FALSE, 0 );\n        gtk_container_set_border_width( GTK_CONTAINER( vb ), 1 );\n        gtk_container_add( GTK_CONTAINER( eb ), vb );\n\n\tsv->top = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( sv->top ), 0.0, 0.5 );\n        gtk_box_pack_start( GTK_BOX( vb ), sv->top, TRUE, TRUE, 0 );\n\n\thb = gtk_hbox_new( FALSE, 5 );\n        gtk_box_pack_start( GTK_BOX( vb ), hb, TRUE, TRUE, 0 );\n\n\tsv->pos = gtk_label_new( \"\" );\n\tset_fixed( sv->pos, strlen( \"(888888,888888)\" ) );\n        gtk_misc_set_alignment( GTK_MISC( sv->pos ), 0.0, 0.5 );\n        gtk_box_pack_start( GTK_BOX( hb ), sv->pos, FALSE, FALSE, 0 );\n\n\tsv->hb = gtk_hbox_new( FALSE, 5 );\n        gtk_box_pack_start( GTK_BOX( hb ), sv->hb, TRUE, TRUE, 0 );\n\n\tsv->mag = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( sv->mag ), 0.0, 0.5 );\n        gtk_box_pack_end( GTK_BOX( hb ), sv->mag, FALSE, FALSE, 0 );\n\n\tgtk_widget_show_all( eb );\n}\n\nGtkType\nstatusview_get_type( void )\n{\n\tstatic GtkType statusview_type = 0;\n\n\tif( !statusview_type ) {\n\t\tstatic const GtkTypeInfo sinfo = {\n\t\t\t\"Statusview\",\n\t\t\tsizeof( Statusview ),\n\t\t\tsizeof( StatusviewClass ),\n\t\t\t(GtkClassInitFunc) statusview_class_init,\n\t\t\t(GtkObjectInitFunc) statusview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tstatusview_type = \n\t\t\tgtk_type_unique( GTK_TYPE_FRAME, &sinfo );\n\t}\n\n\treturn( statusview_type );\n}\n\n/* Our model has changed ... update.\n */\nstatic void\nstatusview_changed_cb( Imagemodel *imagemodel, Statusview *sv )\n{\n\tstatic char *sample[] = {\n\t\t/* Sample text for each BandFmt. Used to try to get\n\t\t * the spacing right.\n\t\t */\n\t\t\"888\",\t\t\t\t/* uchar */\n\t\t\"-888\",\t\t\t\t/* char */\n\t\t\"88888\",\t\t\t/* ushort */\n\t\t\"-88888\",\t\t\t/* short */\n\t\t\"888888888\",\t\t\t/* int */\n\t\t\"-888888888\",\t\t\t/* uint */\n\t\t\"888888888\",\t\t\t/* float */\n\t\t\"(88888888,888888888)\",\t\t/* complex */\n\t\t\"88888888888\",\t\t\t/* double */\n\t\t\"(8888888888,888888888)\"\t/* dpcomplex */\n\t};\n\n\tConversion *conv = imagemodel->conv;\n\tiImage *iimage = imagemodel->iimage;\n\tIMAGE *im = imageinfo_get( FALSE, iimage->value.ii );\n\tdouble size = (double) im->Ysize * IM_IMAGE_SIZEOF_LINE( im );\n\tunsigned int nb;\n\tint fmt;\n\tchar txt[MAX_LINELENGTH];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n#ifdef DEBUG\n\tprintf( \"statusview_changed_cb: %p\\n\", imagemodel );\n#endif /*DEBUG*/\n\n\twidget_visible( GTK_WIDGET( sv ), imagemodel->show_status );\n\n\t/* If we're hidden, no need to do any more.\n\t */\n\tif( !imagemodel->show_status )\n\t\treturn;\n\n\tif( conv->mag > 0 )\n\t\tset_glabel( sv->mag, \"%s %d:1\", \n\t\t\t_( \"Magnification\" ), conv->mag );\n\telse\n\t\tset_glabel( sv->mag, \"%s 1:%d\", \n\t\t\t_( \"Magnification\" ), -conv->mag );\n\n\tvips_buf_appendf( &buf, \"%s, \", \n\t\tNN( IOBJECT( iimage )->caption ) );\n\tvips_buf_append_size( &buf, size );\n\tvips_buf_appendf( &buf, \", %.3gx%.3g p/mm\", im->Xres, im->Yres );\n\tset_gcaption( sv->top, \"%s\", vips_buf_all( &buf ) );\n\n\tif( im->Coding == IM_CODING_LABQ ||\n\t\tim->Coding == IM_CODING_RAD ) {\n\t\tnb = 3;\n\t\tfmt = 6;\n\t}\n\telse {\n\t\tnb = im->Bands;\n\t\tfmt = im->BandFmt;\n\t}\n\n\tif( sv->nb != nb || sv->fmt != fmt ) {\n\t\t/* Bands/fmt has changed ... rebuild band display widgets.\n\t\t */\n\t\tunsigned int i;\n\t\tint width;\n\n\t\tstatusviewband_destroy( sv );\n\t\tsv->fmt = fmt;\n\t\tsv->nb = nb;\n\t\tif( sv->fmt >= 0 && sv->fmt < IM_NUMBER( sample ) )\n\t\t\twidth = strlen( sample[sv->fmt] );\n\t\telse\n\t\t\twidth = 10;\n\n\t\t/* Don't display more than 8 bands ... it'll make the window\n\t\t * too large.\n\n\t\t \tFIXME ... now very kewl\n\n\t\t */\n\t\tfor( i = 0; i < IM_MIN( 8, nb ); i++ ) {\n\t\t\tStatusviewBand *band = INEW( NULL, StatusviewBand );\n\n\t\t\tband->sv = sv;\n\t\t\tband->bandno = i;\n\t\t\tband->val = gtk_label_new( \"\" );\n\t\t\tgtk_misc_set_alignment( GTK_MISC( band->val ), \n\t\t\t\t0.0, 0.5 );\n\t\t\tset_fixed( band->val, width );\n\t\t\tgtk_box_pack_start( GTK_BOX( sv->hb ), \n\t\t\t\tband->val, FALSE, FALSE, 0 );\n\t\t\tgtk_widget_show( band->val );\n\n\t\t\tsv->bands = g_slist_append( sv->bands, band );\n\t\t}\n\t}\n}\n\nstatic void\nstatusview_link( Statusview *sv, Imagemodel *imagemodel )\n{\n\tsv->imagemodel = imagemodel;\n\tg_signal_connect( G_OBJECT( sv->imagemodel ), \n\t\t\"changed\", G_CALLBACK( statusview_changed_cb ), sv );\n}\n\nStatusview *\nstatusview_new( Imagemodel *imagemodel )\n{\n\tStatusview *sv = gtk_type_new( TYPE_STATUSVIEW );\n\n\tstatusview_link( sv, imagemodel );\n\n\treturn( sv );\n}\n\n/* Turn a IM_CODING_LABQ 4-band image into three floats.\n */\nstatic void\nstatusview_mouse_LABPACK( Statusview *sv, int x, int y )\n{\n\tImagemodel *imagemodel = sv->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tGSList *bands = sv->bands;\n\n\t/* Three widgets we update.\n\t */\n\tStatusviewBand *b1;\n\tStatusviewBand *b2;\n\tStatusviewBand *b3;\n\n\tunsigned char *e = \n\t\t(unsigned char *) get_element( conv->reg, x, y, 0 );\n\n\tunsigned int iL = (e[0] << 2) | (e[3] >> 6);\n\tfloat L = 100.0 * iL / 1023.0;\n\tsigned int ia = ((signed char) e[1] << 3) | ((e[3] >> 3) & 0x7);\n\tfloat a = 0.125 * ia;\n\tsigned int ib = ((signed char) e[2] << 3) | (e[3] & 0x7);\n\tfloat b = 0.125 * ib;\n\n\tif( g_slist_length( sv->bands ) == 3 ) {\n\t\tb1 = (StatusviewBand *) bands->data;\n\t\tb2 = (StatusviewBand *) bands->next->data;\n\t\tb3 = (StatusviewBand *) bands->next->next->data;\n\n\t\tset_glabel( b1->val, \"%g\", L );\n\t\tset_glabel( b2->val, \"%g\", a );\n\t\tset_glabel( b3->val, \"%g\", b );\n\t}\n}\n\n/* Turn a IM_CODING_RAD 4-band image into three floats.\n */\nstatic void\nstatusview_mouse_RAD( Statusview *sv, int x, int y )\n{\n\tImagemodel *imagemodel = sv->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tGSList *bands = sv->bands;\n\n\t/* Three widgets we update.\n\t */\n\tStatusviewBand *b1;\n\tStatusviewBand *b2;\n\tStatusviewBand *b3;\n\n\tunsigned char *e = \n\t\t(unsigned char *) get_element( conv->reg, x, y, 0 );\n\n\tdouble f = ldexp( 1.0, e[3] - (128 + 8) );\n\tfloat r = (e[0] + 0.5) * f;\n\tfloat g = (e[1] + 0.5) * f;\n\tfloat b = (e[2] + 0.5) * f;\n\n\tif( g_slist_length( sv->bands ) == 3 ) {\n\t\tb1 = (StatusviewBand *) bands->data;\n\t\tb2 = (StatusviewBand *) bands->next->data;\n\t\tb3 = (StatusviewBand *) bands->next->next->data;\n\n\t\tset_glabel( b1->val, \"%g\", r );\n\t\tset_glabel( b2->val, \"%g\", g );\n\t\tset_glabel( b3->val, \"%g\", b );\n\t}\n}\n\n/* Sub-fn of below. Remake a band in the bar.\n */\nstatic void *\nstatusview_mouse_band( StatusviewBand *svb, void *e )\n{\n\tImagemodel *imagemodel = svb->sv->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tREGION *reg = conv->reg;\n\tIMAGE *im = reg->im;\n\n\t/* Generate string for contents of band element.\n\t */\n\tif( im->Coding == IM_CODING_NONE )\n\t\tswitch( im->BandFmt ) {\n\t\tcase IM_BANDFMT_UCHAR:\n\t\t\tset_glabel( svb->val, \"%d\", \n\t\t\t\t((unsigned char *)e)[svb->bandno] );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_CHAR:\n\t\t\tset_glabel( svb->val, \"%d\", \n\t\t\t\t((char *)e)[svb->bandno] );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_USHORT:\n\t\t\tset_glabel( svb->val, \"%d\", \n\t\t\t\t((unsigned short *)e)[svb->bandno] );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_SHORT:\n\t\t\tset_glabel( svb->val, \"%d\", \n\t\t\t\t((short *)e)[svb->bandno] );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_UINT:\n\t\t\tset_glabel( svb->val, \"%u\", \n\t\t\t\t((unsigned int *)e)[svb->bandno] );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_INT:\n\t\t\tset_glabel( svb->val, \"%d\", \n\t\t\t\t((int *)e)[svb->bandno] );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_FLOAT:\n\t\t\tset_glabel( svb->val, \"%g\", \n\t\t\t\t((float *)e)[svb->bandno] );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_COMPLEX:\n\t\t\tset_glabel( svb->val, \"(%g,%g)\", \n\t\t\t\t((float *)e)[svb->bandno << 1], \n\t\t\t\t((float *)e)[(svb->bandno << 1) + 1] );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_DOUBLE:\n\t\t\tset_glabel( svb->val, \"%g\", \n\t\t\t\t((double *)e)[svb->bandno] );\n\t\t\tbreak;\n\t\t\t\n\t\tcase IM_BANDFMT_DPCOMPLEX:\n\t\t\tset_glabel( svb->val, \"(%g,%g)\", \n\t\t\t\t((double *)e)[svb->bandno << 1], \n\t\t\t\t((double *)e)[(svb->bandno << 1) + 1] );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tset_glabel( svb->val, \"???\" );\n\t\t\tbreak;\n\t\t}\n\telse\n\t\tset_glabel( svb->val, \"???\" );\n\n\treturn( NULL );\n}\n\nvoid \nstatusview_mouse( Statusview *sv, int x, int y )\n{\n\tImagemodel *imagemodel = sv->imagemodel;\n\tConversion *conv = imagemodel->conv;\n\tIMAGE *im = imageinfo_get( FALSE, conv->ii );\n\tREGION *reg = conv->reg;\n\tdouble dx, dy;\n\n\tx = IM_CLIP( 0, x, conv->underlay.width - 1 );\n\ty = IM_CLIP( 0, y, conv->underlay.height - 1 );\n\n\t/* Calculate x/y pos we display.\n\t */\n\tdx = x;\n\tdy = y;\n\n\tif( imagemodel->rulers_offset ) {\n\t\tdx -= im->Xoffset;\n\t\tdy -= im->Yoffset;\n\t}\n\n\tif( imagemodel->rulers_mm ) {\n\t\tdx /= im->Xres;\n\t\tdy /= im->Yres;\n\t}\n\n\tset_glabel( sv->pos, \"(%5g, %5g)\", dx, dy ); \n\n\t/* Update value list.\n\t */\n\tif( reg ) {\n\t\tif( reg->im->Coding == IM_CODING_LABQ )\n\t\t\tstatusview_mouse_LABPACK( sv, x, y );\n\t\telse if( reg->im->Coding == IM_CODING_RAD )\n\t\t\tstatusview_mouse_RAD( sv, x, y );\n\t\telse\n\t\t\tslist_map( sv->bands, \n\t\t\t\t(SListMapFn) statusview_mouse_band, \n\t\t\t\tget_element( reg, x, y, 0 ) );\n\t}\n}\n"
  },
  {
    "path": "src/statusview.h",
    "content": "/* Decls for statusview.c ... display image info and mouse posn\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_STATUSVIEW (statusview_get_type())\n#define STATUSVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_STATUSVIEW, Statusview ))\n#define STATUSVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_STATUSVIEW, StatusviewClass ))\n#define IS_STATUSVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_STATUSVIEW ))\n#define IS_STATUSVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_STATUSVIEW ))\n\n/* A band element display in the status bar.\n */\ntypedef struct _StatusviewBand {\n\tStatusview *sv;\t\t/* Bar we're in */\n\tint bandno;\t\t/* Band we extract */\n\tGtkWidget *val;\t\t/* Label we write to */\n} StatusviewBand;\n\nstruct _Statusview {\n\tGtkFrame parent_class;\n\n\tImagemodel *imagemodel;\n\tguint changed_sid;\n\n\tGtkWidget *top;\t\t/* Top label */\n\tGtkWidget *pos;\t\t/* Position */\n\tGtkWidget *hb;\t\t/* Band element hbox */\n\tGtkWidget *mag;\t\t/* Magnification display */\n\tGSList *bands;\t\t/* List of StatusviewBand */\n\tint nb;\t\t\t/* Last number of bands we saw */\n\tint fmt;\t\t/* The last bandfmt we set ... for spacing */\n};\n\ntypedef struct _StatusviewClass {\n\tGtkFrameClass parent_class;\n\n\t/* My methods.\n\t */\n} StatusviewClass;\n\nGtkType statusview_get_type( void );\nStatusview *statusview_new( Imagemodel *imagemodel );\n\nvoid statusview_mouse( Statusview *sv, int x, int y );\n"
  },
  {
    "path": "src/string.c",
    "content": "/* an editable string\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic void\nstring_finalize( GObject *gobject )\n{\n\tString *string;\n\n#ifdef DEBUG\n\tprintf( \"string_finalize\\n\" );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_STRING( gobject ) );\n\n\tstring = STRING( gobject );\n\n\tIM_FREE( string->value );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic View *\nstring_view_new( Model *model, View *parent )\n{\n\treturn( stringview_new() );\n}\n\n/* Members of string we automate.\n */\nstatic ClassmodelMember string_members[] = {\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_CAPTION, \"caption\", N_( \"Caption\" ),\n\t\tG_STRUCT_OFFSET( iObject, caption ) },\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_VALUE, \"value\", N_( \"Value\" ),\n\t\tG_STRUCT_OFFSET( String, value ) }\n};\n\nstatic void\nstring_class_init( StringClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Init methods.\n\t */\n\tgobject_class->finalize = string_finalize;\n\n\tmodel_class->view_new = string_view_new;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n\n\tclassmodel_class->members = string_members;\n\tclassmodel_class->n_members = IM_NUMBER( string_members );\n}\n\nstatic void\nstring_init( String *string )\n{\n\tstring->value = NULL;\n\tIM_SETSTR( string->value, \"\" );\n\n\tiobject_set( IOBJECT( string ), CLASS_STRING, NULL );\n}\n\nGType\nstring_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( StringClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) string_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( String ),\n\t\t\t32,             /* n_pstringlocs */\n\t\t\t(GInstanceInitFunc) string_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"String\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/stringview.c",
    "content": "/* a view of a text thingy\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic EditviewClass *parent_class = NULL;\n\n/* Re-read the text in a tally entry. \n */\nstatic void *\nstringview_scan( View *view )\n{\n\tStringview *stringview = STRINGVIEW( view );\n\tString *string = STRING( VOBJECT( stringview )->iobject );\n    \tExpr *expr = HEAPMODEL( string )->row->expr;\n\tchar value[MAX_STRSIZE];\n\tchar value2[MAX_STRSIZE];\n\n#ifdef DEBUG\n\tRow *row = HEAPMODEL( string )->row;\n\n\tprintf( \"stringview_scan: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\texpr_error_clear( expr );\n\n\tif( !get_geditable_string( EDITVIEW( stringview )->text, \n\t\tvalue, MAX_STRSIZE ) ) {\n\t\texpr_error_set( expr );\n\t\treturn( view );\n\t}\n\tmy_strccpy( value2, value );\n\n\tif( strcmp( string->value, value2 ) != 0 ) {\n\t\tIM_SETSTR( string->value, value2 );\n\t\tclassmodel_update( CLASSMODEL( string ) ) ;\n\t}\n\n\treturn( VIEW_CLASS( parent_class )->scan( view ) );\n}\n\nstatic void \nstringview_refresh( vObject *vobject )\n{\n\tStringview *stringview = STRINGVIEW( vobject );\n\tString *string = STRING( VOBJECT( stringview )->iobject );\n\n#ifdef DEBUG\n\tRow *row = HEAPMODEL( string )->row;\n\n\tprintf( \"stringview_refresh: \" );\n\trow_name_print( row );\n\tprintf( \" (%p)\\n\", vobject );\n#endif /*DEBUG*/\n\n\tif( string->value ) {\n\t\tchar txt[MAX_STRSIZE];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\tvips_buf_appendsc( &buf, FALSE, string->value );\n\t\teditview_set_entry( EDITVIEW( stringview ), \n\t\t\t\"%s\", vips_buf_all( &buf ) );\n\t}\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\nstringview_class_init( StringviewClass *class )\n{\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = stringview_refresh;\n\n\tview_class->scan = stringview_scan;\n}\n\nstatic void\nstringview_init( Stringview *stringview )\n{\n}\n\nGtkType\nstringview_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Stringview\",\n\t\t\tsizeof( Stringview ),\n\t\t\tsizeof( StringviewClass ),\n\t\t\t(GtkClassInitFunc) stringview_class_init,\n\t\t\t(GtkObjectInitFunc) stringview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_EDITVIEW, &info );\n\t}\n\n\treturn( type );\n}\n\nView *\nstringview_new( void )\n{\n\tStringview *stringview = gtk_type_new( TYPE_STRINGVIEW );\n\n\treturn( VIEW( stringview ) );\n}\n"
  },
  {
    "path": "src/stringview.h",
    "content": "/* edit a string\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_STRINGVIEW (stringview_get_type())\n#define STRINGVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_STRINGVIEW, Stringview ))\n#define STRINGVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_STRINGVIEW, StringviewClass ))\n#define IS_STRINGVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_STRINGVIEW ))\n#define IS_STRINGVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_STRINGVIEW ))\n\ntypedef struct _Stringview {\n\tEditview parent_object;\n\n} Stringview;\n\ntypedef struct _StringviewClass {\n\tEditviewClass parent_class;\n\n\t/* My methods.\n\t */\n} StringviewClass;\n\nGtkType stringview_get_type( void );\nView *stringview_new( void );\n"
  },
  {
    "path": "src/subcolumn.c",
    "content": "/* a subcolumn \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic HeapmodelClass *parent_class = NULL;\n\nstatic gboolean\nsubcolumn_row_pred_none( Row *row )\n{\n\treturn( FALSE );\n}\n\n/* No params, no super.\n */\nstatic gboolean\nsubcolumn_row_pred_members( Row *row )\n{\n\tif( row->sym &&\n\t\tis_system( row->sym ) )\n\t\treturn( FALSE );\n\n\tif( row->sym &&\n\t\tis_super( row->sym ) )\n\t\treturn( FALSE );\n\n\tif( row->sym &&\n\t\trow->sym->type == SYM_PARAM )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic gboolean\nsubcolumn_row_pred_params( Row *row )\n{\n\treturn( row->sym && \n\t\trow->sym->type == SYM_PARAM );\n}\n\n/* Everything but empty superclasses.\n */\nstatic gboolean\nsubcolumn_row_pred_super( Row *row )\n{\n\tif( row->sym &&\n\t\tis_super( row->sym ) && \n\t\tPEISELIST( &row->expr->root ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Array of these guys control member visibility, scol->vislevel indexes this\n * array, one of preds from vislevel down has to be TRUE for the row to be\n * visible.\n */\nconst SubcolumnVisibility subcolumn_visibility[] = {\n\t{ \"none\", subcolumn_row_pred_none },\n\t{ \"members\", subcolumn_row_pred_members },\n\t{ \"params\", subcolumn_row_pred_params },\n\t{ \"super\", subcolumn_row_pred_super }\n};\nconst int subcolumn_nvisibility = IM_NUMBER( subcolumn_visibility );\n\n/* Map down a Subcolumn.\n */\nvoid *\nsubcolumn_map( Subcolumn *scol, row_map_fn fn, void *a, void *b )\n{\n\treturn( icontainer_map( ICONTAINER( scol ), \n\t\t(icontainer_map_fn) fn, a, b ) );\n}\n\nstatic void\nsubcolumn_dispose( GObject *gobject )\n{\n\tSubcolumn *scol;\n\n#ifdef DEBUG\n\tprintf( \"subcolumn_dispose\\n\" );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_SUBCOLUMN( gobject ) );\n\n\tscol = SUBCOLUMN( gobject );\n\n\tscol->col = NULL;\n\tscol->scol = NULL;\n\tscol->top_col = NULL;\n\n\theap_unregister_element( reduce_context->heap, &scol->base );\n\tscol->base.type = ELEMENT_NOVAL;\n\tscol->base.ele = (void *) 13;\n\n\tscol->this = NULL;\n\tscol->super = NULL;\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\n/* Stuff we track during class instance display update.\n */\ntypedef struct {\n\tSubcolumn *scol;\t\t/* Enclosing column */\n\tGSList *notused;\t\t/* List of row we've not used */\n} ClassRefreshInfo;\n\n/* Test for row represents a sym.\n */\nstatic void *\nsubcolumn_test_sym( Row *row, Symbol *sym )\n{\n\tif( row->sym == sym )\n\t\treturn( row );\n\n\treturn( NULL );\n}\n\n/* Test for row has a zombie of the same name.\n */\nstatic void *\nsubcolumn_test_row_name( Row *row, Symbol *sym )\n{\n\tif( !row->sym && \n\t\tstrcmp( IOBJECT( row )->name, IOBJECT( sym )->name ) == 0 )\n\t\treturn( row );\n\n\treturn( NULL );\n}\n\n/* Refresh one line of a subcolumn.\n */\nstatic void\nsubcolumn_class_new_heap_sub( ClassRefreshInfo *cri,\n\tSymbol *sym, PElement *value )\n{\n\tRow *row;\n\n#ifdef DEBUG\n\tchar txt[200];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tsymbol_qualified_name( sym, &buf );\n\tprintf( \"subcolumn_class_new_heap_sub: %s\\n\", vips_buf_all( &buf ) );\n#endif /*DEBUG*/\n\n\t/* Do we have a row for this symbol?\n\t */\n\tif( (row = (Row *) slist_map( cri->notused, \n\t\t(SListMapFn) subcolumn_test_sym, sym )) ) {\n\t\t/* Update it.\n\t\t */\n\t\tif( heapmodel_new_heap( HEAPMODEL( row ), value ) ) \n\t\t\texpr_error_set( row->expr );\n\n\t\tcri->notused = g_slist_remove( cri->notused, row );\n\t}\n\telse if( (row = (Row *) slist_map( cri->notused, \n\t\t(SListMapFn) subcolumn_test_row_name, sym )) ) {\n\t\t/* There's a blank row of the same name, left for us by XML \n\t\t * load. Update the row with the correct symbol.\n\t\t */\n\t\trow_link_symbol( row, sym, NULL );\n\t\tif( heapmodel_new_heap( HEAPMODEL( row ), value ) ) \n\t\t\texpr_error_set( row->expr );\n\n\t\tcri->notused = g_slist_remove( cri->notused, row );\n\t}\n\telse {\n\t\trow = row_new( cri->scol, sym, value );\n\t\tif( heapmodel_new_heap( HEAPMODEL( row ), value ) ) \n\t\t\texpr_error_set( row->expr );\n\t}\n}\n\n#ifdef DEBUG\nstatic void *\nsubcolumn_class_dump_tiny_row( Row *row )\n{\n\trow_name_print( row );\n\tprintf( \" \" );\n\n\treturn( NULL );\n}\n#endif /*DEBUG*/\n\n/* A new scrap of heap for a subcolumn.\n */\nstatic gboolean\nsubcolumn_class_new_heap( Subcolumn *scol, PElement *root )\n{\n\tPElement instance = *root;\n\n\tExpr *expr;\n\tRow *row;\n\tgboolean result;\n\tPElement base, member;\n\tHeapNode *p;\n\tClassRefreshInfo cri;\n\n\t/* Must be a class display.\n\t */\n\tg_assert( !scol->is_top );\n\trow = HEAPMODEL( scol )->row;\n\texpr = row->expr;\n\n#ifdef DEBUG\n\tprintf( \"subcolumn_class_new_heap: \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Can loop here for some recursive classes.\n\n\t\tFIXME\n\n\tif( mainw_countdown_animate( 99 ) )\n\t\treturn( FALSE );\n\t */\n\n\t/* No displays for system rows.\n\t */\n\tif( row->sym &&\n\t\tis_system( row->sym ) )\n\t\treturn( TRUE );\n\n\t/* If we are the top of a class instance display, get a new serial.\n\t * As we recurse down refreshing our contents, this should stop \n\t * circular structures looping the browser.\n\n\t \tFIXME ... clear flags for a whole class, then do a complete\n\t\tredisplay? more reliable, but even slower :-(\n\n\t */\n\tif( scol->scol->is_top )\n\t\theap_serial_new( reduce_context->heap );\n\n\t/* Is it a class with a typecheck member? Go through\n\t * that. Do an isclass first to force eval.\n\t */\n\tif( !heap_is_class( &instance, &result ) )\n\t\treturn( FALSE );\n\tif( result &&\n\t\tclass_get_member( &instance, MEMBER_CHECK, NULL, &member ) ) {\n#ifdef DEBUG\n\t\tprintf( \"subcolumn_class_new_heap: invoking arg checker\\n\" );\n#endif \n\n\t\t/* Force eval of the typecheck member.\n\t\t */\n\t\tif( !heap_is_class( &member, &result ) || !result )\n\t\t\treturn( FALSE );\n\t}\n\n\t/* Have we already displayed this class?\n\t */\n\tif( (PEGETVAL( &instance )->flgs & FLAG_SERIAL) == \n\t\treduce_context->heap->serial ) {\n\t\t/* \n\t\t\n\t\t\tFIXME ... display something here? \"circular\"?\n\n\t\t */\n\t\treturn( TRUE );\n\t}\n\tSETSERIAL( PEGETVAL( &instance )->flgs, reduce_context->heap->serial );\n\n\t/* Note the heap root ... if this is the top of a row tree, then we\n\t * clone the class and use that private copy.\n\t */\n\tPEPOINTE( &base, &(SUBCOLUMN( scol ))->base );\n\tPEPUTPE( &base, &instance );\n\tPEPUTPE( &expr->root, &base );\n\n\t/* Init rebuild params. We make a list of all the existing\n\t * row objects for this class display, and every time we\n\t * manage to reuse one of them, we knock it off the list. At the\n\t * end, remove all unused rows.\n\t */\n\tcri.scol = scol;\n\tcri.notused = g_slist_copy( ICONTAINER( scol )->children );\n\n#ifdef DEBUG\n\tprintf( \"subcolumn_class_new_heap: existing rows: \" );\n\ticontainer_map( ICONTAINER( scol ), \n\t\t(icontainer_map_fn) subcolumn_class_dump_tiny_row, NULL, NULL );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Loop along the members, updating row entries.\n\t */\n\tPEGETCLASSMEMBER( &member, &base );\n\n\tif( PEISNODE( &member ) )\n\t\tfor( p = PEGETVAL( &member ); p; p = GETRIGHT( p ) ) {\n\t\t\tPElement s, v;\n\t\t\tHeapNode *hn;\n\t\t\tSymbol *sym;\n\n\t\t\t/* Get the sym/value pair.\n\t\t\t */\n\t\t\thn = GETLEFT( p );\n\t\t\tPEPOINTLEFT( hn, &s );\n\t\t\tPEPOINTRIGHT( hn, &v );\n\t\t\tsym = SYMBOL( PEGETSYMREF( &s ) );\n\n\t\t\t/* We don't make rows for the default constructor, or\n\t\t\t * for \".name\". These things don't change, so there's\n\t\t\t * no point (and the default constructor has no text\n\t\t\t * equivalent anyway).\n\t\t\t */\n\t\t\tif( strcmp( IOBJECT( sym )->name, MEMBER_NAME ) == 0 )\n\t\t\t\tcontinue;\n\t\t\tif( is_member( sym ) && \n\t\t\t\tstrcmp( IOBJECT( sym )->name, \n\t\t\t\tIOBJECT( symbol_get_parent( sym ) )->name ) == \n\t\t\t\t0 )\n\t\t\t\tcontinue;\n\n\t\t\t/* Display!\n\t\t\t */\n\t\t\tsubcolumn_class_new_heap_sub( &cri, sym, &v );\n\t\t}\n\n\t/* Remove all the rows we've not used. \n\t */\n\tslist_map( cri.notused, (SListMapFn) iobject_destroy, NULL );\n\tIM_FREEF( g_slist_free, cri.notused );\n\n\treturn( TRUE );\n}\n\nstatic void *\nsubcolumn_new_heap( Heapmodel *heapmodel, PElement *root )\n{\n\tSubcolumn *scol = SUBCOLUMN( heapmodel );\n\n\t/* New heap for a class display? CLear known_private, we've no idea\n\t * where this heap came from.\n\t */\n\tif( scol == scol->top_scol )\n\t\tscol->known_private = FALSE;\n\n\t/* A bunch of locals? Update them all.\n\t */\n\tif( !scol->is_top && !subcolumn_class_new_heap( scol, root ) )\n\t\treturn( scol );\n\n\treturn( HEAPMODEL_CLASS( parent_class )->new_heap( heapmodel, root ) );\n}\n\nstatic void\nsubcolumn_child_add( iContainer *parent, iContainer *child, int pos )\n{\n\tSubcolumn *scol = SUBCOLUMN( parent );\n\tRow *row = ROW( child );\n\n\t/* May not have a symbol yet during ws load.\n\t *\n\t * Can't use is_this()/is_super(), not everything has been built yet.\n\t * We don't do this often, so strcmp() it.\n\t */\n\tconst char *name = \n\t\trow->sym ? IOBJECT( row->sym )->name : IOBJECT( row )->name;\n\n\tif( strcmp( name, MEMBER_THIS ) == 0 ) \n\t\tscol->this = row;\n\n\tif( strcmp( name, MEMBER_SUPER ) == 0 ) \n\t\tscol->super = row;\n\n\tICONTAINER_CLASS( parent_class )->child_add( parent, child, pos );\n}\n\nstatic void\nsubcolumn_child_remove( iContainer *parent, iContainer *child )\n{\n\tSubcolumn *scol = SUBCOLUMN( parent );\n\tRow *row = ROW( child );\n\n\tICONTAINER_CLASS( parent_class )->child_remove( parent, child );\n\n\tif( scol->this == row )\n\t\tscol->this = NULL;\n\tif( scol->super == row )\n\t\tscol->super = NULL;\n}\n\n/* If this is a top-level subcolumn, get the enclosing column.\n */\nstatic Column *\nsubcolumn_get_column( Subcolumn *scol )\n{\n\tg_assert( scol->is_top );\n\n\treturn( COLUMN( ICONTAINER( scol )->parent ) );\n}\n\n/* If this is a nested subcolumn, get the enclosing subcolumn.\n */\nstatic Subcolumn *\nsubcolumn_get_subcolumn( Subcolumn *scol )\n{\n\tRhs *rhs;\n\tRow *row;\n\tSubcolumn *escol;\n\n\tg_assert( !scol->is_top );\n\n\trhs = HEAPMODEL( scol )->rhs;\n\trow = HEAPMODEL( rhs )->row;\n\tescol = row->scol;\n\n\treturn( escol );\n}\n\n/* Return the enclosing column for a Subcolumn.\n */\nstatic Column *\nsubcolumn_get_top_column( Subcolumn *scol )\n{\n\tif( !scol->is_top ) \n\t\treturn( subcolumn_get_top_column( \n\t\t\tsubcolumn_get_subcolumn( scol ) ) );\n\n\treturn( subcolumn_get_column( scol ) );\n}\n\n/* Return the enclosing subcolumn ... but not the is_top one. Ie. the enclosing\n * subcolumn which has the base for this class tree.\n */\nstatic Subcolumn *\nsubcolumn_get_top_subcolumn( Subcolumn *scol )\n{\n\tSubcolumn *enclosing;\n\n\tif( scol->is_top )\n\t\treturn( NULL );\n\n\tenclosing = subcolumn_get_subcolumn( scol );\n\tif( enclosing->is_top )\n\t\treturn( scol );\n\telse \n\t\treturn( subcolumn_get_top_subcolumn( enclosing ) );\n}\n\nstatic void\nsubcolumn_parent_add( iContainer *child )\n{\n\tSubcolumn *scol = SUBCOLUMN( child );\n\n\tICONTAINER_CLASS( parent_class )->parent_add( child );\n\n\tg_assert( IS_COLUMN( child->parent ) || IS_RHS( child->parent ) );\n\tg_assert( !IS_COLUMN( child->parent ) || \n\t\tg_slist_length( child->parent->children ) == 1 );\n\n\tscol->is_top = IS_COLUMN( child->parent );\n\n\t/* For sub-columns, default to nothing visible.\n\t */\n\tif( !scol->is_top )\n\t\tscol->vislevel = 0;\n\n\t/* Update context pointers.\n\t */\n\tif( scol->is_top )\n\t\tscol->col = subcolumn_get_column( scol );\n\telse\n\t\tscol->col = NULL;\n\n\tif( !scol->is_top )\n\t\tscol->scol = subcolumn_get_subcolumn( scol );\n\telse\n\t\tscol->scol = NULL;\n\n\tscol->top_col = subcolumn_get_top_column( scol );\n\tscol->top_scol = subcolumn_get_top_subcolumn( scol );\n\n\t/* Top level subcolumns default to display on, others to display off.\n\t */\n\tMODEL( scol )->display = scol->is_top;\n}\n\nstatic View *\nsubcolumn_view_new( Model *model, View *parent )\n{\n\treturn( subcolumnview_new() );\n}\n\nstatic void\nsubcolumn_display( Model *model, gboolean display )\n{\n\t/*\n\tprintf( \"subcolumn_display: \" ); \n\trow_name_print( HEAPMODEL( model )->row );\n\tprintf( \" %d\\n\", display ); \n\t */\n\n\tMODEL_CLASS( parent_class )->display( model, display );\n}\n\nstatic gboolean\nsubcolumn_load( Model *model, \n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\tSubcolumn *scol = SUBCOLUMN( model );\n\n\tg_assert( IS_COLUMN( parent ) || IS_RHS( parent ) );\n\n\tif( !get_iprop( xnode, \"vislevel\", &scol->vislevel ) )\n\t\treturn( FALSE );\n\n\tif( !MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic xmlNode *\nsubcolumn_save( Model *model, xmlNode *xnode )\n{\n\tSubcolumn *scol = SUBCOLUMN( model );\n\n\txmlNode *xthis;\n\n\tif( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )\n\t\treturn( NULL );\n\n\tif( !set_iprop( xthis, \"vislevel\", scol->vislevel ) )\n\t\treturn( NULL );\n\n\treturn( xthis );\n}\n\nstatic void\nsubcolumn_class_init( SubcolumnClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiContainerClass *icontainer_class = (iContainerClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tHeapmodelClass *heapmodel_class = (HeapmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->dispose = subcolumn_dispose;\n\n\ticontainer_class->child_add = subcolumn_child_add;\n\ticontainer_class->child_remove = subcolumn_child_remove;\n\ticontainer_class->parent_add = subcolumn_parent_add;\n\n\tmodel_class->view_new = subcolumn_view_new;\n\tmodel_class->display = subcolumn_display;\n\tmodel_class->load = subcolumn_load;\n\tmodel_class->save = subcolumn_save;\n\n\theapmodel_class->new_heap = subcolumn_new_heap;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\nsubcolumn_init( Subcolumn *scol )\n{\n#ifdef DEBUG\n\tprintf( \"subcolumn_init\\n\" );\n#endif /*DEBUG*/\n\n\tscol->col = NULL;\n\tscol->scol = NULL;\n\tscol->top_col = NULL;\n\n        scol->vislevel = subcolumn_nvisibility - 1;\n\n\tscol->base.type = ELEMENT_NOVAL;\n\tscol->base.ele = (void *) 14;\n\theap_register_element( reduce_context->heap, &scol->base );\n\tscol->known_private = FALSE;\n\n\tscol->this = NULL;\n\tscol->super = NULL;\n}\n\nGType\nsubcolumn_get_type( void )\n{\n\tstatic GType subcolumn_type = 0;\n\n\tif( !subcolumn_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( SubcolumnClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) subcolumn_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Subcolumn ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) subcolumn_init,\n\t\t};\n\n\t\tsubcolumn_type = g_type_register_static( TYPE_HEAPMODEL, \n\t\t\t\"Subcolumn\", &info, 0 );\n\t}\n\n\treturn( subcolumn_type );\n}\n\nstatic void\nsubcolumn_link( Subcolumn *scol, Rhs *rhs, Column *col )\n{\n\tg_assert( rhs == NULL || col == NULL );\n\n\t/* parent_add() sets is_top for us.\n\t */\n\tif( rhs ) \n\t\ticontainer_child_add( ICONTAINER( rhs ), \n\t\t\tICONTAINER( scol ), -1 );\n\telse \n\t\ticontainer_child_add( ICONTAINER( col ), \n\t\t\tICONTAINER( scol ), -1 );\n}\n\nSubcolumn *\nsubcolumn_new( Rhs *rhs, Column *col )\n{\n\tSubcolumn *scol;\n\n\tscol = SUBCOLUMN( g_object_new( TYPE_SUBCOLUMN, NULL ) );\n\tsubcolumn_link( scol, rhs, col );\n\n\treturn( scol );\n}\n\nvoid\nsubcolumn_set_vislevel( Subcolumn *scol, int vislevel )\n{\n\tscol->vislevel = IM_CLIP( 0, vislevel, subcolumn_nvisibility - 1 );\n\n#ifdef DEBUG\n\tprintf( \"subcolumn_set_vislevel: %d\\n\", scol->vislevel );\n#endif /*DEBUG*/\n\n\tiobject_changed( IOBJECT( scol ) );\n}\n\n/* Make sure we have a private copy of the graph for this tree of stuff.\n */\ngboolean\nsubcolumn_make_private( Subcolumn *scol )\n{\n\tSubcolumn *top_scol = scol->top_scol;\n\tPElement base;\n\n\tif( !top_scol || top_scol->known_private )\n\t\treturn( TRUE );\n\n#ifdef DEBUG\n{\n\tRow *row = HEAPMODEL( top_scol )->row;\n\n\tprintf( \"subcolumn_make_private: cloning \" );\n\trow_name_print( row );\n\tprintf( \"\\n\" );\n}\n#endif /*DEBUG*/\n\n\t/* Clone from the class args and rebuild our tree.\n\t */\n\tPEPOINTE( &base, &top_scol->base );\n\tif( !class_clone_args( reduce_context->heap, &base, &base ) ||\n\t\theapmodel_new_heap( HEAPMODEL( top_scol ), &base ) )\n\t\treturn( FALSE );\n\n\ttop_scol->known_private = TRUE;\n\n\treturn( TRUE );\n}\n\n"
  },
  {
    "path": "src/subcolumn.h",
    "content": "/* a column of rows in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_SUBCOLUMN (subcolumn_get_type())\n#define SUBCOLUMN( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_SUBCOLUMN, Subcolumn ))\n#define SUBCOLUMN_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_SUBCOLUMN, SubcolumnClass))\n#define IS_SUBCOLUMN( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_SUBCOLUMN ))\n#define IS_SUBCOLUMN_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_SUBCOLUMN ))\n#define SUBCOLUMN_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_SUBCOLUMN, SubcolumnClass ))\n\n/* Predicate on a row.\n */\ntypedef gboolean (*RowPred)( Row * );\n\n/* Control class member visibility with these.\n */\ntypedef struct {\n\tconst char *name;\n\tRowPred pred;\n} SubcolumnVisibility;\n\nstruct _Subcolumn {\n\tHeapmodel parent_class;\n\n\t/* Our context.\n\t */\n\tColumn *col;\t\t/* Enclosing column (or NULL) */\n\tSubcolumn *scol;\t/* Enclosing subcolumn (or NULL) */\n\tColumn *top_col;\t/* Topmost enclosing column */\n\tSubcolumn *top_scol;\t/* Topmost enclosing subcolumn */\n\n\tint vislevel;\t\t/* Visibility level */\n\tgboolean is_top;\t/* TRUE if parent is a column */\n\n\tElement base;\t\t/* \"this\" for our members */\n\tgboolean known_private;\t/* TRUE after top-level clone .. can write! */\n\n\t/* For subcolumns representing a class instance, the rows for the\n\t * \"this\" and \"super\" members.\n\t */\n\tRow *this;\n\tRow *super;\n};\n\ntypedef struct _SubcolumnClass {\n\tHeapmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} SubcolumnClass;\n\nextern const SubcolumnVisibility subcolumn_visibility[];\nextern const int subcolumn_nvisibility;\n\nvoid *subcolumn_map( Subcolumn *scol, row_map_fn fn, void *a, void *b );\n\nGType subcolumn_get_type( void );\nvoid *subcolumn_new_view( Subcolumn *scol );\nSubcolumn *subcolumn_new( Rhs *rhs, Column *col );\n\nvoid subcolumn_set_vislevel( Subcolumn *scol, int vislevel );\n\ngboolean subcolumn_make_private( Subcolumn *scol );\n"
  },
  {
    "path": "src/subcolumnview.c",
    "content": "/* a subcolumnview button in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\nstatic void *\nsubcolumnview_destroy_sub( Rowview *rview, Subcolumnview *sview )\n{\n\tDESTROY_GTK( rview ); \n\n\treturn( NULL );\n}\n\nstatic void\nsubcolumnview_destroy( GtkObject *object )\n{\n\tSubcolumnview *sview;\n\n#ifdef DEBUG\n\tprintf( \"subcolumnview_destroy\\n\" );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_SUBCOLUMNVIEW( object ) );\n\n\tsview = SUBCOLUMNVIEW( object );\n\n\tUNREF( sview->group );\n\n\t/* Destroying us won't automatically destroy our rowviews, since they\n\t * are not true child-widgets. Do it by hand. \n\t */\n\t(void) view_map( VIEW( sview ), \n\t\t(view_map_fn) subcolumnview_destroy_sub, sview, NULL );\n\tDESTROY_GTK( sview->table );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\nsubcolumnview_link( View *view, Model *model, View *parent )\n{\n\tSubcolumnview *sview = SUBCOLUMNVIEW( view );\n\tSubcolumn *scol = SUBCOLUMN( model );\n\n#ifdef DEBUG\n\tprintf( \"subcolumnview_link: \" );\n\tif( HEAPMODEL( scol )->row )\n\t\trow_name_print( HEAPMODEL( scol )->row );\n\telse\n\t\tprintf( \"(null)\" );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\t/* Add to enclosing column, if there is one. Attached to enclosing row\n\t * by rowview_refresh() if we're a subcolumn.\n\t */\n\tif( !scol->is_top ) \n\t\tsview->rhsview = RHSVIEW( parent );\n\n\tgtk_widget_show( GTK_WIDGET( sview ) );\n}\n\nstatic void *\nsubcolumnview_refresh_sub( Rowview *rview, Subcolumnview *sview )\n{\n\tSubcolumn *scol = SUBCOLUMN( VOBJECT( sview )->iobject );\n\tRow *row = ROW( VOBJECT( rview )->iobject );\n\tint i;\n\n\t/* Most predicates need a sym.\n\t */\n\tif( !row->sym )\n\t\treturn( NULL );\n\n\tfor( i = 0; i <= scol->vislevel; i++ )\n\t\tif( subcolumn_visibility[i].pred( row ) ) {\n\t\t\trowview_set_visible( rview, TRUE );\n\t\t\tsview->nvis++;\n\t\t\tbreak;\n\t\t}\n\tif( i > scol->vislevel )\n\t\trowview_set_visible( rview, FALSE );\n\n\treturn( NULL );\n}\n\nstatic void \nsubcolumnview_refresh( vObject *vobject )\n{\n\tSubcolumnview *sview = SUBCOLUMNVIEW( vobject );\n\tSubcolumn *scol = SUBCOLUMN( VOBJECT( sview )->iobject );\n\tint model_rows = icontainer_get_n_children( ICONTAINER( scol ) );\n\tint old_nvis = sview->nvis;\n\tgboolean editable = scol->top_col->ws->mode != WORKSPACE_MODE_NOEDIT;\n\n#ifdef DEBUG\n\tprintf( \"subcolumnview_refresh\\n\" );\n#endif /*DEBUG*/\n\n\tif( sview->rows != model_rows ) {\n\t\tsview->rows = model_rows;\n\t\tif( sview->rows )\n\t\t\tgtk_table_resize( GTK_TABLE( sview->table ), \n\t\t\t\tsview->rows, 4 );\n\n#ifdef DEBUG\n\t\tprintf( \"subcolumnview_refresh: resize to %d rows\\n\",\n\t\t\tsview->rows );\n#endif /*DEBUG*/\n\t}\n\n\t/* Top-level subcolumns look different in no-edit mode.\n\t */\n\tif( scol->is_top && editable ) {\n\t\tgtk_alignment_set_padding( GTK_ALIGNMENT( sview->align ), \n\t\t\t0, 0, 0, 0 );\n\t\tgtk_table_set_row_spacings( GTK_TABLE( sview->table ), 0 );\n\t\tgtk_table_set_col_spacings( GTK_TABLE( sview->table ), 0 );\n\t}\n\telse if( scol->is_top && !editable ) {\n\t\tgtk_alignment_set_padding( GTK_ALIGNMENT( sview->align ), \n\t\t\t5, 5, 5, 5 );\n\t\tgtk_table_set_row_spacings( GTK_TABLE( sview->table ), 5 );\n\t\tgtk_table_set_col_spacings( GTK_TABLE( sview->table ), 5 );\n\t}\n\n\t/* Nested subcols: we just change the left indent.\n\t */\n\tif( !scol->is_top && editable ) {\n\t\tgtk_alignment_set_padding( GTK_ALIGNMENT( sview->align ), \n\t\t\t0, 0, 0, 0 );\n\t}\n\telse if( !scol->is_top && !editable ) {\n\t\tgtk_alignment_set_padding( GTK_ALIGNMENT( sview->align ), \n\t\t\t0, 0, 15, 0 );\n\t}\n\n\tsview->nvis = 0;\n\t(void) view_map( VIEW( sview ), \n\t\t(view_map_fn) subcolumnview_refresh_sub, sview, NULL );\n\n\tif( sview->nvis != old_nvis ) {\n\t\tview_resize( VIEW( sview ) );\n\t\tiobject_changed( IOBJECT( scol->top_col ) );\n\t}\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\nsubcolumnview_class_init( SubcolumnviewClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass*) class;\n\tvObjectClass *vobject_class = (vObjectClass*) class;\n\tViewClass *view_class = (ViewClass*) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = subcolumnview_destroy;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = subcolumnview_refresh;\n\n\tview_class->link = subcolumnview_link;\n}\n\nstatic void\nsubcolumnview_init( Subcolumnview *sview )\n{\n\tsview->rhsview = NULL;\n\n        sview->rows = 0;\n        sview->nvis = 0;\n\n        sview->align = gtk_alignment_new( 0, 0, 1, 1 );\n        gtk_box_pack_start( GTK_BOX( sview ), sview->align, FALSE, FALSE, 0 );\n\n        sview->table = gtk_table_new( sview->rows, 4, FALSE );\n        gtk_container_add( GTK_CONTAINER( sview->align ), sview->table );\n\n        gtk_widget_show_all( sview->align );\n\n\tsview->group = gtk_size_group_new( GTK_SIZE_GROUP_HORIZONTAL );\n}\n\nGtkType\nsubcolumnview_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Subcolumnview\",\n\t\t\tsizeof( Subcolumnview ),\n\t\t\tsizeof( SubcolumnviewClass ),\n\t\t\t(GtkClassInitFunc) subcolumnview_class_init,\n\t\t\t(GtkObjectInitFunc) subcolumnview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_VIEW, &info );\n\t}\n\n\treturn( type );\n}\n\nView *\nsubcolumnview_new( void )\n{\n\tSubcolumnview *sview = gtk_type_new( TYPE_SUBCOLUMNVIEW );\n\n\treturn( VIEW( sview ) );\n}\n"
  },
  {
    "path": "src/subcolumnview.h",
    "content": "/* a column of tallyrows in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_SUBCOLUMNVIEW (subcolumnview_get_type())\n#define SUBCOLUMNVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_SUBCOLUMNVIEW, Subcolumnview ))\n#define SUBCOLUMNVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_SUBCOLUMNVIEW, SubcolumnviewClass ))\n#define IS_SUBCOLUMNVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_SUBCOLUMNVIEW ))\n#define IS_SUBCOLUMNVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_SUBCOLUMNVIEW ))\n\nstruct _Subcolumnview {\n\tView view;\n\n\t/* Enclosing rhsview, if any.\n\t */\n\tRhsview *rhsview;\n\n\t/* My instance vars.\n\t */\n        GtkWidget *align; \t/* Alignment widget */\n        GtkWidget *table; \t/* Central tally area for column */\n        int rows;               /* Number of rows atm */\n\tint nvis;\t\t/* Number of children currently visible */\n\tGtkSizeGroup *group;\t/* Align captions with this */     \n};\n\ntypedef struct _SubcolumnviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} SubcolumnviewClass;\n\nGtkType subcolumnview_get_type( void );\nView *subcolumnview_new( void );\n"
  },
  {
    "path": "src/symbol.c",
    "content": "/* Basic ops on symbols.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* All debug\n#define DEBUG\n */\n\n/* Just trace create/destroy.\n#define DEBUG_MAKE\n */\n\n/* Time recomputes.\n#define DEBUG_TIME\n */\n\n/* Show symbols as we recalc\n#define DEBUG_RECALC\n */\n\n/* If DEBUG is on, make sure other debugs are on too.\n */\n#ifdef DEBUG\n# ifndef DEBUG_MAKE\n#  define DEBUG_MAKE\n# endif\n# ifndef DEBUG_TIME\n#  define DEBUG_TIME\n# endif\n# ifndef DEBUG_RECALC\n#  define DEBUG_RECALC\n# endif\n#endif\n\n/* Our signals. \n */\nenum {\n\tSIG_NEW_VALUE,\t\t/* new value for sym->expr */\n\tSIG_LAST\n};\n\nstatic guint symbol_signals[SIG_LAST] = { 0 };\n\n/* Global symbol - top-level definitions are locals to this symbol.\n */\nSymbol *symbol_root = NULL;\n\n/* Set of dirty top-level symbols with no dirty children which do not contain\n * errors. Used to generate next-to-recalc.\n */\nstatic GSList *symbol_leaf_set = NULL;\n\nstatic FilemodelClass *parent_class = NULL;\n\n/* Apply a function to a symbol ... and any locals.\n */\nSymbol *\nsymbol_map_all( Symbol *sym, symbol_map_fn fn, void *a, void *b )\n{\n\tSymbol *res;\n\n\t/* Apply to this sym.\n\t */\n\tif( (res = fn( sym, a, b, NULL )) )\n\t\treturn( res );\n\n\t/* And over any locals of those locals.\n\t */\n\tif( sym->expr && sym->expr->compile && \n\t\t(res = icontainer_map3( ICONTAINER( sym->expr->compile ), \n\t\t\t(icontainer_map3_fn) symbol_map_all, \n\t\t\t(void *) fn, a, b )) )\n\t\treturn( res );\n\n\treturn( NULL );\n}\n\n/* Find a symbol's enclosing sym.\n */\nSymbol *\nsymbol_get_parent( Symbol *sym )\n{\n\tif( !ICONTAINER( sym )->parent )\n\t\treturn( NULL );\n\n\treturn( COMPILE( ICONTAINER( sym )->parent )->sym );\n}\n\n/* Find the enclosing workspace, if any. \n */\nWorkspace *\nsymbol_get_workspace( Symbol *sym )\n{\n\tif( !sym->expr || !sym->expr->row )\n\t\treturn( NULL );\n\n\treturn( row_get_workspace( sym->expr->row ) );\n}\n\n/* Find the enclosing tool, if any.\n */\nTool *\nsymbol_get_tool( Symbol *sym )\n{\n\tSymbol *i;\n\n\tfor( i = sym; i && !i->tool; i = symbol_get_parent( i ) )\n\t\t;\n\tif( i )\n\t\treturn( i->tool );\n\n\treturn( NULL );\n}\n\n/* Get the enclosing scope for a sym.\n */\nSymbol *\nsymbol_get_scope( Symbol *sym )\n{\n\tSymbol *i;\n\n\tfor( i = sym; i && !is_scope( i ); i = symbol_get_parent( i ) )\n\t\t;\n\n\treturn( i );\n}\n\n/* Make a fully-qualified symbol name .. eg fred.jim, given jim. Don't print\n * static scopes.\n */\nvoid\nsymbol_qualified_name( Symbol *sym, VipsBuf *buf )\n{\n\tSymbol *parent = symbol_get_parent( sym );\n\n\tif( parent && !is_scope( parent ) ) {\n\t\tsymbol_qualified_name( parent, buf );\n\t\tvips_buf_appends( buf, \".\" );\n\t}\n\n\tvips_buf_appends( buf, NN( IOBJECT( sym )->name ) );\n}\n\n/* Make a symbol name relative to a scope context ... ie. from the point of\n * view of a local of context, what name will find sym.\n */\nvoid\nsymbol_qualified_name_relative( Symbol *context, Symbol *sym, VipsBuf *buf )\n{\n\tSymbol *parent = symbol_get_parent( sym );\n\n\tif( parent && !is_ancestor( context, parent ) ) {\n\t\tsymbol_qualified_name_relative( context, parent, buf );\n\t\tvips_buf_appends( buf, \".\" );\n\t}\n\n\tvips_buf_appends( buf, NN( IOBJECT( sym )->name ) );\n}\n\n/* As above, but include stuff about where the symbol is defined, handy for\n * building error messages.\n */\nvoid *\nsymbol_name_error( Symbol *sym, VipsBuf *buf )\n{\n\tTool *tool;\n\n\tsymbol_qualified_name( sym, buf );\n\tif( (tool = symbol_get_tool( sym )) )\n\t\ttool_error( tool, buf );\n\n\tvips_buf_appends( buf, \" \" );\n\n\treturn( NULL );\n}\n\n/* Handy for error messages ... but nowt else. Return string overwritten on\n * next call.\n */\nconst char *\nsymbol_name( Symbol *sym )\n{\n\tstatic char txt[200];\n\tstatic VipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tvips_buf_rewind( &buf );\n\tsymbol_qualified_name( sym, &buf );\n\n\treturn( vips_buf_all( &buf ) );\n}\n\n/* Convenience ... print a qual name to stdout.\n */\nvoid *\nsymbol_name_print( Symbol *sym )\n{\n\tprintf( \"%s \", symbol_name( sym ) );\n\n\treturn( NULL );\n}\n\n/* Print a symbol's name, including the enclosing static scope. Return value\n * is a pointer to a static buffer :(\n */\nconst char *\nsymbol_name_scope( Symbol *sym )\n{\n\tSymbol *scope = symbol_get_scope( sym );\n\n\tstatic char txt[200];\n\tstatic VipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tvips_buf_rewind( &buf );\n\tvips_buf_appends( &buf, NN( IOBJECT( scope )->name ) );\n\tvips_buf_appends( &buf, \".\" );\n\tsymbol_qualified_name_relative( scope, sym, &buf );\n\n\treturn( vips_buf_all( &buf ) );\n}\n\n/* Convenience ... print a qual name to stdout.\n */\nvoid\nsymbol_name_scope_print( Symbol *sym )\n{\n\tprintf( \"%s\", symbol_name_scope( sym ) );\n}\n\nvoid \nsymbol_new_value( Symbol *sym )\n{\n\tg_signal_emit( G_OBJECT( sym ), symbol_signals[SIG_NEW_VALUE], 0 );\n}\n\n/* Add a pointer to a patch list.\n */\nvoid *\nsymbol_patch_add( void **pnt, Symbol *sym )\n{\n\tg_assert( sym->type == SYM_ZOMBIE );\n\n\tsym->patch = g_slist_prepend( sym->patch, pnt );\n\n\treturn( NULL );\n}\n\nstatic void\nsymbol_clear( Symbol *sym )\n{\n\tsym->type = SYM_ZOMBIE;\n\n\tsym->patch = NULL;\n\n\tsym->expr = NULL;\n\n\tsym->base.type = ELEMENT_NOVAL;\n\tsym->base.ele = (void *) 15;\t/* handy for debugging */\n\n\tsym->dirty = FALSE;\n\tsym->parents = NULL;\n\n\tsym->topchildren = NULL;\n\tsym->topparents = NULL;\n\tsym->ndirtychildren = 0;\n\tsym->leaf = FALSE;\n\n\tsym->generated = FALSE;\n\tsym->placeholder = FALSE;\n\n\tsym->tool = NULL;\n\n\tsym->function = NULL;\n\n\tsym->builtin = NULL;\n\n\tsym->wsr = NULL;\n\n\tsym->ws = NULL;\n}\n\n/* Initialise root symbol.\n */\nSymbol *\nsymbol_root_init( void )\n{\n\tSymbol *root = SYMBOL( g_object_new( TYPE_SYMBOL, NULL ) );\n\n\tsymbol_clear( root );\n\tiobject_set( IOBJECT( root ), \"$$ROOT\", NULL );\n\troot->type = SYM_ROOT;\n\troot->expr = expr_new( root );\n\t(void) compile_new_local( root->expr );\n\n\tsymbol_root = symbol_new( root->expr->compile, \"root\" );\n\tsymbol_root->type = SYM_ROOT;\n\tsymbol_root->expr = expr_new( symbol_root );\n\t(void) compile_new( symbol_root->expr );\n\n\treturn( root );\n}\n\n/* Should a symbol be in the leaf set?\n */\nstatic gboolean\nsymbol_is_leafable( Symbol *sym )\n{\n\tif( is_top( sym ) && \n\t\tsym->dirty && \n\t\tsym->expr && \n\t\t!sym->expr->err && \n\t\tsym->ndirtychildren == 0 )\n\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\n#ifdef DEBUG\n/* Do a sanity check on a symbol.\n */\nvoid *\nsymbol_sanity( Symbol *sym ) \n{\n\tif( is_top( sym ) ) {\n\t\tif( symbol_ndirty( sym ) != sym->ndirtychildren )\n\t\t\terror( \"sanity failure #1 for sym \\\"%s\\\"\", \n\t\t\t\tsymbol_name( sym ) );\n\t}\n\n\tif( symbol_is_leafable( sym ) && !sym->leaf )\n\t\terror( \"sanity failure #2 for sym \\\"%s\\\"\", symbol_name( sym ) );\n\tif( !symbol_is_leafable( sym ) && sym->leaf )\n\t\terror( \"sanity failure #3 for sym \\\"%s\\\"\", symbol_name( sym ) );\n\tif( sym->leaf && !g_slist_find( symbol_leaf_set, sym ) )\n\t\terror( \"sanity failure #6 for sym \\\"%s\\\"\", symbol_name( sym ) );\n\tif( !sym->leaf && g_slist_find( symbol_leaf_set, sym ) )\n\t\terror( \"sanity failure #7 for sym \\\"%s\\\"\", symbol_name( sym ) );\n\n\treturn( NULL );\n}\n#endif/*DEBUG*/\n\n#ifdef DEBUG\n/* Test the leaf set for sanity.\n */\nvoid\nsymbol_leaf_set_sanity( void )\n{\n\tslist_map( symbol_leaf_set, (SListMapFn) symbol_sanity, NULL );\n\ticontainer_map( ICONTAINER( symbol_root->expr->compile ),\n\t\t(icontainer_map_fn) symbol_sanity, NULL, NULL );\n\n\t/* Commented out to reduce spam\n\t *\n\tprintf( \"Leaf set: \" );\n\tslist_map( symbol_leaf_set, (SListMapFn) dump_tiny, NULL );\n\tprintf( \"\\n\" );\n\t */\n}\n#endif /*DEBUG*/\n\n/* Strip a symbol down, ready for redefinition. \n */\nvoid *\nsymbol_strip( Symbol *sym )\n{\n#ifdef DEBUG_MAKE\n\tprintf( \"symbol_strip: \" );\n\tsymbol_name_print( sym );\n\tprintf( \"\\n\" );\n#endif /*DEBUG_MAKE*/\n\n\t/* Anything that refers to us will need a recomp.\n\t */\n\tif( is_top( sym ) ) \n\t\tsymbol_dirty_intrans( sym, link_serial_new() );\n\n\t/* Clean out old exprinfo.\n\t */\n\ticontainer_map( ICONTAINER( sym ),\n\t\t(icontainer_map_fn) expr_strip, NULL, NULL );\n\n\t/* Free any top-links we made.\n\t */\n\t(void) slist_map( sym->topchildren, (SListMapFn) link_destroy, NULL );\n\n\t/* Can free the patch list. We should not have to resolve off this\n\t * name again.\n\t */\n\tIM_FREEF( g_slist_free, sym->patch );\n\n\t/* Workspaceroot? Unlink from wsr.\n\t */\n\tif( sym->wsr ) {\n\t\tsym->wsr->sym = NULL;\n\t\tsym->wsr = NULL;\n\t}\n\n\t/* Workspace? Unlink from ws.\n\t */\n\tif( sym->ws ) {\n\t\tsym->ws->sym = NULL;\n\t\tsym->ws = NULL;\n\t}\n\n\t/* It's a ZOMBIE now.\n\t */\n\tsym->type = SYM_ZOMBIE;\n\n#ifdef DEBUG\n\tsymbol_sanity( sym );\n#endif /*DEBUG*/\n\n\treturn( NULL );\n}\n\nstatic void *\nsymbol_made_error_clear( Link *link )\n{\n\texpr_error_clear( link->parent->expr );\n\n\treturn( NULL );\n}\n\n/* Finish creating a symbol. Sequence is: symbol_new(), specialise ZOMBIE\n * into a particular symbol type, symbol_made(). Do any final tidying up.\n */\nvoid\nsymbol_made( Symbol *sym )\n{\n#ifdef DEBUG_MAKE\n\tprintf( \"symbol_made: \" );\n\tsymbol_name_print( sym );\n\tprintf( \"\\n\" );\n#endif /*DEBUG_MAKE*/\n\n\tif( is_top( sym ) ) {\n\t\t/* Remake all top-level dependencies.\n\t\t */\n\t\t(void) symbol_link_build( sym );\n\n\t\t/* Clear error on every symbol that refs us, then mark dirty.\n\t\t * This lets us replace refed-to syms cleanly.\n\t\t */\n\t\tslist_map( sym->topparents,\n\t\t\t(SListMapFn) symbol_made_error_clear, NULL );\n\n\t\t/* Real dirrrrty.\n\t\t */\n\t\tif( sym->expr )\n\t\t\texpr_dirty( sym->expr, link_serial_new() );\n\t}\n\n#ifdef DEBUG\n\tdump_symbol( sym );\n#endif /*DEBUG*/\n}\n\nstatic void *\nsymbol_not_defined_sub( Link *link, VipsBuf *buf )\n{\n\tsymbol_name_error( link->parent, buf );\n\n\treturn( NULL );\n}\n\n/* Make a \"not defined\" error message. Can be called before symbol is removed,\n * so don't assume it's a ZOMBIE.\n */\nvoid\nsymbol_not_defined( Symbol *sym )\n{\n\tchar txt[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\terror_top( _( \"Not found.\" ) );\n\tvips_buf_appendf( &buf, _( \"Symbol %s is not defined.\" ), \n\t\tsymbol_name( sym ) );\n\tif( sym->topparents ) {\n\t\tvips_buf_appends( &buf, \"\\n\" );\n\t\tvips_buf_appendf( &buf, _( \"%s is referred to by\" ),\n\t\t\tsymbol_name( sym ) );\n\t\tvips_buf_appends( &buf, \": \" );\n\t\tslist_map2( sym->topparents,\n\t\t\t(SListMap2Fn) symbol_not_defined_sub, &buf, NULL );\n\t\tvips_buf_appends( &buf, \"\\n\" );\n\t}\n\terror_sub( \"%s\", vips_buf_all( &buf ) );\n}\n\n/* Compile refers to sym, which is going ... mark compile as containing an \n * error.\n */\nstatic void *\nsymbol_destroy_error( Compile *compile, Symbol *sym )\n{\n\tsymbol_not_defined( sym );\n\tcompile_error_set( compile );\n\n\treturn( NULL );\n}\n\nstatic void \nsymbol_dispose( GObject *gobject )\n{\n\tSymbol *sym;\n\tCompile *compile;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_SYMBOL( gobject ) );\n\n\tsym = SYMBOL( gobject );\n\tcompile = COMPILE( ICONTAINER( sym )->parent );\n\n#ifdef DEBUG_MAKE\n\tprintf( \"symbol_dispose: \" );\n\tsymbol_name_print( sym );\n\tprintf( \"(%p)\\n\", sym );\n#endif /*DEBUG_MAKE*/\n\n\t/* Make sure we're not leaving last_sym dangling.\n\t */\n\tif( compile && compile->last_sym == sym )\n\t\tcompile->last_sym = NULL;\n\n\t/* Clear state.\n\t */\n\tif( is_top( sym ) ) {\n\t\t/* All stuff that depends on this sym is now dirty.\n\t\t */\n\t\tsymbol_dirty_intrans( sym, link_serial_new() );\n\n\t\t/* This will knock this sym off the leaf set as well.\n\t\t */\n\t\tsymbol_dirty_clear( sym );\n\t}\n\n\t/* Strip it down.\n\t */\n\t(void) symbol_strip( sym );\n\tIDESTROY( sym->tool );\n\n\t/* Any exprs which refer to us must have errors.\n\t */\n\t(void) slist_map( sym->parents, \n\t\t(SListMapFn) symbol_destroy_error, sym );\n\n\t/* Remove links from any expr which refer to us.\n\t */\n\t(void) slist_map( sym->parents, (SListMapFn) compile_link_break, sym );\n\n\t/* No other syms should have toplinks to us.\n\t */\n\t(void) slist_map( sym->topparents, (SListMapFn) link_destroy, NULL );\n\n\t/* Unregister value with GC.\n\t */\n\treduce_unregister( sym );\n\n\t/* Free other stuff. \n\t */\n\tsym->type = SYM_ZOMBIE; \n\n\tg_assert( !sym->tool );\n\tg_assert( !sym->parents );\n\tg_assert( !sym->topparents );\n\tg_assert( !sym->topchildren );\n\n\tIM_FREEF( g_slist_free, sym->patch );\n\tIM_FREEF( g_slist_free, sym->parents );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\nsymbol_changed( iObject *iobject )\n{\n\tSymbol *sym = SYMBOL( iobject );\n\n\t/* If we have a tool, signal changed on that as well.\n\t */\n\tif( sym->tool )\n\t\tiobject_changed( IOBJECT( sym->tool ) );\n\n\tIOBJECT_CLASS( parent_class )->changed( iobject );\n}\n\nstatic void\nsymbol_real_new_value( Symbol *symbol )\n{\n}\n\nstatic void\nsymbol_class_init( SymbolClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = symbol_dispose;\n\n\tiobject_class->changed = symbol_changed;\n\n\tsymbol_signals[SIG_NEW_VALUE] = g_signal_new( \"new_value\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( SymbolClass, new_value ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\n\tclass->new_value = symbol_real_new_value;\n}\n\nstatic void\nsymbol_init( Symbol *sym )\n{\n\tsymbol_clear( sym );\n\n#ifdef DEBUG_MAKE\n\tprintf( \"symbol_init: (%p)\\n\", sym );\n#endif /*DEBUG_MAKE*/\n}\n\nGtkType\nsymbol_get_type( void )\n{\n\tstatic GtkType symbol_type = 0;\n\n\tif( !symbol_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( SymbolClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) symbol_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Symbol ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) symbol_init,\n\t\t};\n\n\t\tsymbol_type = g_type_register_static( TYPE_FILEMODEL, \n\t\t\t\"Symbol\", &info, 0 );\n\t}\n\n\treturn( symbol_type );\n}\n\n/* Make a new symbol on an expr. If it's already there and a ZOMBIE, just \n * return it. If it's not a ZOMBIE, turn it into one. Otherwise make and \n * link on a new symbol.\n */\nSymbol *\nsymbol_new( Compile *compile, const char *name )\n{\n\tSymbol *sym;\n\n\tif( (sym = compile_lookup( compile, name )) ) {\n\t\tif( sym->type != SYM_ZOMBIE ) \n\t\t\t/* Already exists: strip it down.\n\t\t\t */\n\t\t\t(void) symbol_strip( sym );\n\n#ifdef DEBUG_MAKE\n\t\tprintf( \"symbol_new: redefining \" );\n\t\tsymbol_name_print( sym );\n\t\tprintf( \"(%p)\\n\", sym );\n#endif /*DEBUG_MAKE*/\n\t}\n\telse {\n\t\tsym = SYMBOL( g_object_new( TYPE_SYMBOL, NULL ) );\n\t\tiobject_set( IOBJECT( sym ), name, NULL );\n\t\ticontainer_child_add( ICONTAINER( compile ), \n\t\t\tICONTAINER( sym ), -1 );\n\n#ifdef DEBUG_MAKE\n\t\tprintf( \"symbol_new: creating \" );\n\t\tsymbol_name_print( sym );\n\t\tprintf( \"(%p)\\n\", sym );\n#endif /*DEBUG_MAKE*/\n\t}\n\n\treturn( sym );\n}\n\ngboolean\nsymbol_rename( Symbol *sym, const char *new_name )\n{\n\tCompile *compile = COMPILE( ICONTAINER( sym )->parent );\n\tSymbol *old_sym;\n\n\tif( strcmp( IOBJECT( sym )->name, new_name ) == 0 )\n\t\treturn( TRUE );\n\t\n\tif( (old_sym = compile_lookup( compile, new_name )) ) {\n\t\terror_top( \"%s\", _( \"Name in use.\" ) );\n\t\terror_sub( _( \"Can't rename %s \\\"%s\\\" as \\\"%s\\\". \"\n\t\t\t\"The name is already in use.\" ), \n\t\t\tdecode_SymbolType_user( sym->type ), \n\t\t\tIOBJECT( sym )->name,\n\t\t\tnew_name );\n\t\treturn( FALSE );\n\t}\n\n\t/* Everything that depends on us will break.\n\t */\n\tsymbol_dirty_intrans( sym, link_serial_new() );\n\n\tg_object_ref( sym );\n\n\ticontainer_child_remove( ICONTAINER( sym ) );\n\tiobject_set( IOBJECT( sym ), new_name, NULL );\n\ticontainer_child_add( ICONTAINER( compile ), ICONTAINER( sym ),\n\t\tICONTAINER( sym )->pos );\n\n\tg_object_unref( sym );\n\n\treturn( TRUE );\n}\n\nvoid\nsymbol_error_redefine( Symbol *sym )\n{\n\tstatic char txt[200];\n\tstatic VipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tvips_buf_rewind( &buf );\n\tvips_buf_appendf( &buf, _( \"Redefinition of \\\"%s\\\".\" ), \n\t\tIOBJECT( sym )->name );\n\tif( sym->tool && sym->tool->lineno != -1 ) {\n\t\tvips_buf_appendf( &buf, \"\\n\" );\n\t\tvips_buf_appendf( &buf, _( \"Previously defined at line %d.\" ),\n\t\t\tsym->tool->lineno );\n\t}\n\n\tyyerror( vips_buf_all( &buf ) );\n}\n\n/* Name in defining occurence. If this is a top-level definition, clean the\n * old symbol and get ready to attach a user function to it. If its not a top-\n * level definition, we flag an error. Consider repeated parameter names, \n * repeated occurence of names in locals, local name clashes with parameter\n * name etc.\n * We make a ZOMBIE: our caller should turn it into a blank user definition, a\n * parameter etc.\n */\nSymbol *\nsymbol_new_defining( Compile *compile, const char *name )\n{\n\tSymbol *sym;\n\n\t/* Block definition of \"root\" anywhere ... too confusing.\n\t */\n\tif( strcmp( name, IOBJECT( symbol_root )->name ) == 0 )\n\t\tnip2yyerror( _( \"Attempt to redefine root symbol \\\"%s\\\".\" ), \n\t\t\tname );\n\n\t/* Is this a redefinition of an existing symbol?\n\t */\n\tif( (sym = compile_lookup( compile, name )) ) {\n\t\t/* Yes. Check that this redefinition is legal.\n\t\t */\n\t\tswitch( sym->type ) {\n\t\tcase SYM_VALUE:\n\t\t\t/* Redef of existing symbol? Only allowed at top\n\t\t\t * level.\n\t\t\t */\n\t\t\tif( !is_scope( compile->sym ) )\n\t\t\t\tsymbol_error_redefine( sym );\n\t\t\tbreak;\n\n\t\tcase SYM_ZOMBIE:\n\t\t\t/* This is the definition for a previously referenced\n\t\t\t * symbol. Just return the ZOMBIE we made.\n\t\t\t */\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\t/* Parameter, workspace, etc.\n\t\t\t */\n\t\t\tnip2yyerror( _( \"Can't redefine %s \\\"%s\\\".\" ), \n\t\t\t\tdecode_SymbolType_user( sym->type ), name );\n\t\t\t/*NOTREACHED*/\n\t\t}\n\n\t\t/* This is the defining occurence ... move to the end of the\n\t\t * traverse order.\n\t\t */\n\t\ticontainer_child_move( ICONTAINER( sym ), -1 );\n\t}\n\n\t/* Get it ready.\n\t */\n\tsym = symbol_new( compile, name );\n\n\treturn( sym );\n}\n\n/* Make a reference to a symbol. Look on the local table for the name - if\n * it's not there, make a ZOMBIE. Note that ZOMBIEs etc. need patch lists\n * attached to them for all pointers to them we make. Responsibility of\n * caller!\n */\nSymbol *\nsymbol_new_reference( Compile *compile, const char *name )\n{\n\tSymbol *sym = compile_lookup( compile, name );\n\n\tif( !sym )\n\t\tsym = symbol_new( compile, name );\n\n\t/* Note the new dependency.\n\t */\n\tcompile_link_make( compile, sym );\n\n\treturn( sym );\n}\n\n/* Compile refers to child ... break link.\n */\nvoid *\nsymbol_link_break( Symbol *child, Compile *compile )\n{\n\tcompile_link_break( compile, child );\n\n\treturn( NULL );\n}\n\n/* Specialise into a user definition.\n */\ngboolean\nsymbol_user_init( Symbol *sym )\n{\n\tg_assert( sym->type == SYM_ZOMBIE );\n\n\tsym->type = SYM_VALUE;\n\treduce_register( sym );\n\tif( !sym->expr ) \n\t\tsym->expr = expr_new( sym );\n\n\t/* We don't symbol_made() yet, wait until we have finished building\n\t * sym->expr.\n\t */\n\n\treturn( TRUE );\n}\n\n/* Specialise into a parameter on an expression.\n */\ngboolean\nsymbol_parameter_init( Symbol *sym )\n{\n\tCompile *parent = COMPILE( ICONTAINER( sym )->parent );\n\n\tg_assert( sym->type == SYM_ZOMBIE );\n\n\tsym->type = SYM_PARAM;\n\tparent->param = g_slist_append( parent->param, sym );\n\tparent->nparam = g_slist_length( parent->param );\n\tsymbol_made( sym );\n\n\treturn( TRUE );\n}\n\n/* Specialise into a builtin parameter (eg. \"this\").\n */\ngboolean\nsymbol_parameter_builtin_init( Symbol *sym )\n{\n\tg_assert( sym->type == SYM_ZOMBIE );\n\n\tsym->type = SYM_PARAM;\n\tsymbol_made( sym );\n\n\treturn( TRUE );\n}\n\n/* Get the next dirty leaf symbol.\n */\nstatic Symbol *\nsymbol_leaf_next( void ) \n{\n\tif( symbol_leaf_set )\n\t\treturn( (Symbol *) symbol_leaf_set->data );\n\telse\n\t\treturn( NULL ); \n}\n\n/* Are there symbols we can recalculate? Used to display \"Calculating ...\"\n * status.\n */\ngboolean \nsymbol_busy( void )\n{\n\treturn( symbol_leaf_set != NULL );\n}\n\n/* Set leaf state.\n */\nstatic void\nsymbol_set_leaf( Symbol *sym, gboolean leaf )\n{\n\tif( sym->leaf != leaf ) {\n\t\tgboolean changed;\n\n\t\tsym->leaf = leaf;\n\n\t\tchanged = FALSE;\n\t\tif( leaf ) {\n\t\t\tif( !symbol_leaf_set )\n\t\t\t\tchanged = TRUE;\n\n\t\t\tsymbol_leaf_set = \n\t\t\t\tg_slist_prepend( symbol_leaf_set, sym );\n\t\t}\n\t\telse {\n\t\t\tg_assert( symbol_leaf_set );\n\n\t\t\tsymbol_leaf_set = \n\t\t\t\tg_slist_remove( symbol_leaf_set, sym );\n\n\t\t\tif( !symbol_leaf_set )\n\t\t\t\tchanged = TRUE;\n\t\t}\n\n\t\tif( changed )\n\t\t\tiobject_changed( IOBJECT( reduce_context->heap ) );\n\n\t\tif( sym->expr && sym->expr->row )\n\t\t\tiobject_changed( IOBJECT( sym->expr->row ) );\n\t}\n}\n\n/* State of a symbol has changed ... update! \n */\nvoid\nsymbol_state_change( Symbol *sym )\n{\n\tg_assert( sym->ndirtychildren >= 0 );\n\n\t/* Used to do more ... now we just set leaf.\n\t */\n\tsymbol_set_leaf( sym, symbol_is_leafable( sym ) );\n}\n\n/* Recalculate a symbol. We know we are dirty and have no dirty ancestors.\n */\nstatic gboolean\nsymbol_recalculate_sub( Symbol *sym )\n{\n\tgboolean result = TRUE;\n\n#ifdef DEBUG_TIME\n\tstatic GTimer *timer = NULL;\n\n\tif( !timer )\n\t\ttimer = g_timer_new();\n\tg_timer_reset( timer );\n#endif /*DEBUG_TIME*/\n\n\tg_assert( is_value( sym ) );\n\n\tif( sym->expr->row ) {\n\t\t/* This is the root of a display ... use that recomp\n\t\t * mechanism. \n\t\t */\n\t\trow_recomp( sym->expr->row );\n\n\t\t/* Stuff may have been removed.\n\t\t */\n\t\tif( sym->expr &&\n\t\t\tsym->expr->row &&\n\t\t\tsym->expr->row->err )\n\t\t\tresult = FALSE;\n\t}\n\telse if( sym->expr->compile->nparam == 0 ) {\n\t\t/* No params: this ought to have a value.\n\t\t */\n\t\tif( !reduce_regenerate( sym->expr, &sym->expr->root ) ) \n\t\t\tresult = FALSE;\n\t}\n\n#ifdef DEBUG_TIME\n\tprintf( \"symbol_recalculate_sub: \" );\n\tsymbol_name_scope_print( sym );\n\tprintf( \" %g\\n\", g_timer_elapsed( timer, NULL ) );\n#endif /*DEBUG_TIME*/\n\n\treturn( result );\n}\n\n/* Note the name of the last thing we calced here, for progress to display.\n */\nstatic char symbol_last_calc_txt[256];\nstatic VipsBuf symbol_last_calc_buf = VIPS_BUF_STATIC( symbol_last_calc_txt );\n\nstatic void\nsymbol_note_calc_name( Symbol *sym )\n{\n\tSymbol *scope = symbol_get_scope( sym );\n\tVipsBuf *buf = &symbol_last_calc_buf;\n\n\tvips_buf_rewind( buf );\n\tvips_buf_appends( buf, NN( IOBJECT( scope )->name ) );\n\tvips_buf_appends( buf, \".\" );\n\tsymbol_qualified_name_relative( scope, sym, buf );\n}\n\nconst char *\nsymbol_get_last_calc( void )\n{\n\treturn( vips_buf_all( &symbol_last_calc_buf ) ); \n}\n\n/* We can get called recursively .. eg. we do an im_tiff2vips(), that\n * pops a progress box, that triggers idle, that tries to recalc a\n * leaf again.\n */\nstatic gboolean symbol_running = FALSE;\n\n/* Recalc a symbol ... with error checks.\n */\nstatic void *\nsymbol_recalculate_leaf_sub( Symbol *sym )\n{\n#ifdef DEBUG_RECALC\n\tprintf( \"symbol_recalculate_leaf_sub: %s\\n\", symbol_name_scope( sym ) );\n\n\t/* We can symbol_recalculate_leaf_sub() syms which are not dirty.\n\t */\n\tg_assert( !sym->dirty || symbol_is_leafable( sym ) );\n\n\tg_assert( symbol_ndirty( sym ) == 0 );\n#endif /*DEBUG_RECALC*/\n\n\terror_clear();\n\tif( sym->expr->err ) {\n\t\texpr_error_get( sym->expr );\n\n#ifdef DEBUG_RECALC\n\t\tprintf( \"\\t(error: previous error)\\n\" );\n#endif /*DEBUG_RECALC*/\n\n\t\treturn( sym );\n\t}\n\tif( !sym->dirty ) \n\t\treturn( NULL );\n\tif( !is_value( sym ) ) {\n\t\tsymbol_dirty_clear( sym );\n\t\treturn( NULL );\n\t}\n\tif( symbol_running )\n\t\treturn( NULL );\n\n\treduce_context->heap->filled = FALSE;\n\tsymbol_running = TRUE;\n\tprogress_begin();\n\tsymbol_note_calc_name( sym );\n\tif( !symbol_recalculate_sub( sym ) || \n\t\treduce_context->heap->filled ) {\n\t\texpr_error_set( sym->expr );\n\t\tsymbol_running = FALSE;\n\t\tprogress_end();\n\n#ifdef DEBUG_RECALC\n\t\tprintf( \"\\t(error: %s %s)\\n\", \n\t\t\tsym->expr->error_top, sym->expr->error_sub );\n#endif /*DEBUG_RECALC*/\n\n\t\treturn( sym );\n\t}\n\tsymbol_running = FALSE;\n\tprogress_end();\n\n\t/* Have we discovered any dirty children? If not, we've cleaned this\n\t * sym.\n\t */\n\tif( !sym->ndirtychildren ) {\n\t\tsymbol_dirty_clear( sym );\n\t\tif( sym->expr ) {\n\t\t\texpr_new_value( sym->expr );\n\n#ifdef DEBUG_RECALC\n\t\t\tprintf( \"\\tsuccess: \" ); \n\t\t\tgraph_pointer( &sym->expr->root );\n#endif /*DEBUG_RECALC*/\n\t\t}\n\t}\n#ifdef DEBUG_RECALC\n\telse {\n\t\tprintf( \"\\t(found dirty children)\\n\" );\n\t}\n#endif /*DEBUG_RECALC*/\n\n\treturn( NULL );\n}\n\n/* Recalculate a symbol. FALSE if no symbols can be recalced.\n */\nstatic gboolean\nsymbol_recalculate_leaf( void )\n{\n\tgboolean recalculated;\n\tSymbol *sym;\n\n\trecalculated = FALSE;\n\n#ifdef DEBUG\n\tprintf( \"symbol_recalculate_leaves: Leaf set: \" );\n\tslist_map( symbol_leaf_set, (SListMapFn) dump_tiny, NULL );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t/* Grab stuff off the leaf set.\n\t */\n\tif( (sym = symbol_leaf_next()) ) {\n\t\t/* Should be dirty with no dirty children. Unless it's a\n\t\t * function, in which case dirty kids are OK.\n\t\t */\n\t\tg_assert( sym->dirty );\n\t\tg_assert( !sym->expr->err );\n\t\tg_assert( is_top( sym ) );\n\t\tg_assert( symbol_ndirty( sym ) == 0 || is_value( sym ) );\n\n\t\t/* Found a symbol!\n\t\t */\n\t\t(void) symbol_recalculate_leaf_sub( sym );\n\n\t\t/* Note a pending GC.\n\t\t */\n\t\t(void) heap_gc_request( reduce_context->heap );\n\n\t\t/* We have recalculated a symbol.\n\t\t */\n\t\trecalculated = TRUE;\n\t}\n\n\treturn( recalculated );\n}\n\n/* Our idle recomp callback. \n */\nstatic gint symbol_idle_id = 0;\n\nstatic gboolean\nsymbol_recalculate_idle_cb( void )\n{\n\tstatic GTimer *timer = NULL;\n\n\tgboolean run_again;\n\n#ifdef DEBUG_RECALC\n\tprintf( \"symbol_recalculate_idle_cb:\\n\" ); \n#endif /*DEBUG_RECALC*/\n\n\tif( symbol_running ) \n\t\t/* We've been run from a nested main loop, perhaps from the\n\t\t * progress bar. Just run again and perhaps next time we'll be\n\t\t * back in the top-level main loop.\n\t\t */\n\t\treturn( TRUE ); \n\n\tif( !timer )\n\t\ttimer = g_timer_new();\n\n\tg_timer_reset( timer );\n\n\trun_again = TRUE;\n\n\tif( !mainw_auto_recalc ) \n\t\t/* Auto-calc has been turned off during a recomp.\n\t\t */\n\t\trun_again = FALSE; \n\telse\n\t\twhile( g_timer_elapsed( timer, NULL ) < 0.1 )\n\t\t\tif( !symbol_recalculate_leaf() ) {\n\t\t\t\trun_again = FALSE;\n\t\t\t\tbreak;\n\t\t\t}\n\n\tif( !run_again ) {\n#ifdef DEBUG_RECALC\n\t\tprintf( \"symbol_recalculate_idle_cb: bg recalc done\\n\" ); \n#endif /*DEBUG_RECALC*/\n\n\t\tsymbol_idle_id = 0;\n\t\tprogress_end();\n\t}\n\n\treturn( run_again );\n}\n\n/* Recalculate ... either nudge the idle recomp, or in batch mode, do a recomp\n * right now.\n */\nvoid\nsymbol_recalculate_all_force( gboolean now )\n{\n#ifdef DEBUG\n\ticontainer_map( ICONTAINER( symbol_root->expr->compile ), \n\t\t(icontainer_map_fn) symbol_sanity, NULL, NULL );\n#endif /*DEBUG*/\n\n\t/* In case we're called directly.\n\t */\n\t(void) view_scan_all();\n\n\tif( symbol_running )\n\t\t/* Do nothing.\n\t\t */\n\t\t;\n\telse if( main_option_batch || \n\t\tnow ) {\n\t\tprogress_begin();\n\n\t\twhile( symbol_recalculate_leaf() )\n\t\t\t;\n\n\t\tprogress_end();\n\t}\n\telse if( !symbol_idle_id ) {\n#ifdef DEBUG_RECALC\n\t\tprintf( \"symbol_recalculate_all_force: \"\n\t\t\t\"starting bg recalc ...\\n\" ); \n#endif /*DEBUG_RECALC*/\n\n\t\tprogress_begin();\n\t\tsymbol_idle_id = g_idle_add( \n\t\t\t(GSourceFunc) symbol_recalculate_idle_cb, NULL );\n\t}\n}\n\n/* Recalculate the symbol table.\n */\nvoid\nsymbol_recalculate_all( void )\n{\n\t/* Do a scan, even if we don't recomp. We need to pick up edits before\n\t * views get refreshed.\n\t */\n\t(void) view_scan_all();\n\n\tif( mainw_auto_recalc )\n\t\tsymbol_recalculate_all_force( FALSE );\n}\n\n/* Recalc a symbol ... with error checks.\n */\ngboolean\nsymbol_recalculate_check( Symbol *sym )\n{\n\tgboolean result;\n\n\tresult = symbol_recalculate_leaf_sub( sym ) == NULL;\n\n\treturn( result );\n}\n"
  },
  {
    "path": "src/symbol.h",
    "content": "/* Types for the symbol table.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_SYMBOL (symbol_get_type())\n#define SYMBOL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_SYMBOL, Symbol ))\n#define SYMBOL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_SYMBOL, SymbolClass))\n#define IS_SYMBOL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_SYMBOL ))\n#define IS_SYMBOL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_SYMBOL ))\n#define SYMBOL_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_SYMBOL, SymbolClass ))\n\n/* The types of symbol we can have.\n */\ntypedef enum {\n\tSYM_VALUE,\t\t/* Symbol with a value attached */\n\tSYM_PARAM,\t\t/* A parameter to a user function */\n\tSYM_ZOMBIE,\t\t/* A referred to but not defined */\n\tSYM_WORKSPACE,\t\t/* A loaded workspace */\n\tSYM_WORKSPACEROOT,\t/* Base of all workspaces */\n\tSYM_ROOT,\t\t/* The root symbol */\n\tSYM_EXTERNAL,\t\t/* A reference to an external function */\n\tSYM_BUILTIN\t\t/* A reference to a built-in function */\n} SymbolType;\n\n/* A symbol.\n */\nstruct _Symbol {\n\tFilemodel parent_class;\n\n\t/* The type of this symbol.\n\t */\n\tSymbolType type;\n\n\t/* Track during parse. A list of pointers to pointers to this\n\t * symbol which we need to patch if we resolve to an outer scope.\n\t */\n\tGSList *patch;\n\n\t/* Main expression for this sym. All expressions are icontainer\n\t * children of us.\n\t */\n\tExpr *expr;\n\n\t/* Base of graph for value of this symbol. Use sym->expr->root to get\n\t * value though .. we just hold pointer for GC here. Expressions on\n\t * ext_expr have their GC handled by their enclosing Subcolumn.\n\t */\n\tElement base;\t\t/* Value for this expr */\n\n\t/* Recomputation links. Use these to work out what to build next.\n\t */\n\tgboolean dirty;\t\t/* True if this sym needs recalc */\n\tGSList *parents;\t/* Compiles which refer to this sym */\n\n\tGSList *topchildren;\t/* For top syms, all top-level children */\n\tGSList *topparents;\t/* For top syms, all top-level parents */\n\tint ndirtychildren;\t/* Number of dirty top syms we refer to */\n\tgboolean leaf;\t\t/* True for in recomp set */\n\n\t/* This is a generated symbol, like $$result, $$fn1, whatever.\n\t */\n\tgboolean generated;\n\n\t/* A temporary intermediate symbol generated during parse to hold \n\t * stuff until we need it. Don't generate code for these.\n\t */\n\tgboolean placeholder;\n\n\t/* X-tras for definitions.\n\t */\n\tTool *tool;\t\t/* Tool and toolkit defined in */\n\n\t/* X-tras for SYM_EXTERNAL ... our im_function.\n\t */\n\tim_function *function;\t/* Function we run */\n\tint fn_nargs;\t\t/* Number of args fn needs from nip */\n\n\t/* X-tras for SYM_BUILTIN ... our function.\n\t */\n\tBuiltinInfo *builtin;\n\n\t/* For WORKSPACEROOT ... the wsr we represent.\n\t */\n\tWorkspaceroot *wsr;\n\n\t/* For WORKSPACE ... the ws we represent.\n\t */\n\tWorkspace *ws;\n};\n\ntypedef struct _SymbolClass {\n\tFilemodelClass parent_class;\n\n\t/* \n\n\t\tnew_value\tsym->expr has a new value (this signal is\n\t\t\t\tfwd'd from sym->expr)\n\n\t */\n\n\tvoid (*new_value)( Symbol *sym );\n} SymbolClass;\n\nGType symbol_get_type( void );\n\n/* All symbols come off this.\n */\nextern Symbol *symbol_root;\n\nSymbol *symbol_map_all( Symbol *sym, symbol_map_fn fn, void *a, void *b );\n\nSymbol *symbol_get_parent( Symbol *sym );\nWorkspace *symbol_get_workspace( Symbol *sym );\nTool *symbol_get_tool( Symbol *sym );\nSymbol *symbol_get_scope( Symbol *sym );\n\nvoid symbol_qualified_name( Symbol *sym, VipsBuf *buf );\nvoid symbol_qualified_name_relative( Symbol *context, \n\tSymbol *sym, VipsBuf *buf );\nvoid *symbol_name_error( Symbol *sym, VipsBuf *buf );\nconst char *symbol_name( Symbol *sym );\nvoid *symbol_name_print( Symbol *sym );\nconst char *symbol_name_scope( Symbol *sym );\nvoid symbol_name_scope_print( Symbol *sym );\n\nvoid symbol_new_value( Symbol *sym );\n\nvoid *symbol_patch_add( void **pnt, Symbol *sym );\n\nSymbol *symbol_root_init( void );\n\nSymbol *symbol_new( Compile *compile, const char *name );\ngboolean symbol_rename( Symbol *sym, const char *new_name );\nvoid symbol_error_redefine( Symbol *sym );\nSymbol *symbol_new_defining( Compile *compile, const char *name );\nSymbol *symbol_new_reference( Compile *compile, const char *name );\nvoid symbol_made( Symbol *sym );\n\nvoid symbol_not_defined( Symbol *sym );\n\nvoid *symbol_link_break( Symbol *child, Compile *compile );\n\ngboolean symbol_user_init( Symbol *sym );\ngboolean symbol_parameter_init( Symbol *sym );\ngboolean symbol_parameter_builtin_init( Symbol *sym );\n\ngboolean symbol_busy( void );\n\nvoid *symbol_sanity( Symbol *sym );\nvoid symbol_leaf_set_sanity( void );\nvoid *symbol_strip( Symbol *sym );\n\nvoid symbol_state_change( Symbol *sym );\n\nconst char *symbol_get_last_calc( void );\ngboolean symbol_recalculate_check( Symbol *sym );\nvoid symbol_recalculate_all_force( gboolean now );\nvoid symbol_recalculate_all( void );\n"
  },
  {
    "path": "src/toggle.c",
    "content": "/* a toggle button ... put/get methods\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/*\n#define DEBUG\n */\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic View *\ntoggle_view_new( Model *model, View *parent )\n{\n\treturn( toggleview_new() );\n}\n\n/* Members of toggle we automate.\n */\nstatic ClassmodelMember toggle_members[] = {\n\t{ CLASSMODEL_MEMBER_STRING, NULL, 0,\n\t\tMEMBER_CAPTION, \"caption\", N_( \"Caption\" ),\n\t\tG_STRUCT_OFFSET( iObject, caption ) },\n\t{ CLASSMODEL_MEMBER_BOOLEAN, NULL, 0,\n\t\tMEMBER_VALUE, \"value\", N_( \"Value\" ),\n\t\tG_STRUCT_OFFSET( Toggle, value ) }\n};\n\nstatic void\ntoggle_class_init( ToggleClass *class )\n{\n\tModelClass *model_class = (ModelClass *) class;\n\tClassmodelClass *classmodel_class = (ClassmodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tmodel_class->view_new = toggle_view_new;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n\n\tclassmodel_class->members = toggle_members;\n\tclassmodel_class->n_members = IM_NUMBER( toggle_members );\n}\n\nstatic void\ntoggle_init( Toggle *toggle )\n{\n        toggle->value = FALSE;\n\n\tiobject_set( IOBJECT( toggle ), CLASS_TOGGLE, NULL );\n}\n\nGType\ntoggle_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ToggleClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) toggle_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Toggle ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) toggle_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"Toggle\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/toggle.h",
    "content": "/* a toggle button in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_TOGGLE (toggle_get_type())\n#define TOGGLE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_TOGGLE, Toggle ))\n#define TOGGLE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_TOGGLE, ToggleClass))\n#define IS_TOGGLE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_TOGGLE ))\n#define IS_TOGGLE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_TOGGLE ))\n#define TOGGLE_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_TOGGLE, ToggleClass ))\n\ntypedef struct _Toggle {\n\tClassmodel parent_class;\n\n\t/* My instance vars.\n\t */\n\tgboolean value;\n} Toggle;\n\ntypedef struct _ToggleClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} ToggleClass;\n\nGType toggle_get_type( void );\n"
  },
  {
    "path": "src/toggleview.c",
    "content": "/* the display part of a toggle button \n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/*\n#define DEBUG\n */\n\nstatic GraphicviewClass *parent_class = NULL;\n\n/* Toggleview callback.\n */\nstatic void\ntoggleview_change_cb( GtkWidget *widget, Toggleview *togview )\n{\n\tToggle *tog = TOGGLE( VOBJECT( togview )->iobject );\n\tClassmodel *classmodel = CLASSMODEL( tog );\n\n\tif( tog->value != GTK_TOGGLE_BUTTON( widget )->active ) {\n\t\ttog->value = GTK_TOGGLE_BUTTON( widget )->active;\n\n\t\tclassmodel_update( classmodel );\n\t\tsymbol_recalculate_all();\n\t}\n}\n\nstatic void \ntoggleview_refresh( vObject *vobject )\n{\n\tToggleview *togview = TOGGLEVIEW( vobject );\n\tToggle *tog = TOGGLE( VOBJECT( togview )->iobject );\n\n        gtk_toggle_button_set_active( \n\t\tGTK_TOGGLE_BUTTON( togview->toggle ), tog->value );\n\tset_glabel( GTK_BIN( togview->toggle )->child, \"%s\", \n\t\tIOBJECT( tog )->caption );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\ntoggleview_class_init( ToggleviewClass *class )\n{\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = toggleview_refresh;\n}\n\nstatic void\ntoggleview_init( Toggleview *togview )\n{\n        togview->toggle = build_gtoggle( GTK_WIDGET( togview ), \"\" );\n        set_tooltip( togview->toggle, _( \"Left-click to change value\" ) );\n        gtk_signal_connect( GTK_OBJECT( togview->toggle ), \"clicked\",\n\t\tGTK_SIGNAL_FUNC( toggleview_change_cb ), togview );\n\n        gtk_widget_show_all( GTK_WIDGET( togview ) );\n}\n\nGtkType\ntoggleview_get_type( void )\n{\n\tstatic GtkType toggleview_type = 0;\n\n\tif( !toggleview_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Toggleview\",\n\t\t\tsizeof( Toggleview ),\n\t\t\tsizeof( ToggleviewClass ),\n\t\t\t(GtkClassInitFunc) toggleview_class_init,\n\t\t\t(GtkObjectInitFunc) toggleview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttoggleview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info );\n\t}\n\n\treturn( toggleview_type );\n}\n\nView *\ntoggleview_new( void )\n{\n\tToggleview *togview = gtk_type_new( TYPE_TOGGLEVIEW );\n\n\treturn( VIEW( togview ) );\n}\n"
  },
  {
    "path": "src/toggleview.h",
    "content": "/* a toggleview button in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_TOGGLEVIEW (toggleview_get_type())\n#define TOGGLEVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_TOGGLEVIEW, Toggleview ))\n#define TOGGLEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_TOGGLEVIEW, ToggleviewClass ))\n#define IS_TOGGLEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_TOGGLEVIEW ))\n#define IS_TOGGLEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_TOGGLEVIEW ))\n\ntypedef struct _Toggleview {\n\tGraphicview parent_object;\n\n\t/* My instance vars.\n\t */\n\tGtkWidget *toggle;\n} Toggleview;\n\ntypedef struct _ToggleviewClass {\n\tGraphicviewClass parent_class;\n\n\t/* My methods.\n\t */\n} ToggleviewClass;\n\nGtkType toggleview_get_type( void );\nView *toggleview_new( void );\n"
  },
  {
    "path": "src/tool.c",
    "content": "/* Manage toolkits and their display.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG_VERBOSE\n#define DEBUG_MENUS\n#define DEBUG\n#define DEBUG_TOOLITEM\n */\n\n#include \"ip.h\"\n\nstatic FilemodelClass *parent_class = NULL;\n\n/* Largest string we let the user set for name/tip/etc.\n */\n#define MAX_NAME (256)\n\nvoid\ntool_error( Tool *tool, VipsBuf *buf )\n{\n\tif( tool->lineno != -1 ) {\n\t\tvips_buf_appends( buf, \" (\" );\n\t\tif( FILEMODEL( tool->kit )->filename )\n\t\t\tvips_buf_appends( buf, \n\t\t\t\tFILEMODEL( tool->kit )->filename );\n\t\telse\n\t\t\tvips_buf_appends( buf, IOBJECT( tool->kit )->name );\n\t\tvips_buf_appendf( buf, \":%d)\", tool->lineno );\n\t}\n}\n\nstatic void *\ntool_linkreport_sym_sym( Symbol *child, \n\tSymbol *parent, VipsBuf *buf, gboolean *found )\n{\n\t/* Don't report generated syms eg. from lcomps or pattern\n\t * matches.\n\t */\n\tif( child->type == SYM_ZOMBIE && \n\t\t!child->generated && !parent->generated &&\n\t\t!compile_resolve_top( child ) ) {\n\n\t\tsymbol_name_error( parent, buf );\n\n\t\tvips_buf_appendf( buf, \" \" );\n\t\t/* used as in \"fred refers to undefined symbol jim\"\n\t\t */\n\t\tvips_buf_appendf( buf, _( \"refers to undefined symbol\" ) );\n\t\tvips_buf_appendf( buf, \" \" );\n\t\tsymbol_qualified_name( child, buf );\n\t\tvips_buf_appendf( buf, \"\\n\" );\n\n\t\t*found = TRUE;\n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\ntool_linkreport_sym( Symbol *sym, VipsBuf *buf, gboolean *found )\n{\n\tif( sym->expr )\n\t\treturn( slist_map3( sym->expr->compile->children,\n\t\t\t(SListMap3Fn) tool_linkreport_sym_sym, \n\t\t\tsym, buf, found ) );\n\n\treturn( NULL );\n}\n\nvoid *\ntool_linkreport_tool( Tool *tool, VipsBuf *buf, gboolean *found )\n{\n\tif( tool->type != TOOL_SYM )\n\t\treturn( NULL );\n\n\treturn( symbol_map_all( tool->sym, \n\t\t(symbol_map_fn) tool_linkreport_sym, buf, found ) );\n}\n\nstatic void\ntool_finalize( GObject *gobject )\n{\n\tTool *tool;\n\n#ifdef DEBUG\n\tprintf( \"tool_finalize: %p %s\\n\", \n\t\tgobject, NN( IOBJECT( gobject )->name ) );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_TOOL( gobject ) );\n\n\ttool = TOOL( gobject );\n\n\tIM_FREE( tool->help );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void *toolitem_free( Toolitem *toolitem );\n\n/* Remove a tool. Also strip the sym, if any.\n */\nstatic void \ntool_dispose( GObject *gobject )\n{\t\n\tTool *tool = TOOL( gobject );\n\n#ifdef DEBUG\n\tprintf( \"tool_dispose: destroying tool for \" );\n\tif( tool->sym )\n\t\tsymbol_name_print( tool->sym );\n\telse\n\t\tprintf( \"anonymous-tool\" );\n\tprintf( \"at addr %p\\n\", tool );\n#endif /*DEBUG*/\n\n\tFREESID( tool->new_value_sid, tool->link_sym );\n\n\t/* Unlink from symbol and toolkit. This changes the kit - mark it as\n\t * dirty.\n\t */\n\tif( tool->sym ) {\n\t\tSymbol *sym = tool->sym;\n\n\t\tsym->tool = NULL;\n\t\ttool->sym = NULL;\n\n\t\tsymbol_strip( sym );\n\n\t\t/* Anything that referred to this symbol is going to need a\n\t\t * recalc.\n\t\t */\n\t}\n\n\tif( tool->kit ) {\n\t\tfilemodel_set_modified( FILEMODEL( tool->kit ), TRUE );\n\t\ttool->kit = NULL;\n\t}\n\n\tIM_FREEF( toolitem_free, tool->toolitem );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic View *\ntool_view_new( Model *model, View *parent )\n{\n\treturn( toolview_new() );\n}\n\n/* Save a tool's definition to a file. \n */\nstatic gboolean\ntool_save_text( Model *model, iOpenFile *of )\n{\n\tTool *tool = TOOL( model );\n\tSymbol *sym = tool->sym;\n\n\tswitch( tool->type ) {\n\tcase TOOL_SYM:\n\t\tif( sym->expr )\n\t\t\tif( !ifile_write( of, \n\t\t\t\t\"%s;\\n\\n\", sym->expr->compile->text ) )\n\t\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase TOOL_SEP:\n\t\tif( !ifile_write( of, \"#separator\\n\\n\" ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase TOOL_DIA:\n\t\tif( !ifile_write( of, \"#dialog \\\"%s\\\" \\\"%s\\\"\\n\\n\",\n\t\t\tIOBJECT( tool )->name, FILEMODEL( tool )->filename ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nstatic char *\ntool_type_to_char( Tooltype type )\n{\n\tswitch( type ) {\n\tcase TOOL_SYM:\treturn( \"symbol\" );\n\tcase TOOL_DIA:\treturn( \"dialog\" );\n\tcase TOOL_SEP:\treturn( \"separator\" );\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t\t\n\t\t/* Keep gcc happy.\n\t\t */\n\t\treturn( FALSE );\n\t}\n}\n\nstatic void\ntool_info( iObject *iobject, VipsBuf *buf )\n{\n\tTool *tool = TOOL( iobject );\n\n\tIOBJECT_CLASS( parent_class )->info( iobject, buf );\n\n\tvips_buf_appendf( buf, \"type = \\\"%s\\\"\\n\", tool_type_to_char( tool->type ) );\n\tif( tool->type == TOOL_SYM )\n\t\tvips_buf_appendf( buf, \"symbol = \\\"%s\\\"\\n\", \n\t\t\tIOBJECT( tool->sym )->name );\n\tif( tool->lineno != -1 )\n\t\tvips_buf_appendf( buf, \"lineno = %d\\n\", tool->lineno );\n\tif( tool->kit )\n\t\tvips_buf_appendf( buf, \"toolkit = \\\"%s\\\"\\n\", \n\t\t\tIOBJECT( tool->kit )->name );\n}\n\nstatic void\ntool_parent_add( iContainer *child )\n{\n        Tool *tool = TOOL( child );\n        Toolkit *kit = TOOLKIT( child->parent );\n\n        tool->kit = kit;\n\n        ICONTAINER_CLASS( parent_class )->parent_add( child );\n}\n\nstatic void\ntool_class_init( ToolClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tiContainerClass *icontainer_class = (iContainerClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->finalize = tool_finalize;\n\tgobject_class->dispose = tool_dispose;\n\n\tiobject_class->info = tool_info;\n\n\ticontainer_class->parent_add = tool_parent_add;\n\n\tmodel_class->view_new = tool_view_new;\n\tmodel_class->save_text = tool_save_text;\n}\n\nstatic void\ntool_init( Tool *tool )\n{\n        tool->type = TOOL_SEP;\n        tool->sym = NULL;\n        tool->kit = NULL;\n        tool->lineno = -1;\n}\n\nGType\ntool_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ToolClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) tool_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Tool ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) tool_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_FILEMODEL, \n\t\t\t\"Tool\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\n/* Add a tool to a toolkit.\n */\nstatic void\ntool_link( Tool *tool, Toolkit *kit, int pos, const char *name )\n{\n#ifdef DEBUG\n\tprintf( \"tool_link: %s\\n\", name );\n#endif /*DEBUG*/\n\n\tfilemodel_set_modified( FILEMODEL( kit ), TRUE );\n\tiobject_set( IOBJECT( tool ), name, NULL );\n\ticontainer_child_add( ICONTAINER( kit ), ICONTAINER( tool ), pos );\n}\n\nstatic void *\ntoolitem_free( Toolitem *toolitem )\n{\n\tToolitem *parent = toolitem->parent;\n\n#ifdef DEBUG_TOOLITEM\n\tprintf( \"toolitem_free: %s\\n\", toolitem->name );\n#endif /*DEBUG_TOOLITEM*/\n\n\tslist_map( toolitem->children, (SListMapFn) toolitem_free, NULL );\n\n\tg_assert( !toolitem->children );\n\n\tif( parent ) {\n\t\tparent->children = g_slist_remove( parent->children, toolitem );\n\t\ttoolitem->parent = NULL;\n\t}\n\n\tIM_FREE( toolitem->label );\n\tIM_FREE( toolitem->name );\n\tIM_FREE( toolitem->icon );\n\tIM_FREE( toolitem->tooltip );\n\tIM_FREE( toolitem->help );\n\tIM_FREE( toolitem->action );\n\tIM_FREE( toolitem->path );\n\tIM_FREE( toolitem->user_path );\n\tIM_FREE( toolitem );\n\n\treturn( NULL );\n}\n\nstatic Toolitem *\ntoolitem_new( Toolitem *parent, Compile *compile, Tool *tool )\n{\n\tToolitem *toolitem;\n\n\tif( !(toolitem = INEW( NULL, Toolitem )) )\n\t\treturn( NULL );\n\ttoolitem->compile = compile;\n\ttoolitem->tool = tool;\n\ttoolitem->action_sym = NULL;\n\n\ttoolitem->is_separator = FALSE;\n\ttoolitem->is_pullright = FALSE;\n\ttoolitem->children = NULL;\n\ttoolitem->parent = parent;\n\ttoolitem->is_action = FALSE;\n\n\ttoolitem->label = NULL;\n\ttoolitem->name = NULL;\n\ttoolitem->icon = NULL;\n\ttoolitem->tooltip = NULL;\n\ttoolitem->help = NULL;\n\ttoolitem->action = NULL;\n\ttoolitem->path = NULL;\n\ttoolitem->user_path = NULL;\n\n\tif( parent ) \n\t\tparent->children = \n\t\t\tg_slist_append( parent->children, toolitem );\n\n\treturn( toolitem );\n}\n\n/* Set label & name & icon.\n\n\tFIXME ... we will do repeated heap_is_instanceof() during item build,\n\tdo it once and set a flag instead\n\n */\nstatic void\ntoolitem_set_name( Toolitem *toolitem, PElement *root )\n{\n\tgboolean result;\n\tchar value[MAX_NAME];\n\tint i;\n\n\tif( root && \n\t\theap_is_instanceof( CLASS_MENUITEM, root, &result ) && \n\t\tresult ) {\n\t\tif( class_get_member_string( root, \n\t\t\tMEMBER_LABEL, value, MAX_NAME ) ) {\n\t\t\tchar *p, *q;\n\n\t\t\t/* Save the i18n-ed version.\n\t\t\t */\n\t\t\tIM_SETSTR( toolitem->label, _( value ) );\n\n\t\t\t/* Strip underscores (they mark mnemonics). Can't use\n\t\t\t * strrcpy() or memccpy(), we have overlapping blocks.\n\t\t\t */\n\t\t\tim_strncpy( value, toolitem->label, MAX_NAME );\n\t\t\tfor( p = q = value; *p; p++ )\n\t\t\t\tif( *p != '_' )\n\t\t\t\t\t*q++ = *p;\n\t\t\t*q = '\\0';\n\t\t\tIM_SETSTR( toolitem->name, value );\n\t\t}\n\n\t\tif( class_get_member_string( root, \n\t\t\tMEMBER_ICON, value, MAX_NAME ) ) \n\t\t\tIM_SETSTR( toolitem->icon, value );\n\t}\n\telse {\n\t\t/* Remove underscores from the object name ... we don't want\n\t\t * them to be mnemonics.\n\t\t */\n\t\tim_strncpy( value, \n\t\t\tIOBJECT( toolitem->compile->sym )->name, MAX_NAME );\n\t\tfor( i = 0; value[i]; i++ )\n\t\t\tif( value[i] == '_' )\n\t\t\t\tvalue[i] = ' ';\n\n\t\tIM_SETSTR( toolitem->label, value );\n\t\tIM_SETSTR( toolitem->name, toolitem->label );\n\t}\n\n\tif( root && \n\t\theap_is_instanceof( CLASS_MENUSEPARATOR, root, &result ) && \n\t\tresult ) \n\t\ttoolitem->is_separator = TRUE;\n}\n\nstatic void\ntoolitem_set_tooltip( Toolitem *toolitem, PElement *root )\n{\n\tgboolean result;\n\tchar value[MAX_NAME];\n\n\tif( root && \n\t\theap_is_instanceof( CLASS_MENUITEM, root, &result ) &&\n\t\tresult &&\n\t\tclass_get_member_string( root, \n\t\t\tMEMBER_TOOLTIP, value, MAX_NAME ) ) {\n\t\tIM_SETSTR( toolitem->tooltip, _( value ) );\n\t}\n\telse if( toolitem->tool &&\n\t\ttoolitem->tool->help ) \n\t\tIM_SETSTR( toolitem->tooltip, toolitem->tool->help );\n}\n\nstatic void\ntoolitem_set_pullright( Toolitem *toolitem, PElement *root )\n{\n\tgboolean result;\n\n\t/* New-style pullright?\n\t */\n\tif( root && \n\t\theap_is_instanceof( CLASS_MENUPULLRIGHT, root, &result ) &&\n\t\tresult ) \n\t\ttoolitem->is_pullright = TRUE;\n\t/* Old-style pullright?\n\t */\n\telse if( is_value( toolitem->compile->sym ) && \n\t\tis_class( toolitem->compile ) && \n\t\t!toolitem->compile->has_super && \n\t\ttoolitem->compile->nparam == 0 ) \n\t\ttoolitem->is_pullright = TRUE;\n}\n\nstatic void\ntoolitem_set_action( Toolitem *toolitem, PElement *root )\n{\n\tgboolean result;\n\tchar txt[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tif( toolitem->parent )\n\t\tvips_buf_appendf( &buf, \"%s.\", toolitem->parent->action );\n\tvips_buf_appendf( &buf, \"%s\", IOBJECT( toolitem->compile->sym )->name );\n\n\t/* If this is a Menuaction, we need the action member.\n\t */\n\tif( root && \n\t\theap_is_instanceof( CLASS_MENUACTION, root, &result ) &&\n\t\tresult ) {\n\t\tPElement out;\n\n\t\ttoolitem->is_action = TRUE;\n\t\t(void) class_get_member( root, \n\t\t\tMEMBER_ACTION, &toolitem->action_sym, &out );\n\t}\n\n\t/* If there's an action member, use that. \n\t */\n\tif( toolitem->is_action )\n\t\tvips_buf_appends( &buf, \".\" MEMBER_ACTION ); \n\n\tIM_SETSTR( toolitem->action, vips_buf_all( &buf ) );\n\n\t/* No action member found and this is an item (ie. not a pullright)?\n\t * Default to the sym itself.\n\t */\n\tif( !toolitem->action_sym && !toolitem->is_pullright )\n\t\ttoolitem->action_sym = toolitem->compile->sym;\n}\n\nstatic void\ntoolitem_set_path( Toolitem *toolitem )\n{\n\tchar txt[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tif( toolitem->parent )\n\t\tvips_buf_appendf( &buf, \"%s\", toolitem->parent->path );\n\telse \n\t\tvips_buf_appendf( &buf, \"<mainw>/Toolkits/%s\", \n\t\t\tIOBJECT( toolitem->tool->kit )->name );\n\tvips_buf_appendf( &buf, \"/%s\", toolitem->name );\n\tIM_SETSTR( toolitem->path, vips_buf_all( &buf ) );\n}\n\nstatic void\ntoolitem_set_user_path( Toolitem *toolitem )\n{\n\tchar txt[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tif( toolitem->parent )\n\t\tvips_buf_appends( &buf, toolitem->parent->user_path );\n\telse\n\t\tvips_buf_appends( &buf, IOBJECT( toolitem->tool->kit )->name );\n\tvips_buf_appendf( &buf, \" / %s\", toolitem->name );\n\tIM_SETSTR( toolitem->user_path, vips_buf_all( &buf ) );\n}\n\nstatic void *\ntoolitem_set_help_sub( Symbol *param, VipsBuf *buf )\n{\n\tvips_buf_appends( buf, \" \" );\n\tvips_buf_appends( buf, IOBJECT( param )->name );\n\n\treturn( NULL );\n}\n\nstatic void\ntoolitem_set_help( Toolitem *toolitem )\n{\n\tchar txt[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tvips_buf_appends( &buf, toolitem->name );\n\n\t/* Get the params from the action member if we can.\n\t */\n\tif( toolitem->action_sym && \n\t\ttoolitem->action_sym->expr &&\n\t\ttoolitem->action_sym->expr->compile->param ) \n\t\tslist_map( toolitem->action_sym->expr->compile->param,\n\t\t\t(SListMapFn) toolitem_set_help_sub, &buf );\n\n\tvips_buf_appends( &buf, \": \" );\n\tif( toolitem->tooltip )\n\t\tvips_buf_appends( &buf, toolitem->tooltip );\n\tIM_SETSTR( toolitem->help, vips_buf_firstline( &buf ) );\n}\n\nstatic Toolitem *\ntoolitem_build( Tool *tool, \n\tCompile *compile, PElement *root, Toolitem *parent )\n{\n\tToolitem *toolitem;\n\n\tif( !(toolitem = toolitem_new( parent, compile, tool )) )\n\t\treturn( NULL );\n\n\ttoolitem_set_name( toolitem, root );\n\ttoolitem_set_tooltip( toolitem, root );\n\ttoolitem_set_pullright( toolitem, root );\n\ttoolitem_set_action( toolitem, root );\n\ttoolitem_set_path( toolitem );\n\ttoolitem_set_user_path( toolitem );\n\ttoolitem_set_help( toolitem );\n\n#ifdef DEBUG_TOOLITEM\n\tprintf( \"toolitem_build: %s\\n\", toolitem->name );\n#endif /*DEBUG_TOOLITEM*/\n\n#ifdef DEBUG_VERBOSE\n\tprintf( \"toolitem_build:\\n\" );\n\tprintf( \"\\tpullright = %d\\n\", toolitem->is_pullright );\n\tprintf( \"\\tlabel = \\\"%s\\\"\\n\", toolitem->label );\n\tprintf( \"\\tname = \\\"%s\\\"\\n\", toolitem->name );\n\tprintf( \"\\ticon = \\\"%s\\\"\\n\", toolitem->icon );\n\tprintf( \"\\ttooltip = \\\"%s\\\"\\n\", toolitem->tooltip );\n\tprintf( \"\\thelp = \\\"%s\\\"\\n\", toolitem->help );\n\tprintf( \"\\taction = \\\"%s\\\"\\n\", toolitem->action );\n\tprintf( \"\\tpath = \\\"%s\\\"\\n\", toolitem->path );\n\tprintf( \"\\tuser_path = \\\"%s\\\"\\n\", toolitem->user_path );\n#endif /*DEBUG_VERBOSE*/\n\n\treturn( toolitem );\n}\n\nstatic Toolitem *\ntoolitem_build_all( Tool *tool, Compile *compile, PElement *root,\n\tToolitem *parent );\n\nstatic void *\ntoolitem_build_all_sub( Symbol *sym, Toolitem *parent )\n{\n\tif( is_menuable( sym ) )\n\t\t(void) toolitem_build_all( parent->tool, sym->expr->compile, \n\t\t\tNULL, parent );\n\n\treturn( NULL );\n}\n\nstatic Toolitem *\ntoolitem_build_all( Tool *tool, Compile *compile, PElement *root,\n\tToolitem *parent )\n{\n\tToolitem *toolitem;\n\tgboolean result;\n\n\tif( !(toolitem = toolitem_build( tool, compile, root, parent )) )\n\t\treturn( NULL );\n\n\t/* If this is a dynamic pullright, walk the heap to find the members.\n\t */\n\tif( toolitem->is_pullright && root && \n\t\theap_is_instanceof( CLASS_MENUPULLRIGHT, root, &result ) &&\n\t\tresult ) {\n\t\tPElement member;\n\t\tHeapNode *p;\n\n\t\tPEGETCLASSMEMBER( &member, root );\n\n\t\tif( PEISNODE( &member ) )\n\t\t\tfor( p = PEGETVAL( &member ); p; p = GETRIGHT( p ) ) {\n\t\t\t\tPElement s, v;\n\t\t\t\tHeapNode *hn;\n\t\t\t\tSymbol *sym;\n\n\t\t\t\t/* Get the sym/value pair.\n\t\t\t\t */\n\t\t\t\thn = GETLEFT( p );\n\t\t\t\tPEPOINTLEFT( hn, &s );\n\t\t\t\tPEPOINTRIGHT( hn, &v );\n\t\t\t\tsym = SYMBOL( PEGETSYMREF( &s ) );\n\n\t\t\t\t/* Ignore this/super/check etc.\n\t\t\t\t */\n\t\t\t\tif( !is_menuable( sym ) )\n\t\t\t\t\tcontinue;\n\n\t\t\t\t/* For dynamic menus, only make items for\n\t\t\t\t * things which are subclasses of menu.\n\t\t\t\t */\n\t\t\t\tif( !heap_is_instanceof( CLASS_MENU, \n\t\t\t\t\t&v, &result ) || !result ) \n\t\t\t\t\tcontinue;\n\n\t\t\t\t(void) toolitem_build_all( tool, \n\t\t\t\t\tsym->expr->compile, &v, toolitem );\n\t\t\t}\n\t}\n\telse if( toolitem->is_pullright ) {\n\t\t/* A static pullright... just walk the container.\n\t\t */\n\t\t(void) icontainer_map( ICONTAINER( compile ),\n\t\t\t(icontainer_map_fn) toolitem_build_all_sub,\n\t\t\ttoolitem, NULL );\n\t}\n\n\treturn( toolitem );\n}\n\n#ifdef DEBUG_MENUS\nstatic void \ntoolitem_print( Toolitem *toolitem ) \n{\n\tif( toolitem->is_separator )\n\t\tprintf( \"-----------\\n\" );\n\telse \n\t\tprintf( \"%s --- %s\\n\", \n\t\t\tNN( toolitem->user_path ), NN( toolitem->help ) );\n}\n\nstatic void *\ntoolitem_print_all( Toolitem *toolitem )\n{\n\tif( toolitem->is_pullright )\n\t\tslist_map( toolitem->children, \n\t\t\t(SListMapFn) toolitem_print_all, NULL );\n\telse\n\t\ttoolitem_print( toolitem );\n\n\treturn( NULL );\n}\n#endif /*DEBUG_MENUS*/\n\n/* Rebuild the toolitem tree.\n */\nstatic void\ntool_toolitem_rebuild( Tool *tool )\n{\n\tIM_FREEF( toolitem_free, tool->toolitem );\n\n\tswitch( tool->type ) {\n\tcase TOOL_SYM:\n\t\tif( is_menuable( tool->sym ) )\n\t\t\ttool->toolitem = toolitem_build_all( tool, \n\t\t\t\ttool->sym->expr->compile, \n\t\t\t\t&tool->sym->expr->root, \n\t\t\t\tNULL ); \n\t\tbreak;\n\n\tcase TOOL_DIA:\n\t\tif( (tool->toolitem = toolitem_new( NULL, NULL, tool )) ) \n\t\t\tIM_SETSTR( tool->toolitem->label, \n\t\t\t\tIOBJECT( tool )->name );\n\t\tbreak;\n\n\tcase TOOL_SEP:\n\t\tif( (tool->toolitem = toolitem_new( NULL, NULL, tool )) )\n\t\t\ttool->toolitem->is_separator = TRUE;\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( 0 );\n\t}\n\n\tiobject_changed( IOBJECT( tool ) );\n\n#ifdef DEBUG_MENUS\n\tif( tool->toolitem )\n\t\ttoolitem_print_all( tool->toolitem );\n#endif /*DEBUG_MENUS*/\n}\n\n/* The expr has a new value.\n */\nstatic void\ntool_new_value_cb( Symbol *sym, Tool *tool )\n{\n#ifdef DEBUG\n\tprintf( \"tool_new_value_cb: new value for \" );\n\tsymbol_name_print( sym );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\ttool_toolitem_rebuild( tool );\n}\n\nstatic void\ntool_set_help( Tool *tool ) \n{\n\tchar *p;\n\tchar value[MAX_NAME];\n\n\tif( tool->sym &&\n\t\ttool->sym->expr &&\n\t\ttool->sym->expr->compile &&\n\t\t(p = tool->sym->expr->compile->text) ) {\n\t\t/* Skip leading whitespace.\n\t\t */\n\t\twhile( isspace( (int)(*p) ) )\n\t\t\tp++;\n\n\t\t/* Skip leading comment, if any.\n\t\t */\n\t\tif( p[0] == '/' && p[1] == '*' )\n\t\t\tp += 2;\n\t\telse if( p[0] == '/' && p[1] == '/' )\n\t\t\tp += 2;\n\n\t\t/* Skip more whitespace.\n\t\t */\n\t\twhile( isspace( (int)(*p) ) )\n\t\t\tp++;\n\n\t\t/* Limit to MAX_NAME chars or 1st line. Strip trailing\n\t\t * whitespace.\n\t\t */\n\t\tim_strncpy( value, p, MAX_NAME );\n\t\tif( (p = strchr( value, '\\n' )) )\n\t\t\t*p = '\\0';\n\t\t*((char *) my_strrspn( value, WHITESPACE )) = '\\0';\n\n\t\tIM_SETSTR( tool->help, value );\n\t}\n\telse if( tool->sym &&\n\t\ttool->sym->type == SYM_EXTERNAL )\n\t\tIM_SETSTR( tool->help, tool->sym->function->desc );\n\telse if( tool->sym &&\n\t\ttool->sym->type == SYM_BUILTIN )\n\t\tIM_SETSTR( tool->help, tool->sym->builtin->desc );\n\telse\n\t\tIM_SETSTR( tool->help, NULL );\n}\n\n/* Add a symbol to a toolkit. \n */\nTool *\ntool_new_sym( Toolkit *kit, int pos, Symbol *sym )\n{\n\tTool *tool;\n\n\tg_assert( kit && sym );\n\n\t/* Is there a tool we can reuse? Don't update pos .. assume we want to\n\t * keep the old one.\n\t */\n\tif( (tool = sym->tool) &&\n\t\ttool->kit == kit ) {\n\t\ttool->lineno = -1;\n\t\ttool_set_help( tool );\n\t\treturn( tool );\n\t}\n\n\t/* Junk any existing tool for this sym.\n\t */\n\tif( (tool = sym->tool) ) {\n\t\tsym->tool = NULL;\n\t\ttool->sym = NULL;\n\n\t\tIDESTROY( tool );\n\t}\n\n\ttool = TOOL( g_object_new( TYPE_TOOL, NULL ) );\n\ttool->type = TOOL_SYM;\n\ttool->sym = sym;\n\tsym->tool = tool;\n\ttool->new_value_sid = g_signal_connect( sym, \"new_value\", \n\t\tG_CALLBACK( tool_new_value_cb ), tool );\n\ttool->link_sym = sym;\n\ttool_link( tool, kit, pos, IOBJECT( sym )->name );\n\n\ttool_set_help( tool );\n\n#ifdef DEBUG\n\tprintf( \"tool_new_sym: new tool for \" );\n\tsymbol_name_print( sym );\n\tprintf( \"at %p\\n\", tool );\n#endif /*DEBUG*/\n\n\treturn( tool );\n}\n\n/* Add a separator to a toolkit. \n */\nTool *\ntool_new_sep( Toolkit *kit, int pos )\n{\n\tTool *tool;\n\n\tg_assert( kit );\n\n\ttool = TOOL( g_object_new( TYPE_TOOL, NULL ) );\n\ttool->type = TOOL_SEP;\n\tiobject_set( IOBJECT( tool ), \"separator\", NULL );\n\ttool_link( tool, kit, pos, NULL );\n\ttool_toolitem_rebuild( tool );\n\n\treturn( tool );\n}\n\n/* Search a kit for a tool by tool name. Used for searching for dialogs ... we\n * can't use the symtable stuff, as they're not syms.\n */\nstatic Tool *\ntool_find( Toolkit *kit, const char *name )\n{\n\treturn( (Tool *) icontainer_map( ICONTAINER( kit ), \n\t\t(icontainer_map_fn) iobject_test_name, (char *) name, NULL ) );\n}\n\n/* Add a dialog entry to a toolkit. \n */\nTool *\ntool_new_dia( Toolkit *kit, int pos, \n\tconst char *name, const char *filename )\n{\n\tTool *tool;\n\n\tg_assert( kit && name && filename );\n\n\tif( (tool = tool_find( kit, name )) ) {\n\t\tif( tool->type != TOOL_DIA ) {\n\t\t\terror_top( _( \"Name clash.\" ) );\n\t\t\terror_sub( _( \"Can't create dialog with name \\\"%s\\\", \"\n\t\t\t\t\"an object with that name already exists in \"\n\t\t\t\t\"kit \\\"%s\\\".\" ), \n\t\t\t\tname, IOBJECT( kit )->name );\n\t\t\treturn( NULL );\n\t\t}\n\n\t\t/* Just update the filename.\n\t\t */\n\t\tfilemodel_set_filename( FILEMODEL( tool ), filename );\n\t\ttool->lineno = -1;\n\t}\n\telse {\n\t\ttool = TOOL( g_object_new( TYPE_TOOL, NULL ) );\n\t\ttool->type = TOOL_DIA;\n\t\tfilemodel_set_filename( FILEMODEL( tool ), filename );\n\t\tiobject_set( IOBJECT( tool ), name, NULL );\n\t\ttool_link( tool, kit, pos, NULL );\n\t}\n\n\ttool_toolitem_rebuild( tool );\n\n\treturn( tool );\n}\n\nstatic Toolitem *\ntoolitem_lookup_toolitem( Toolitem *toolitem, Symbol *action )\n{\n\tif( toolitem->action_sym == action )\n\t\treturn( toolitem );\n\telse\n\t\treturn( (Toolitem *) slist_map( toolitem->children,\n\t\t\t(SListMapFn) toolitem_lookup_toolitem, action ) );\n}\n\nstatic Toolitem *\ntoolitem_lookup_tool( Tool *tool, Symbol *action )\n{\n\tif( tool->toolitem )\n\t\treturn( toolitem_lookup_toolitem( tool->toolitem, action ) );\n\telse\n\t\treturn( NULL );\n}\n\nstatic Toolitem *\ntoolitem_lookup_toolkit( Toolkit *kit, Symbol *action )\n{\n\treturn( (Toolitem *) toolkit_map( kit, \n\t\t(tool_map_fn) toolitem_lookup_tool,\n\t\taction, NULL ) );\n}\n\n/* Just walk the whole kit. Could use a hash in kitg, but we don't call this\n * so often.\n */\nToolitem *\ntoolitem_lookup( Toolkitgroup *kitg, Symbol *action )\n{\n\treturn( (Toolitem *) toolkitgroup_map( kitg,\n\t\t(toolkit_map_fn) toolitem_lookup_toolkit, \n\t\taction, NULL ) );\n}\n"
  },
  {
    "path": "src/tool.h",
    "content": "/* Tools ... mostly a menu item.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* Build a tree of these for each tool we make.\n */\nstruct _Toolitem {\n\t/* The thing for which we are making an item. Eg. if the .def file\n\t * has 'fred = class Menuitem \"poop\" \"lots of poop\" {}', this is the\n\t * Compile for fred.\n\t *\n\t * compile is not always valid .. eg. for #dialog or #separator\n\t */\n\tCompile *compile;\n\n\t/* The top-level tool we come from.\n\t */\n\tTool *tool;\n\n\t/* The symbol we perform the action with (eg. get nparam from this).\n\t */\n\tSymbol *action_sym;\n\n\t/* Set for a separator.\n\t */\n\tgboolean is_separator;\n\n\t/* Set if we decide during build that this item should be a pullright.\n\t */\n\tgboolean is_pullright;\n\n\t/* If this is a pullright, the children of this item. If we are a\n\t * child, the parent.\n\t */\n\tGSList *children;\n\tToolitem *parent;\n\n\t/* Set if we decide this should have an action.\n\t */\n\tgboolean is_action;\n\n\tchar *label;\t\t/* eg. \"W_hite Balance\" */\n\tchar *name;\t\t/* eg. \"White Balance\" */\n\tchar *icon;\t\t/* eg. \"$VIPSHOME/icons/wb.png\" */\n\tchar *tooltip;\t\t/* eg. \"move whitepoint to region neutral\" */\n\tchar *help;\t\t/* eg. \"White Balance r: move ...\" */\n\tchar *action;\t\t/* eg. \"White_balance_widget._action\" */\n\tchar *path;\t\t/* eg. \"<mainw>/Toolkits/Image\" */\n\tchar *user_path;\t/* eg. \"Image / White Balance\" */\n};\n\n#define TYPE_TOOL (tool_get_type())\n#define TOOL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_TOOL, Tool ))\n#define TOOL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_TOOL, ToolClass))\n#define IS_TOOL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_TOOL ))\n#define IS_TOOL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_TOOL ))\n#define TOOL_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_TOOL, ToolClass ))\n\n/* Tool types: a def (sym points to symbol for this def), a dialog (keep\n * filename and prompt name), or a separator.\n */\ntypedef enum {\n\tTOOL_SYM,\n\tTOOL_DIA,\n\tTOOL_SEP\n} Tooltype;\n\n/* What we hold for each tool. \n */\nstruct _Tool {\n\tFilemodel parent_class;\n\n\tTooltype type;\t\t\n\tSymbol *sym;\t\t/* For SYM tools: symbol this tool represents */\n\tguint new_value_sid;\t/* Watch for new_value with this */\n\tSymbol *link_sym;\t/* the sym we are watching (in case ->sym is\n\t\t\t\t   NULLed before we try to disconnect */\n\n\tToolkit *kit; \t\t/* Link back to toolkit */\n\tint lineno;\t\t/* -1 for not known, or lineno in kit */\n\n\tToolitem *toolitem;\t/* Items made by this tool */\n\n\t/* The first line of the comment prior to the definition. Toolitem help\n\t * and tooltip can be generated from the Menuitem members.\n\t */\n\tchar *help;\t\t/* eg. \"concat l: join a list of ..\" */\n};\n\ntypedef struct _ToolClass {\n\tFilemodelClass parent_class;\n\n\t/* My methods.\n\t */\n} ToolClass;\n\nvoid tool_error( Tool *tool, VipsBuf *buf );\n\nvoid *tool_linkreport_tool( Tool *tool, VipsBuf *buf, gboolean *found );\n\nGType tool_get_type( void );\n\nTool *tool_new_sym( Toolkit *kit, int pos, Symbol *sym );\nTool *tool_new_sep( Toolkit *kit, int pos );\nTool *tool_new_dia( Toolkit *kit, int pos, \n\tconst char *filename, const char *name );\n\nToolitem *toolitem_lookup( Toolkitgroup *kitg, Symbol *action );\n"
  },
  {
    "path": "src/toolkit.c",
    "content": "/* Manage toolkits and their display.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic FilemodelClass *parent_class = NULL;\n\nTool *\ntoolkit_map( Toolkit *kit, tool_map_fn fn, void *a, void *b )\n{\n\treturn( (Tool *) icontainer_map( ICONTAINER( kit ), \n\t\t(icontainer_map_fn) fn, a, b ) );\n}\n\nstatic void\ntoolkit_changed( iObject *iobject )\n{\n\t/* If we change, signal change on our parent too (toolkitgroup) ...\n\t * things like Program and Toolkitbrowser which need to spot any \n \t * change to any kit can connect to that, rather than having to \n\t * connect to all kits independently.\n\t */\n\tif( IS_ICONTAINER( iobject ) && ICONTAINER( iobject )->parent )\n\t\tiobject_changed( IOBJECT( ICONTAINER( iobject )->parent ) );\n}\n\nstatic void\ntoolkit_info( iObject *iobject, VipsBuf *buf )\n{\n\tToolkit *kit = TOOLKIT( iobject );\n\n\tIOBJECT_CLASS( parent_class )->info( iobject, buf );\n\n\tvips_buf_appendf( buf, \"group = \\\"%s\\\"\\n\", IOBJECT( kit->kitg )->name );\n}\n\nstatic View *\ntoolkit_view_new( Model *model, View *parent )\n{\n\treturn( toolkitview_new() );\n}\n\nstatic gboolean\ntoolkit_save_text( Model *model, iOpenFile *of )\n{\n\tif( icontainer_map( ICONTAINER( model ), \n\t\t(icontainer_map_fn) model_save_text, of, NULL ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Load from an iOpenFile.\n */\nstatic gboolean\ntoolkit_load_text( Model *model, Model *parent, iOpenFile *of )\n{\n\tToolkit *kit = TOOLKIT( model );\n\tint pos = icontainer_pos_last( ICONTAINER( model ) ) + 1;\n\tgboolean res;\n\n\t/* Load up definitions.\n\t */\n\tfilemodel_set_filename( FILEMODEL( model ), of->fname_real );\n\tattach_input_file( of );\n\tif( !(res = parse_toplevel( kit, pos )) ) \n\t\t/* The sub won't have filename or line number: zap them in.\n\t\t */\n\t\terror_sub( \"%s:%d\\n%s\\n\", \n\t\t\tFILEMODEL( kit )->filename, input_state.lineno, \n\t\t\terror_get_sub() );\n\n#ifdef DEBUG\n\t(void) dump_kit( kit );\n#endif /*DEBUG*/\n\n\treturn( res );\n}\n\nstatic void\ntoolkit_class_init( ToolkitClass *class )\n{\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tFilemodelClass *filemodel_class = (FilemodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tiobject_class->info = toolkit_info;\n\tiobject_class->changed = toolkit_changed;\n\n\tmodel_class->view_new = toolkit_view_new;\n\tmodel_class->save_text = toolkit_save_text;\n\tmodel_class->load_text = toolkit_load_text;\n\n\tfilemodel_class->filetype = filesel_type_definition;\n}\n\nstatic void\ntoolkit_init( Toolkit *kit )\n{\n\tkit->kitg = NULL;\n\tkit->pseudo = FALSE;\n}\n\nGType\ntoolkit_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ToolkitClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) toolkit_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Toolkit ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) toolkit_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_FILEMODEL, \n\t\t\t\"Toolkit\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\ntoolkit_link( Toolkit *kit, Toolkitgroup *kitg, const char *name )\n{\n\tiobject_set( IOBJECT( kit ), name, NULL );\n\ticontainer_child_add( ICONTAINER( kitg ), ICONTAINER( kit ), -1 );\n\tkit->kitg = kitg;\n\tfilemodel_register( FILEMODEL( kit ) );\n\tif( name[0] == '_' )\n\t\tMODEL( kit )->display = FALSE;\n\ttoolkitgroup_sort( kitg );\n}\n\n/* Find a kit by kit name.\n */\nToolkit *\ntoolkit_find( Toolkitgroup *kitg, const char *name )\n{\t\n\treturn( (Toolkit *) icontainer_map( ICONTAINER( kitg ), \n\t\t(icontainer_map_fn) iobject_test_name, (char *) name, NULL ) );\n}\n\nToolkit *\ntoolkit_new( Toolkitgroup *kitg, const char *name )\n{\t\n\tToolkit *kit;\n\n#ifdef DEBUG\n\tprintf( \"toolkit_new: %s\\n\", name );\n#endif /*DEBUG*/\n\n\t/* Exists already?\n\t */\n\tif( (kit = toolkit_find( kitg, name )) ) \n\t\tIDESTROY( kit );\n\n\t/* Make a new kit.\n\t */\n\tkit = TOOLKIT( g_object_new( TYPE_TOOLKIT, NULL ) );\n\ttoolkit_link( kit, kitg, name );\n\n\treturn( kit );\n}\n\nToolkit *\ntoolkit_new_filename( Toolkitgroup *kitg, const char *filename )\n{\n\tchar name[FILENAME_MAX];\n\tToolkit *kit;\n\n\tname_from_filename( filename, name );\n\tkit = toolkit_new( kitg, name );\n\tfilemodel_set_filename( FILEMODEL( kit ), filename );\n\n\treturn( kit );\n}\n\n/* Load a file as a toolkit.\n */\nToolkit *\ntoolkit_new_from_file( Toolkitgroup *kitg, const char *filename )\n{\n\tToolkit *kit = toolkit_new_filename( kitg, filename );\n\tgboolean res;\n\n\tres = filemodel_load_all( FILEMODEL( kit ), MODEL( kitg ), \n\t\tfilename, NULL );\n\tfilemodel_set_modified( FILEMODEL( kit ), FALSE );\n\n\t/* Don't remove the kit if load failed, we want to leave it so the \n\t * user can try to fix the problem.\n\t */\n\n\tif( res )\n\t\treturn( kit );\n\telse\n\t\treturn( NULL );\n}\n\n/* Load from an iOpenFile.\n */\nToolkit *\ntoolkit_new_from_openfile( Toolkitgroup *kitg, iOpenFile *of )\n{\n\tToolkit *kit = toolkit_new_filename( kitg, of->fname );\n\tgboolean res;\n\n\tres = filemodel_load_all_openfile( FILEMODEL( kit ), \n\t\tMODEL( kitg ), of );\n\tfilemodel_set_modified( FILEMODEL( kit ), FALSE );\n\n\t/* Don't remove the kit if load failed, we want to leave it so the \n\t * user can try to fix the problem.\n\t */\n\n\tif( res )\n\t\treturn( kit );\n\telse\n\t\treturn( NULL );\n}\n\n/* Look up a toolkit, make an empty one if not there.\n */\nToolkit *\ntoolkit_by_name( Toolkitgroup *kitg, const char *name )\n{\n\tToolkit *kit;\n\n\tif( !(kit = toolkit_find( kitg, name )) ) {\n\t\tchar file[FILENAME_MAX];\n\n\t\tim_snprintf( file, FILENAME_MAX,\n\t\t\t\"$SAVEDIR\" G_DIR_SEPARATOR_S \"start\" G_DIR_SEPARATOR_S \n\t\t\t\"%s.def\", \n\t\t\tname );\n\t\tkit = toolkit_new_filename( kitg, file );\n\t}\n\n\treturn( kit );\n}\n"
  },
  {
    "path": "src/toolkit.h",
    "content": "/* Groups of tools!\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_TOOLKIT (toolkit_get_type())\n#define TOOLKIT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_TOOLKIT, Toolkit ))\n#define TOOLKIT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_TOOLKIT, ToolkitClass))\n#define IS_TOOLKIT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_TOOLKIT ))\n#define IS_TOOLKIT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_TOOLKIT ))\n#define TOOLKIT_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_TOOLKIT, ToolkitClass ))\n\n/* Toolkits: group definitions with these guys. One toolkit per definition file\n * loaded.\n */\nstruct _Toolkit {\n\tFilemodel parent_class;\n\n\tToolkitgroup *kitg;\n\n\t/* Set this for auto-generated toolkits (eg. packages of function from\n\t * VIPS) ... blocks edit etc. in program window.\n\t */\n\tgboolean pseudo;\n};\n\ntypedef struct _ToolkitClass {\n\tFilemodelClass parent_class;\n\n\t/* My methods.\n\t */\n} ToolkitClass;\n\nTool *toolkit_map( Toolkit *kit, tool_map_fn fn, void *a, void *b );\n\nGType toolkit_get_type( void );\n\nToolkit *toolkit_find( Toolkitgroup *kitg, const char *name );\nToolkit *toolkit_by_name( Toolkitgroup *kitg, const char *name );\n\nToolkit *toolkit_new( Toolkitgroup *kitg, const char *filename );\nToolkit *toolkit_new_filename( Toolkitgroup *kitg, const char *filename );\nToolkit *toolkit_new_from_file( Toolkitgroup *kitg, const char *filename );\nToolkit *toolkit_new_from_openfile( Toolkitgroup *kitg, iOpenFile *of );\n\nvoid *toolkit_linkreport( Toolkit *kit, VipsBuf *buf, gboolean *bad_links );\n"
  },
  {
    "path": "src/toolkitbrowser.c",
    "content": "/* Toolkitbrowser dialog.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk \n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\n/* Our columns.\n */\nenum {\n\tTOOLTIP_COLUMN,\t\t/* Visible columns */\n\tMENU_COLUMN, \t\t\n\tNPARAM_COLUMN,\n\tTOOLITEM_COLUMN,\t/* Secret column */\n\tN_COLUMNS\n};\n\nstatic void\ntoolkitbrowser_destroy( GtkObject *object )\n{\n\tToolkitbrowser *toolkitbrowser = TOOLKITBROWSER( object );\n\n\tUNREF( toolkitbrowser->filter );\n\tUNREF( toolkitbrowser->store );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void *\ntoolkitbrowser_rebuild_item_sub( Symbol *param, VipsBuf *buf )\n{\n\tvips_buf_appends( buf, \" \" );\n\tvips_buf_appends( buf, IOBJECT( param )->name );\n\n\treturn( NULL );\n}\n\nstatic void *\ntoolkitbrowser_rebuild_item3( Toolitem *toolitem,\n\tToolkitbrowser *toolkitbrowser )\n{\n\tif( !toolitem->is_pullright && \n\t\t!toolitem->is_separator &&\n\t\ttoolitem->compile ) {\n\t\tchar txt[256];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\t\tGtkTreeIter iter;\n\n\t\tif( toolitem->action_sym && \n\t\t\ttoolitem->action_sym->expr &&\n\t\t\ttoolitem->action_sym->expr->compile->param ) \n\t\t\tslist_map( toolitem->action_sym->expr->compile->param,\n\t\t\t\t(SListMapFn) toolkitbrowser_rebuild_item_sub, \n\t\t\t\t&buf );\n\n\t\tgtk_list_store_append( toolkitbrowser->store, &iter );\n\t\tgtk_list_store_set( toolkitbrowser->store, &iter,\n\t\t\tTOOLTIP_COLUMN, toolitem->tooltip,\n\t\t\tMENU_COLUMN, toolitem->user_path,\n\t\t\tNPARAM_COLUMN, vips_buf_all( &buf ),\n\t\t\tTOOLITEM_COLUMN, toolitem,\n\t\t\t-1 );\n\t}\n\n\tslist_map( toolitem->children,\n\t\t(SListMapFn) toolkitbrowser_rebuild_item3, toolkitbrowser );\n\n\treturn( NULL );\n}\n\nstatic void *\ntoolkitbrowser_rebuild_item2( Tool *tool, Toolkitbrowser *toolkitbrowser )\n{\n\tif( tool->toolitem )\n\t\ttoolkitbrowser_rebuild_item3( tool->toolitem, toolkitbrowser );\n\n\treturn( NULL );\n}\n\nstatic void *\ntoolkitbrowser_rebuild_item( Toolkit *kit, Toolkitbrowser *toolkitbrowser )\n{\n\ttoolkit_map( kit, \n\t\t(tool_map_fn) toolkitbrowser_rebuild_item2,\n\t\ttoolkitbrowser, NULL );\n\n\treturn( NULL );\n}\n\nstatic void\ntoolkitbrowser_refresh( vObject *vobject )\n{\n\tToolkitbrowser *toolkitbrowser = TOOLKITBROWSER( vobject );\n\n#ifdef DEBUG\n\tprintf( \"toolkitbrowser_refresh:\\n\" );\n#endif /*DEBUG*/\n\n\tgtk_list_store_clear( toolkitbrowser->store );\n\ttoolkitgroup_map( toolkitbrowser->kitg,\n\t\t(toolkit_map_fn) toolkitbrowser_rebuild_item, \n\t\ttoolkitbrowser, NULL );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\ntoolkitbrowser_link( vObject *vobject, iObject *iobject )\n{\n\tToolkitbrowser *toolkitbrowser = TOOLKITBROWSER( vobject );\n\tToolkitgroup *kitg = TOOLKITGROUP( iobject );\n\n\tg_assert( !toolkitbrowser->kitg );\n\n\ttoolkitbrowser->kitg = kitg;\n\n\tVOBJECT_CLASS( parent_class )->link( vobject, iobject );\n}\n\nstatic void\ntoolkitbrowser_class_init( ToolkitbrowserClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = toolkitbrowser_destroy;\n\n\tvobject_class->refresh = toolkitbrowser_refresh;\n\tvobject_class->link = toolkitbrowser_link;\n}\n\nstatic void\ntoolkitbrowser_entry_changed_cb( GtkEditable *editable, \n\tToolkitbrowser *toolkitbrowser )\n{\n\tgtk_tree_model_filter_refilter( \n\t\tGTK_TREE_MODEL_FILTER( toolkitbrowser->filter ) );\n}\n\nstatic gboolean\ntoolkitbrowser_rebuild_test( Toolitem *toolitem, const char *text )\n{\n\tif( my_strcasestr( toolitem->user_path, text ) || \n\t\tmy_strcasestr( toolitem->tooltip, text ) )\n\t\treturn( TRUE );\n\n\treturn( FALSE );\n}\n\nstatic gboolean\ntoolkitbrowser_visible_func( GtkTreeModel *model, GtkTreeIter *iter, \n\tgpointer data )\n{\n\tToolkitbrowser *toolkitbrowser = TOOLKITBROWSER( data );\n\tconst char *text = gtk_entry_get_text( \n\t\tGTK_ENTRY( toolkitbrowser->entry ) );\n\tToolitem *toolitem;\n\n\tgtk_tree_model_get( model, iter, TOOLITEM_COLUMN, &toolitem, -1 );\n\tif( !toolitem )\n\t\treturn( FALSE );\n\n\treturn( toolkitbrowser_rebuild_test( toolitem, text ) );\n}\n\nstatic Toolitem *\ntoolkitbrowser_get_selected( Toolkitbrowser *toolkitbrowser )\n{\n\tGtkTreeSelection *selection = gtk_tree_view_get_selection( \n\t\tGTK_TREE_VIEW( toolkitbrowser->tree ) );\n\tGtkTreeIter iter;\n\tGtkTreeModel *model;\n\tToolitem *toolitem; \n\n        if( gtk_tree_selection_get_selected( selection, &model, &iter ) ) {\n\t\tgtk_tree_model_get( model, &iter, \n\t\t\tTOOLITEM_COLUMN, &toolitem, -1 );\n\n\t\treturn( toolitem );\n        }\n\n\treturn( NULL );\n}\n\nstatic gboolean\ntoolkitbrowser_activate_selected( Toolkitbrowser *toolkitbrowser )\n{\n\tToolitem *toolitem;\n\n        if( (toolitem = toolkitbrowser_get_selected( toolkitbrowser )) ) {\n\t\tif( !workspace_add_action( toolkitbrowser->ws, \n\t\t\ttoolitem->name, toolitem->action, \n\t\t\ttoolitem->action_sym->expr->compile->nparam ) )\n\t\t\treturn( FALSE );\n        }\n\n\treturn( TRUE );\n}\n\nstatic void\ntoolkitbrowser_row_activated_cb( GtkTreeView *treeview,\n\tGtkTreePath *arg1, GtkTreeViewColumn *arg2, \n\tToolkitbrowser *toolkitbrowser )\n{\n\tif( !toolkitbrowser_activate_selected( toolkitbrowser ) )\n\t\tiwindow_alert( GTK_WIDGET( toolkitbrowser ), \n\t\t\tGTK_MESSAGE_ERROR );\n}\n\nstatic void\ntoolkitbrowser_init( Toolkitbrowser *toolkitbrowser )\n{\n\tGtkCellRenderer *renderer;\n\tGtkTreeViewColumn *column;\n\tGtkWidget *label;\n\tGtkWidget *swin;\n\n\ttoolkitbrowser->top = gtk_hbox_new( FALSE, 12 );\n\ttoolkitbrowser->entry = gtk_entry_new();\n        gtk_signal_connect( GTK_OBJECT( toolkitbrowser->entry ), \"changed\", \n\t\tGTK_SIGNAL_FUNC( toolkitbrowser_entry_changed_cb ), \n\t\ttoolkitbrowser );\n\tgtk_box_pack_end( GTK_BOX( toolkitbrowser->top ), \n\t\ttoolkitbrowser->entry, FALSE, FALSE, 2 );\n\tlabel = gtk_image_new_from_stock( GTK_STOCK_FIND, GTK_ICON_SIZE_MENU );\n\tgtk_box_pack_end( GTK_BOX( toolkitbrowser->top ), \n\t\tlabel, FALSE, FALSE, 0 );\n        gtk_box_pack_start( GTK_BOX( toolkitbrowser ), \n\t\ttoolkitbrowser->top, FALSE, FALSE, 2 );\n\tgtk_widget_show_all( toolkitbrowser->top );\n\n\ttoolkitbrowser->store = gtk_list_store_new( N_COLUMNS, \n\t\tG_TYPE_STRING, \n\t\tG_TYPE_STRING,\n\t\tG_TYPE_STRING,\n\t\tG_TYPE_POINTER );\n\n\ttoolkitbrowser->filter = gtk_tree_model_filter_new( \n\t\tGTK_TREE_MODEL( toolkitbrowser->store ), NULL );\n\tgtk_tree_model_filter_set_visible_func( \n\t\tGTK_TREE_MODEL_FILTER( toolkitbrowser->filter ), \n\t\ttoolkitbrowser_visible_func, toolkitbrowser, NULL );\n\n\ttoolkitbrowser->tree = gtk_tree_view_new_with_model( \n\t\tGTK_TREE_MODEL( toolkitbrowser->filter ) );\n\tgtk_tree_view_set_rules_hint( GTK_TREE_VIEW( toolkitbrowser->tree ),\n\t\tTRUE );\n\n\trenderer = gtk_cell_renderer_text_new();\n\tcolumn = gtk_tree_view_column_new_with_attributes( _( \"Action\" ),\n\t\t   renderer, \"text\", TOOLTIP_COLUMN, NULL );\n\tgtk_tree_view_column_set_resizable( column, TRUE );\n\tgtk_tree_view_column_set_reorderable( column, TRUE );\n\tgtk_tree_view_append_column( GTK_TREE_VIEW( toolkitbrowser->tree ), \n\t\tcolumn );\n\n\trenderer = gtk_cell_renderer_text_new();\n\tcolumn = gtk_tree_view_column_new_with_attributes( _( \"Parameters\" ),\n\t\t   renderer, \"text\", NPARAM_COLUMN, NULL );\n\tgtk_tree_view_column_set_resizable( column, TRUE );\n\tgtk_tree_view_column_set_reorderable( column, TRUE );\n\tgtk_tree_view_append_column( GTK_TREE_VIEW( toolkitbrowser->tree ), \n\t\tcolumn );\n\n\trenderer = gtk_cell_renderer_text_new();\n\tcolumn = gtk_tree_view_column_new_with_attributes( _( \"Menu Item\" ),\n\t\t   renderer, \"text\", MENU_COLUMN, NULL );\n\tgtk_tree_view_column_set_resizable( column, TRUE );\n\tgtk_tree_view_column_set_reorderable( column, TRUE );\n\tgtk_tree_view_append_column( GTK_TREE_VIEW( toolkitbrowser->tree ), \n\t\tcolumn );\n\n\tg_signal_connect( G_OBJECT( toolkitbrowser->tree ), \"row-activated\",\n\t\t  G_CALLBACK( toolkitbrowser_row_activated_cb ), \n\t\t  toolkitbrowser );\n\n\tswin = gtk_scrolled_window_new( NULL, NULL );\n        gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ),\n\t\tGTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );\n\tgtk_container_add( GTK_CONTAINER( swin ), toolkitbrowser->tree );\n\n        gtk_box_pack_start( GTK_BOX( toolkitbrowser ), swin, TRUE, TRUE, 2 );\n\tgtk_widget_show_all( swin );\n}\n\nGtkType\ntoolkitbrowser_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Toolkitbrowser\",\n\t\t\tsizeof( Toolkitbrowser ),\n\t\t\tsizeof( ToolkitbrowserClass ),\n\t\t\t(GtkClassInitFunc) toolkitbrowser_class_init,\n\t\t\t(GtkObjectInitFunc) toolkitbrowser_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_VOBJECT, &info );\n\t}\n\n\treturn( type );\n}\n\nToolkitbrowser *\ntoolkitbrowser_new( void )\n{\n\tToolkitbrowser *toolkitbrowser = gtk_type_new( TYPE_TOOLKITBROWSER );\n\n\treturn( toolkitbrowser );\n}\n\n/* Find the 'natural' width of the browser.\n */\nint \ntoolkitbrowser_get_width( Toolkitbrowser *toolkitbrowser )\n{\n\tif( toolkitbrowser->top )\n\t\treturn( toolkitbrowser->top->requisition.width );\n\telse\n\t\treturn( 200 );\n}\n\nvoid\ntoolkitbrowser_set_workspace( Toolkitbrowser *toolkitbrowser, Workspace *ws )\n{\n\tg_assert( !toolkitbrowser->ws );\n\n\ttoolkitbrowser->ws = ws;\n}\n"
  },
  {
    "path": "src/toolkitbrowser.h",
    "content": "/* Toolkit browser\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_TOOLKITBROWSER (toolkitbrowser_get_type())\n#define TOOLKITBROWSER( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_TOOLKITBROWSER, Toolkitbrowser ))\n#define TOOLKITBROWSER_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_TOOLKITBROWSER, ToolkitbrowserClass ))\n#define IS_TOOLKITBROWSER( obj ) \\\n\t(GTK_CHECK_TYPE( (obj), TYPE_TOOLKITBROWSER ))\n#define IS_TOOLKITBROWSER_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_TOOLKITBROWSER ))\n\nstruct _Toolkitbrowser {\n\tvObject parent_object;\n\n\tToolkitgroup *kitg;\n\tWorkspace *ws;\n\n\tGtkListStore *store;\t\t/* Model for list view */\n\tGtkTreeModel *filter;\t\t/* After filtering with search box */\n\tGtkWidget *tree;\t\t/* Displayed tree */\n\tGtkWidget *entry;\t\t/* Search widget */\n\tGtkWidget *top;\t\t\t/* hbox for top bar */\n};\n\ntypedef struct _ToolkitbrowserClass {\n\tvObjectClass parent_class;\n\n} ToolkitbrowserClass;\n\nGtkType toolkitbrowser_get_type( void );\nvoid toolkitbrowser_set_mainw( Toolkitbrowser *toolkitbrowser, Mainw *mainw );\nToolkitbrowser *toolkitbrowser_new( void );\nint toolkitbrowser_get_width( Toolkitbrowser *toolkitbrowser );\nvoid toolkitbrowser_set_workspace( Toolkitbrowser *toolkitbrowser, \n\tWorkspace *ws );\n\n"
  },
  {
    "path": "src/toolkitgroup.c",
    "content": "/* Group toolkitgroup files together.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ModelClass *parent_class = NULL;\n\nToolkit *\ntoolkitgroup_map( Toolkitgroup *kitg, toolkit_map_fn fn, void *a, void *b )\n{\n\treturn( (Toolkit *) icontainer_map( ICONTAINER( kitg ), \n\t\t(icontainer_map_fn) fn, a, b ) );\n}\n\nstatic void\ntoolkitgroup_changed( iObject *iobject )\n{\n#ifdef DEBUG\n\tg_print( \"toolkitgroup_changed: \" );\n\tiobject_print( iobject );\n#endif /*DEBUG*/\n\n\tIOBJECT_CLASS( parent_class )->changed( iobject );\n}\n\nstatic View *\ntoolkitgroup_view_new( Model *model, View *parent )\n{\n\treturn( toolkitgroupview_new() );\n}\n\nstatic void\ntoolkitgroup_class_init( ToolkitgroupClass *class )\n{\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tiobject_class->changed = toolkitgroup_changed;\n\n\tmodel_class->view_new = toolkitgroup_view_new;\n}\n\nstatic void\ntoolkitgroup_init( Toolkitgroup *kitg )\n{\n}\n\nGType\ntoolkitgroup_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ToolkitgroupClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) toolkitgroup_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Toolkitgroup ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) toolkitgroup_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_MODEL, \n\t\t\t\"Toolkitgroup\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\ntoolkitgroup_link( Toolkitgroup *kitg, Symbol *root )\n{\n\tchar buf[256];\n\n\tg_assert( root );\n\n\tkitg->root = root;\n\n\tim_snprintf( buf, 256, _( \"Toolkits for %s\" ),\n\t\tIOBJECT( root )->name );\n\tiobject_set( IOBJECT( kitg ), buf, NULL );\n}\n\nToolkitgroup *\ntoolkitgroup_new( Symbol *root )\n{\n\tToolkitgroup *kitg;\n\n\tkitg = TOOLKITGROUP( g_object_new( TYPE_TOOLKITGROUP, NULL ) );\n\ttoolkitgroup_link( kitg, root );\n\n\treturn( kitg );\n}\n\n/* Need a special sort function ... put kits not being displayed at the end so\n * they don't mess up the numbering of the visible kits.\n */\nstatic gint\ntoolkitgroup_sort_compare( Model *a, Model *b )\n{\n\tif( !a->display && b->display )\n\t\treturn( 1 );\n\tif( a->display && !b->display )\n\t\treturn( -1 );\n\n        return( strcasecmp( IOBJECT( a )->name, IOBJECT( b )->name ) );\n}\n\nvoid\ntoolkitgroup_sort( Toolkitgroup *kitg )\n{\n\tiContainer *icontainer = ICONTAINER( kitg );\n\n        icontainer->children = g_slist_sort( icontainer->children, \n\t\t(GCompareFunc) toolkitgroup_sort_compare );\n\ticontainer_pos_renumber( icontainer );\n}\n"
  },
  {
    "path": "src/toolkitgroup.h",
    "content": "/* Declarations for toolkitgroup.c\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_TOOLKITGROUP (toolkitgroup_get_type())\n#define TOOLKITGROUP( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_TOOLKITGROUP, Toolkitgroup ))\n#define TOOLKITGROUP_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_TOOLKITGROUP, \\\n\t\tToolkitgroupClass))\n#define IS_TOOLKITGROUP( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_TOOLKITGROUP ))\n#define IS_TOOLKITGROUP_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_TOOLKITGROUP ))\n#define TOOLKITGROUP_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_TOOLKITGROUP, \\\n\t\tToolkitgroupClass ))\n\n/* A toolkitgroup.\n */\nstruct _Toolkitgroup {\n\tModel parent_class;\n\n\t/* Defs in toolkits in this group are created as locals of this\n\t * symbol. This is symbol_root for the main toolkitgroup, but can be\n\t * local to a workspace if we are loading a set of compatibility defs.\n\t */\n\tSymbol *root;\n};\n\ntypedef struct _ToolkitgroupClass {\n\tModelClass parent_class;\n\n\t/* Methods.\n\t */\n} ToolkitgroupClass;\n\nToolkit *toolkitgroup_map( Toolkitgroup *kitg, \n\ttoolkit_map_fn fn, void *a, void *b );\n\nGType toolkitgroup_get_type( void );\n\nToolkitgroup *toolkitgroup_new( Symbol *root );\n\nvoid toolkitgroup_sort( Toolkitgroup *kitg );\n"
  },
  {
    "path": "src/toolkitgroupview.c",
    "content": "/* a toolkitgroupview button in a toolkitgroup\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n/* \n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\nstatic void *\ntoolkitgroupview_dispose_sub( View *view, void *a, void *b )\n{\n\tDESTROY_GTK( view );\n\n\treturn( NULL );\n}\n\nstatic void\ntoolkitgroupview_dispose( GObject *gobject )\n{\n#ifdef DEBUG\n\tprintf( \"toolkitgroupview_dispose: %p\\n\", gobject );\n#endif /*DEBUG*/\n\n\t/* Toolkitviews are not child widgets of us, they are menu items pased\n\t * into the TK. Destroy them explicitly.\n\t */\n\tview_map( VIEW( gobject ), \n\t\ttoolkitgroupview_dispose_sub, NULL, NULL ); \n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void \ntoolkitgroupview_refresh( vObject *vobject )\n{\n\t/* \n\tToolkitgroupview *kitgview = TOOLKITGROUPVIEW( view );\n\t */\n\n\t/* FIXME ... should update display for reordering of toolkits (to keep\n\t * menu sorted)\n\t */\n\n#ifdef DEBUG\n\tprintf( \"toolkitgroup changed\\n\" );\n#endif /*DEBUG*/\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\ntoolkitgroupview_class_init( ToolkitgroupviewClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->dispose = toolkitgroupview_dispose;\n\n\t/* Create signals.\n\t */\n\n\t/* Set methods.\n\t */\n\tvobject_class->refresh = toolkitgroupview_refresh;\n}\n\nstatic void\ntoolkitgroupview_init( Toolkitgroupview *kitgview )\n{\n}\n\nGtkType\ntoolkitgroupview_get_type( void )\n{\n\tstatic GtkType toolkitgroupview_type = 0;\n\n\tif( !toolkitgroupview_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Toolkitgroupview\",\n\t\t\tsizeof( Toolkitgroupview ),\n\t\t\tsizeof( ToolkitgroupviewClass ),\n\t\t\t(GtkClassInitFunc) toolkitgroupview_class_init,\n\t\t\t(GtkObjectInitFunc) toolkitgroupview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttoolkitgroupview_type = gtk_type_unique( TYPE_VIEW, &info );\n\t}\n\n\treturn( toolkitgroupview_type );\n}\n\nView *\ntoolkitgroupview_new( void )\n{\n\tToolkitgroupview *kitgview = gtk_type_new( TYPE_TOOLKITGROUPVIEW );\n\n\treturn( VIEW( kitgview ) );\n}\n\nvoid\ntoolkitgroupview_set_mainw( Toolkitgroupview *kitgview, Mainw *mainw )\n{\n\tkitgview->mainw = mainw;\n        kitgview->menu = mainw->toolkit_menu;\n}\n"
  },
  {
    "path": "src/toolkitgroupview.h",
    "content": "/* a view of a toolkitgroup\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_TOOLKITGROUPVIEW (toolkitgroupview_get_type())\n#define TOOLKITGROUPVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_TOOLKITGROUPVIEW, Toolkitgroupview ))\n#define TOOLKITGROUPVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_TOOLKITGROUPVIEW, \\\n\tToolkitgroupviewClass ))\n#define IS_TOOLKITGROUPVIEW( obj ) \\\n\t(GTK_CHECK_TYPE( (obj), TYPE_TOOLKITGROUPVIEW ))\n#define IS_TOOLKITGROUPVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_TOOLKITGROUPVIEW ))\n\nstruct _Toolkitgroupview {\n\tView parent_class;\n\n\tGtkWidget *menu;\t\t/* Display the toolkits in this */\n\tMainw *mainw;\t\t\t/* Mainw these menu items act on */\n};\n\ntypedef struct _ToolkitgroupviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} ToolkitgroupviewClass;\n\nGtkType toolkitgroupview_get_type( void );\nView *toolkitgroupview_new( void );\nvoid toolkitgroupview_set_mainw( Toolkitgroupview *kitgview, Mainw *mainw );\n\n"
  },
  {
    "path": "src/toolkitview.c",
    "content": "/* Manage toolkitviews and their display.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* The top n items in the toolkits menu are made by the system for us ... we\n * pop toolkit items in after these.\n */\n#define TOOLKITVIEW_MENU_OFFSET 3\n\nstatic ViewClass *parent_class = NULL;\n\nstatic void \ntoolkitview_destroy( GtkObject *object )\n{\t\n\tToolkitview *kview;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_TOOLKITVIEW( object ) );\n\n\tkview = TOOLKITVIEW( object );\n\n#ifdef DEBUG\n\tprintf( \"toolkitview_destroy: %p\\n\", object );\n\tprintf( \"toolkitview_destroy: menu = %p\\n\", kview->menu );\n\tprintf( \"toolkitview_destroy: item = %p\\n\", kview->item );\n#endif /*DEBUG*/\n\n\tDESTROY_GTK( kview->menu );\n\tDESTROY_GTK( kview->item );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\ntoolkitview_finalize( GObject *gobject )\n{\n#ifdef DEBUG\n\tprintf( \"toolkitview_finalize: %p\\n\", gobject );\n#endif /*DEBUG*/\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\n/* Our widgets have been killed ... kill us in turn.\n */\nstatic void\ntoolkitview_destroy_cb( GtkWidget *widget, Toolkitview *kview )\n{\n\t/*\n\tprintf( \"toolkitview_destroy_cb: %p\\n\", kview );\n\t */\n\n\tkview->menu = NULL;\n\tkview->item = NULL;\n\tkview->destroy_sid = 0;\n\n\tDESTROY_GTK( kview );\n}\n\nstatic void\ntoolkitview_refresh( vObject *vobject )\n{\n\tToolkitview *kview = TOOLKITVIEW( vobject );\n\tToolkit *kit = TOOLKIT( VOBJECT( kview )->iobject );\n\tToolkitgroupview *kitgview = kview->kitgview;\n\tGtkWidget *menu = kitgview->menu;\n\tgboolean changed = FALSE;\n\n#ifdef DEBUG\n\tprintf( \"toolkitview_refresh: \" );\n\tiobject_print( VOBJECT( kview )->iobject );\n#endif /*DEBUG*/\n\n\t/* Make a button ready for the sub-menu. \n\t */\n\tif( !kview->item ) {\n                kview->item = gtk_menu_item_new_with_label( \n\t\t\tIOBJECT( kit )->name );\n\n                gtk_menu_shell_insert( GTK_MENU_SHELL( menu ),\n\t\t\tkview->item, \n\t\t\tICONTAINER( kit )->pos + TOOLKITVIEW_MENU_OFFSET );\n                gtk_widget_show( kview->item );\n\t\tkview->destroy_sid = g_signal_connect( kview->item, \n\t\t\t\"destroy\",\n\t\t\tG_CALLBACK( toolkitview_destroy_cb ), kview );\n\n\t\tchanged = TRUE;\n\t}\n\tif( !kview->menu ) {\n\t\tiWindow *iwnd = IWINDOW( iwindow_get_root( menu ) );\n\t\tchar path[256];\n\n\t\tkview->menu = gtk_menu_new();\n\t\tgtk_menu_set_accel_group( GTK_MENU( kview->menu ),\n\t\t\tiwnd->accel_group );\n\t\tim_snprintf( path, 256, \n\t\t\t\"<mainw>/Toolkits/%s\", IOBJECT( kit )->name );\n\t\tgtk_menu_set_accel_path( GTK_MENU( kview->menu ), path );\n\n\t\tchanged = TRUE;\n\t}\n\n\tif( changed )\n\t\tgtk_menu_item_set_submenu( GTK_MENU_ITEM( kview->item ), \n\t\t\tkview->menu );\n\n\twidget_visible( kview->item, ICONTAINER( kit )->children != NULL );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\ntoolkitview_link( View *view, Model *model, View *parent )\n{\n\tToolkitview *kview = TOOLKITVIEW( view );\n\tToolkitgroupview *kitgview = TOOLKITGROUPVIEW( parent );\n\n\tkview->kitgview = kitgview;\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n#ifdef DEBUG\n\tprintf( \"toolkitview_link: \" );\n\tiobject_print( VOBJECT( kview )->iobject );\n#endif /*DEBUG*/\n}\n\nstatic void\ntoolkitview_class_init( ToolkitviewClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = toolkitview_finalize;\n\tobject_class->destroy = toolkitview_destroy;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = toolkitview_refresh;\n\n\tview_class->link = toolkitview_link;\n}\n\nstatic void\ntoolkitview_init( Toolkitview *kview )\n{\n        kview->item = NULL;\n        kview->menu = NULL;\n        kview->destroy_sid = 0;\n}\n\nGtkType\ntoolkitview_get_type( void )\n{\n\tstatic GtkType kview_type = 0;\n\n\tif( !kview_type ) {\n\t\tstatic const GtkTypeInfo kview_info = {\n\t\t\t\"Toolkitview\",\n\t\t\tsizeof( Toolkitview ),\n\t\t\tsizeof( ToolkitviewClass ),\n\t\t\t(GtkClassInitFunc) toolkitview_class_init,\n\t\t\t(GtkObjectInitFunc) toolkitview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tkview_type = gtk_type_unique( TYPE_VIEW, &kview_info );\n\t}\n\n\treturn( kview_type );\n}\n\nView *\ntoolkitview_new( void )\n{\n\tToolkitview *kview = gtk_type_new( TYPE_TOOLKITVIEW );\n\n\treturn( VIEW( kview ) );\n}\n\n"
  },
  {
    "path": "src/toolkitview.h",
    "content": "/* View for toolkit.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_TOOLKITVIEW (toolkitview_get_type())\n#define TOOLKITVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_TOOLKITVIEW, Toolkitview ))\n#define TOOLKITVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_TOOLKITVIEW, ToolkitviewClass ))\n#define IS_TOOLKITVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_TOOLKITVIEW ))\n#define IS_TOOLKITVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_TOOLKITVIEW ))\n\nstruct _Toolkitview {\n\tView parent_class;\n\n\tToolkitgroupview *kitgview;\n\n\tGtkWidget *menu;\t/* Menu for this kit */\n\tGtkWidget *item;\t/* Menu item in enclosing menu */\n\tguint destroy_sid;\n};\n\ntypedef struct _ToolkitviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} ToolkitviewClass;\n\nGtkType toolkitview_get_type( void );\nView *toolkitview_new( void );\n"
  },
  {
    "path": "src/toolview.c",
    "content": "/* Manage toolviewkits and their display.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\n/* Link menu items to toolview with this.\n */\nstatic GQuark toolview_quark = 0;\n\nstatic Mainw *\ntoolview_get_mainw( Toolview *tview )\n{\n\tif( !tview->kview ||\n\t\t!tview->kview->kitgview )\n\t\treturn( NULL );\n\n\treturn( tview->kview->kitgview->mainw );\n}\n\nstatic Workspace *\ntoolview_get_workspace( Toolview *tview )\n{\n\tMainw *mainw;\n\n\tif( !(mainw = toolview_get_mainw( tview )) )\n\t\treturn( NULL );\n\n\treturn( mainw_get_workspace( mainw ) ); \n}\n\nstatic Workspace *\nitem_get_workspace( GtkWidget *item )\n{\n\tToolview *tview;\n\n\tif( !(tview = gtk_object_get_data_by_id( GTK_OBJECT( item ), \n\t\ttoolview_quark )) )\n\t\treturn( NULL );\n\n\treturn( toolview_get_workspace( tview ) );\n}\n\nstatic void \ntoolview_destroy( GtkObject *object )\n{\t\n\tToolview *tview;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_TOOLVIEW( object ) );\n\n\ttview = TOOLVIEW( object );\n\n#ifdef DEBUG\n\tprintf( \"toolview_destroy: %p\\n\", object );\n#endif /*DEBUG*/\n\n\tDESTROY_GTK( tview->item );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\ntoolview_finalize( GObject *gobject )\n{\n#ifdef DEBUG\n\tprintf( \"toolview_finalize: %p\\n\", gobject );\n#endif /*DEBUG*/\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\ntoolview_activate_cb( GtkWidget *widget, Toolitem *toolitem )\n{\n\tWorkspace *ws = item_get_workspace( widget );\n\n\tswitch( toolitem->tool->type ) {\n\tcase TOOL_DIA:\n\t\tif( !workspace_merge_file( ws, \n\t\t\tFILEMODEL( toolitem->tool )->filename ) )\n\t\t\tiwindow_alert( widget, GTK_MESSAGE_ERROR );\n\t\tsymbol_recalculate_all();\n\t\tbreak;\n\n\tcase TOOL_SYM:\n\t\tif( !workspace_add_action( ws, \n\t\t\ttoolitem->name, toolitem->action, \n\t\t\ttoolitem->action_sym->expr->compile->nparam ) )\n\t\t\tiwindow_alert( widget, GTK_MESSAGE_ERROR );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n}\n\n/* Flash help for a toolview.\n */\nstatic void \ntoolview_select_cb( GtkWidget *widget, Toolitem *toolitem )\n{\n\tWorkspace *ws = item_get_workspace( widget );\n\n\tif( ws && \n\t\ttoolitem->help )\n\t\tworkspace_set_status( ws, \"%s\", toolitem->help );\n}\n\n/* Sub fn of below ... build a menu item for a TOOL_SYM. \n */\nstatic GtkWidget *\ntoolview_refresh_sub( Toolview *tview, \n\tToolitem *toolitem, Workspace *ws, GtkWidget *menu )\n{\n\tMainw *mainw = toolview_get_mainw( tview );\n\tGtkWidget *item;\n\n\tif( toolitem->is_separator ) \n\t\titem = gtk_menu_item_new();\n\telse {\n\t\titem = gtk_image_menu_item_new_with_mnemonic( toolitem->label );\n\n\t\tgtk_object_set_data_by_id( GTK_OBJECT( item ),\n\t\t\ttoolview_quark, tview );\n\n\t\tif( toolitem->icon )\n\t\t\tgtk_image_menu_item_set_image( \n\t\t\t\tGTK_IMAGE_MENU_ITEM( item ),\n\t\t\t\timage_new_from_file( toolitem->icon ) );\n\n\t\tif( !toolitem->is_pullright ) \n\t\t\tgtk_signal_connect( GTK_OBJECT( item ), \"activate\", \n\t\t\t\tGTK_SIGNAL_FUNC( toolview_activate_cb ), \n\t\t\t\ttoolitem );\n\n\t\tif( toolitem->help && \n\t\t\t!toolitem->is_pullright )\n\t\t\tset_tooltip( item, \"%s\", toolitem->help );\n\n\t\tgtk_signal_connect( GTK_OBJECT( item ), \"select\", \n\t\t\tGTK_SIGNAL_FUNC( toolview_select_cb ), toolitem );\n\n\t\t/* Make a pullright and recurse if necessary\n\t\t */\n\t\tif( toolitem->is_pullright ) {\n\t\t\tGtkWidget *submenu = gtk_menu_new();\n\t\t\tGSList *p;\n\n\t\t\tgtk_menu_set_accel_group( GTK_MENU( submenu ), \n\t\t\t\tIWINDOW( mainw )->accel_group );\n\t\t\tgtk_menu_set_accel_path( GTK_MENU( submenu ), \n\t\t\t\ttoolitem->path );\n\n\t\t\tfor( p = toolitem->children; p; p = p->next ) {\n\t\t\t\tToolitem *child = p->data;\n\n\t\t\t\ttoolview_refresh_sub( tview, \n\t\t\t\t\tchild, ws, submenu );\n\t\t\t}\n\n\t\t\tgtk_menu_item_set_submenu( GTK_MENU_ITEM( item ), \n\t\t\t\tsubmenu );\n\t\t}\n\t}\n\n\t/* Is a top-level toolitem?\n \t */\n\tif( toolitem == toolitem->tool->toolitem ) \n\t\tgtk_menu_shell_insert( GTK_MENU_SHELL( menu ), item, \n\t\t\tICONTAINER( toolitem->tool )->pos + 1 );\n\telse\n\t\t/* Submenus are always completely rebuilt, so we can just \n\t\t * append.\n\t\t */\n\t\tgtk_menu_shell_append( GTK_MENU_SHELL( menu ), item );\n\n\tgtk_widget_show( item );\n\n\treturn( item );\n}\n\n/* Our widget has been destroyed. NULL out or pointer to it, to stop us\n * destroying it again later.\n */\nvoid\ntoolview_destroy_cb( GtkWidget *widget, Toolview *tview )\n{\n\tg_assert( tview->item == widget );\n\n\ttview->item = NULL;\n}\n\n/* Update toolview display.\n */\nstatic void\ntoolview_refresh( vObject *vobject )\n{\n\tToolview *tview = TOOLVIEW( vobject );\n\tWorkspace *ws = toolview_get_workspace( tview );\n\tTool *tool = TOOL( VOBJECT( tview )->iobject );\n\tToolkitview *kview = tview->kview;\n\n#ifdef DEBUG\n\tprintf( \"toolview_refresh: \" );\n\tiobject_print( VOBJECT( tview )->iobject );\n#endif /*DEBUG*/\n\n\tif( !toolview_quark ) \n\t\ttoolview_quark = \n\t\t\tg_quark_from_static_string( \"toolview_quark\" );\n\n\tDESTROY_GTK( tview->item );\n\n\tif( tool->toolitem ) \n\t\ttview->item = toolview_refresh_sub( tview, tool->toolitem, \n\t\t\tws, kview->menu );\n\n\tif( tview->item )\n\t\tgtk_signal_connect( GTK_OBJECT( tview->item ), \"destroy\",\n\t\t\tGTK_SIGNAL_FUNC( toolview_destroy_cb ), tview );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\ntoolview_link( View *view, Model *model, View *parent )\n{\n\tToolview *tview = TOOLVIEW( view );\n\tToolkitview *kview = TOOLKITVIEW( parent );\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n#ifdef DEBUG\n\tprintf( \"toolview_link: \" );\n\tiobject_print( VOBJECT( tview )->iobject );\n#endif /*DEBUG*/\n\n\ttview->kview = kview;\n}\n\nstatic void\ntoolview_class_init( ToolviewClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass*) class;\n\tGObjectClass *gobject_class = (GObjectClass*) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = toolview_destroy;\n\tgobject_class->finalize = toolview_finalize;\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = toolview_refresh;\n\n\tview_class->link = toolview_link;\n}\n\nstatic void\ntoolview_init( Toolview *toolview )\n{\n        toolview->item = NULL;\n}\n\nGtkType\ntoolview_get_type( void )\n{\n\tstatic GtkType toolview_type = 0;\n\n\tif( !toolview_type ) {\n\t\tstatic const GtkTypeInfo toolview_info = {\n\t\t\t\"Toolview\",\n\t\t\tsizeof( Toolview ),\n\t\t\tsizeof( ToolviewClass ),\n\t\t\t(GtkClassInitFunc) toolview_class_init,\n\t\t\t(GtkObjectInitFunc) toolview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttoolview_type = gtk_type_unique( TYPE_VIEW, &toolview_info );\n\t}\n\n\treturn( toolview_type );\n}\n\nView *\ntoolview_new( void )\n{\n\tToolview *tview = gtk_type_new( TYPE_TOOLVIEW );\n\n#ifdef DEBUG\n\tprintf( \"toolview_new: %p\\n\", tview );\n#endif /*DEBUG*/\n\n\treturn( VIEW( tview ) );\n}\n"
  },
  {
    "path": "src/toolview.h",
    "content": "/* View a tool as a menu item.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_TOOLVIEW (toolview_get_type())\n#define TOOLVIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_TOOLVIEW, Toolview ))\n#define TOOLVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_TOOLVIEW, ToolviewClass ))\n#define IS_TOOLVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_TOOLVIEW ))\n#define IS_TOOLVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_TOOLVIEW ))\n\n/* One of these for each top-level menu.\n */\nstruct _Toolview {\n\tView parent_class;\n\n\tToolkitview *kview;\n\n\tGtkWidget *item;\t/* Menu item we made for this tool */\n};\n\ntypedef struct _ToolviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} ToolviewClass;\n\nGtkType toolview_get_type( void );\nView *toolview_new( void );\n"
  },
  {
    "path": "src/trace.c",
    "content": "/* trace window\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* OR of the flags in all the trace windows.\n */\nTraceFlags trace_flags = (TraceFlags) 0;\n\nstatic LogClass *parent_class = NULL;\n\n/* All trace windows.\n */\nstatic GSList *trace_all = NULL;\n\n/* Trace buffer stack.\n */\nstatic VipsBuf trace_buffer_stack[SPINE_SIZE];\nstatic int trace_buffer_stack_p = 0;\n\n/* Number of active trace blocks.\n */\nstatic int trace_block_count = 0;\n\n/* All the trace menus we have.\n */\ntypedef struct _TraceTypeMenu {\n\tconst char *name;\n\tTraceFlags flag;\n} TraceTypeMenu;\n\n/* Map action names to trace flags for the radio menu.\n */\nstatic const TraceTypeMenu trace_types[] = {\n\t{ \"Operator\", TRACE_OPERATOR },\n\t{ \"Builtin\", TRACE_BUILTIN },\n\t{ \"Class\", TRACE_CLASS_NEW },\n\t{ \"VIPS\", TRACE_VIPS }\n};\n\nstatic TraceFlags\ntrace_get_trace_flag( GtkAction *action )\n{\n\tconst char *name = gtk_action_get_name( action );\n\n\tint i;\n\n\tfor( i = 0; i < IM_NUMBER( trace_types ); i++ )\n\t\tif( strcmp( name, trace_types[i].name ) == 0 )\n\t\t\treturn( trace_types[i].flag );\n\n\tg_assert( FALSE );\n\t\n\t/* Keep gcc happy.\n\t */\n\treturn( FALSE );\n}\n\nvoid\ntrace_block( void )\n{\n\ttrace_block_count += 1;\n}\n\nvoid\ntrace_unblock( void )\n{\n\ttrace_block_count -= 1;\n\n\tg_assert( trace_block_count >= 0 );\n}\n\nvoid\ntrace_reset( void )\n{\n\tint i;\n\n\tfor( i = 0; i < trace_buffer_stack_p; i++ )\n\t\tvips_buf_destroy( &trace_buffer_stack[i] );\n\n\ttrace_buffer_stack_p = 0;\n}\n\nvoid\ntrace_check( void )\n{\n\tg_assert( trace_buffer_stack_p == 0 );\n}\n\nVipsBuf *\ntrace_push( void )\n{\n\tint i;\n\n#ifdef DEBUG\n\tprintf( \"trace_push: %d\\n\", trace_buffer_stack_p );\n#endif \n\n\tif( trace_buffer_stack_p >= SPINE_SIZE ) {\n\t\terror_top( _( \"Overflow error.\" ) );\n\t\terror_sub( _( \"Trace buffer stack overflow.\" ) );\n\t\treduce_throw( reduce_context );\n\t}\n\n\ti = trace_buffer_stack_p++;\n\tvips_buf_init_dynamic( &trace_buffer_stack[i], MAX_TRACE );\n\n\treturn( &trace_buffer_stack[i] );\n}\n\nvoid\ntrace_pop( void )\n{\n\tint i;\n\n#ifdef DEBUG\n\tprintf( \"trace_pop: %d\\n\", trace_buffer_stack_p );\n#endif \n\n\tg_assert( trace_buffer_stack_p > 0 );\n\n\ti = --trace_buffer_stack_p;\n\tvips_buf_destroy( &trace_buffer_stack[i] );\n}\n\nVipsBuf *\ntrace_current( void )\n{\n\tg_assert( trace_buffer_stack_p > 0 );\n\n\treturn( &trace_buffer_stack[trace_buffer_stack_p - 1] );\n}\n\nint\ntrace_get_mark( void )\n{\n\treturn( trace_buffer_stack_p );\n}\n\nvoid\ntrace_pop_to( int n )\n{\n\tg_assert( n >= 0 && n <= trace_buffer_stack_p );\n\n\twhile( trace_buffer_stack_p > n ) \n\t\ttrace_pop();\n}\n\nstatic void *\ntrace_global_rethink_sub( Trace *trace )\n{\n\ttrace_flags |= trace->flags;\n\n\treturn( NULL );\n}\n\n/* Rethink the global trace_flags.\n */\nstatic void\ntrace_global_rethink( void )\n{\n\ttrace_flags = 0;\n\n\tslist_map( trace_all, (SListMapFn) trace_global_rethink_sub, NULL );\n}\n\nstatic void\ntrace_destroy( GtkObject *object )\n{\n\tTrace *trace;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_TRACE( object ) );\n\n\ttrace = TRACE( object );\n\n\t/* My instance destroy stuff.\n\t */\n\n\ttrace_all = g_slist_remove( trace_all, trace );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n\n\ttrace_global_rethink();\n}\n\nstatic void\ntrace_view_action_cb( GtkToggleAction *action, Trace *trace )\n{\n\tTraceFlags flag = trace_get_trace_flag( GTK_ACTION( action ) );\n\n\tif( gtk_toggle_action_get_active( action ) ) \n\t\ttrace->flags |= flag;\n\telse\n\t\ttrace->flags &= flag ^ ((TraceFlags) -1);\n\n\ttrace_global_rethink();\n}\n\n/* Our actions.\n */\nstatic GtkActionEntry trace_actions[] = {\n\t{ \"Clear\", \n\t\tNULL, N_( \"_Clear\" ), NULL, \n\t\tN_( \"Clear trace window\" ), \n\t\tG_CALLBACK( log_clear_action_cb ) }\n};\n\nstatic GtkToggleActionEntry trace_toggle_actions[] = {\n\t{ \"Operator\",\n\t\tNULL, N_( \"_Operators\" ), NULL,\n\t\tN_( \"trace operators\" ),\n\t\tG_CALLBACK( trace_view_action_cb ), FALSE },\n\n\t{ \"Builtin\",\n\t\tNULL, N_( \"_Builtin Functions\" ), NULL,\n\t\tN_( \"trace calls to built in functions\" ),\n\t\tG_CALLBACK( trace_view_action_cb ), FALSE },\n\n\t{ \"Class\",\n\t\tNULL, N_( \"_Class Construction\" ), NULL,\n\t\tN_( \"trace class constructors\" ),\n\t\tG_CALLBACK( trace_view_action_cb ), FALSE },\n\n\t{ \"VIPS\",\n\t\tNULL, N_( \"_VIPS Operations\" ), NULL,\n\t\tN_( \"trace calls to VIPS\" ),\n\t\tG_CALLBACK( trace_view_action_cb ), FALSE }\n};\n\nstatic const char *trace_menubar_ui_description =\n\"<ui>\"\n\"  <menubar name='TraceMenubar'>\"\n\"    <menu action='FileMenu'>\"\n\"      <menuitem action='Clear'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Close'/>\"\n\"    </menu>\"\n\"    <menu action='ViewMenu'>\"\n\"      <menuitem action='Operator'/>\"\n\"      <menuitem action='Builtin'/>\"\n\"      <menuitem action='Class'/>\"\n\"      <menuitem action='VIPS'/>\"\n\"    </menu>\"\n\"    <menu action='HelpMenu'>\"\n\"      <menuitem action='Guide'/>\"\n\"      <menuitem action='About'/>\"\n\"      <separator/>\"\n\"      <menuitem action='Homepage'/>\"\n\"    </menu>\"\n\"  </menubar>\"\n\"</ui>\";\n\nstatic void\ntrace_class_init( TraceClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tLogClass *log_class = (LogClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = trace_destroy;\n\n\tlog_class->actions = trace_actions;\n\tlog_class->n_actions = IM_NUMBER( trace_actions );\n\tlog_class->toggle_actions = trace_toggle_actions;\n\tlog_class->n_toggle_actions = IM_NUMBER( trace_toggle_actions );\n\tlog_class->action_name = \"TraceActions\";\n\tlog_class->ui_description = trace_menubar_ui_description;\n\tlog_class->menu_bar_name = \"/TraceMenubar\";\n}\n\nstatic void\ntrace_init( Trace *trace )\n{\n\ttrace->flags = 0;\n}\n\nGtkType\ntrace_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Trace\",\n\t\t\tsizeof( Trace ),\n\t\t\tsizeof( TraceClass ),\n\t\t\t(GtkClassInitFunc) trace_class_init,\n\t\t\t(GtkObjectInitFunc) trace_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_LOG, &info );\n\t}\n\n\treturn( type );\n}\n\nstatic void\ntrace_link( Trace *trace )\n{\n        iwindow_set_title( IWINDOW( trace ), _( \"Trace\" ) );\n\tgtk_window_set_default_size( GTK_WINDOW( trace ), 640, 480 );\n\tiwindow_set_size_prefs( IWINDOW( trace ), \n\t\t\"TRACE_WIDTH\", \"TRACE_HEIGHT\" );\n\tiwindow_build( IWINDOW( trace ) );\n\ttrace_all = g_slist_prepend( trace_all, trace );\n\n\tgtk_widget_show( GTK_WIDGET( trace ) ); \n}\n\nTrace *\ntrace_new( void )\n{\n\tTrace *trace = gtk_type_new( TYPE_TRACE );\n\n\ttrace_link( trace );\n\n\treturn( trace );\n}\n\nstatic void *\ntrace_text_sub( Trace *trace, const char *buf, TraceFlags flags )\n{\n\tif( !trace_block_count && trace->flags & flags ) \n\t\tlog_text( LOG( trace ), buf );\n\n\treturn( NULL );\n}\n\nvoid\ntrace_text( TraceFlags flags, const char *fmt, ... )\n{\n\tva_list ap;\n \tchar buf[MAX_STRSIZE];\n\n\tif( !(trace_flags & flags) )\n\t\treturn;\n\n        va_start( ap, fmt );\n        (void) im_vsnprintf( buf, MAX_STRSIZE, fmt, ap );\n        va_end( ap );\n\n\tslist_map2( trace_all, \n\t\t(SListMap2Fn) trace_text_sub, buf, (void *) flags );\n}\n\nvoid\ntrace_pelement( PElement *pe )\n{\n\tVipsBuf *buf = trace_current();\n\tHeap *heap = reduce_context->heap;\n\n\tgraph_pelement( heap, buf, pe, TRACE_FUNCTIONS );\n}\n\nvoid\ntrace_node( HeapNode *node )\n{\n\tElement e;\n\tPElement pe;\n\n\tPEPOINTE( &pe, &e );\n\tPEPUTP( &pe, ELEMENT_NODE, node );\n\ttrace_pelement( &pe );\n}\n\nvoid\ntrace_args( HeapNode **arg, int n )\n{\n\tVipsBuf *buf = trace_current();\n\tint i;\n\n\tfor( i = n - 1; i >= 0; i-- ) {\n\t\tPElement rhs;\n\n\t\tPEPOINTRIGHT( arg[i], &rhs );\n\t\ttrace_pelement( &rhs ); \n\t\tvips_buf_appends( buf, \" \" ); \n\t}\n\n\tvips_buf_appendf( buf, \"->\\n\" ); \n}\n\nvoid\ntrace_binop( Compile *compile, PElement *left, BinOp bop, PElement *right )\n{\n\tVipsBuf *buf = trace_current();\n\n\tvips_buf_appendf( buf, \"\\\"%s\\\" \", decode_BinOp( bop ) );\n\ttrace_pelement( left );\n\tvips_buf_appends( buf, \" \" );\n\ttrace_pelement( right );\n\tvips_buf_appends( buf, \" -> (\" );\n\tcompile_name( compile, buf );\n\tvips_buf_appends( buf, \")\\n\" );\n}\n\nvoid\ntrace_uop( UnOp uop, PElement *arg )\n{\n\tVipsBuf *buf = trace_current();\n\n\tvips_buf_appendf( buf, \"\\\"%s\\\" \", decode_UnOp( uop ) );\n\ttrace_pelement( arg );\n\tvips_buf_appends( buf, \" ->\\n\" ); \n}\n\nvoid\ntrace_result( TraceFlags flags, PElement *out )\n{\n\tVipsBuf *buf = trace_current();\n\n\tvips_buf_appendf( buf, \"    \" ); \n\ttrace_pelement( out );\n\tvips_buf_appends( buf, \"\\n\" ); \n\n\ttrace_text( flags, \"%s\", vips_buf_all( buf ) ); \n}\n"
  },
  {
    "path": "src/trace.h",
    "content": "/* Decls for trace.c ... a trace window\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_TRACE (trace_get_type())\n#define TRACE( obj ) (GTK_CHECK_CAST( (obj), TYPE_TRACE, Trace ))\n#define TRACE_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_TRACE, TraceClass ))\n#define IS_TRACE( obj ) (GTK_CHECK_TYPE( (obj), TYPE_TRACE ))\n#define IS_TRACE_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_TRACE ))\n\n/* The various things we can trace.\n */\ntypedef enum {\n\tTRACE_BUILTIN = 1,\t\t/* Calls to built in functions */\n\tTRACE_OPERATOR = 2,\t\t/* +, -, etc. */\n\tTRACE_CLASS_NEW = 4,\t\t/* Class construction */\n\tTRACE_VIPS = 8\t\t\t/* VIPS operations */\n} TraceFlags;\n\nstruct _Trace {\n\tLog parent_class;\n\n\tTraceFlags flags;\n};\n\ntypedef struct _TraceClass {\n\tLogClass parent_class;\n\n\t/* My methods.\n\t */\n} TraceClass;\n\nextern TraceFlags trace_flags;\n\nvoid trace_block( void );\nvoid trace_unblock( void );\n\nvoid trace_reset( void );\nvoid trace_check( void );\nVipsBuf *trace_push( void );\nvoid trace_pop( void );\nVipsBuf *trace_current( void );\nvoid trace_pop_to( int n );\nint trace_get_mark( void );\n\nGtkType trace_get_type( void );\nTrace *trace_new( void );\n\nvoid trace_text( TraceFlags flags, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\n\nvoid trace_pelement( PElement *pe );\nvoid trace_node( HeapNode *node );\nvoid trace_args( HeapNode **arg, int n );\nvoid trace_binop( Compile *compile, \n\tPElement *left, BinOp bop, PElement *right );\nvoid trace_uop( UnOp uop, PElement *arg );\nvoid trace_result( TraceFlags flags, PElement *out );\n\n"
  },
  {
    "path": "src/tree.c",
    "content": "/* Build parse trees.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* Free any stuff attached to a ParseConst.\n */\nvoid\ntree_const_destroy( ParseConst *pc )\n{\n\tif( pc->type == PARSE_CONST_STR ) \n\t\tIM_FREE( pc->val.str );\n\tpc->type = PARSE_CONST_NONE;\n}\n\nvoid\ntree_const_copy( ParseConst *from, ParseConst *to )\n{\n\t*to = *from;\n\tif( to->type == PARSE_CONST_STR && to->val.str )\n\t\tto->val.str = im_strdupn( to->val.str );\n}\n\n/* Free a parse node.\n */\nvoid *\ntree_node_destroy( ParseNode *n )\n{\n\tswitch( n->type ) {\n\tcase NODE_PATTERN_CLASS:\n\tcase NODE_TAG:\n\t\tIM_FREE( n->tag );\n\t\tbreak;\n\n\tcase NODE_CONST:\n\t\ttree_const_destroy( &n->con );\n\t\tbreak;\n\n\tcase NODE_LISTCONST:\n\tcase NODE_SUPER:\n\t\tIM_FREEF( g_slist_free, n->elist );\n\t\tbreak;\n\n\tcase NODE_APPLY:\n\tcase NODE_CLASS:\n\tcase NODE_BINOP:\n\tcase NODE_UOP:\n\tcase NODE_LEAF:\n\tcase NODE_GENERATOR:\n\tcase NODE_NONE:\n\tcase NODE_COMPOSE:\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\tIM_FREE( n );\n\n\treturn( NULL );\n}\n\n/* Make an empty parse node.\n */\nstatic ParseNode *\ntree_new( Compile *compile )\n{\n\tParseNode *no = INEW( NULL, ParseNode );\n\n\tno->compile = compile;\n\tno->type = NODE_NONE;\n\tno->biop = BI_NONE;\n\tno->uop = UN_NONE;\n\tno->arg1 = NULL;\n\tno->arg2 = NULL;\n\tno->arg3 = NULL;\n\tno->leaf = NULL;\n\tno->klass = NULL;\n\tno->elist = NULL;\n\tno->tag = NULL;\n\tno->con.type = PARSE_CONST_NONE;\n\tno->con.val.str = NULL;\n\n\tcompile->treefrag = g_slist_prepend( compile->treefrag, no );\n\n\treturn( no );\n}\n\n/* Make a binary operator node.\n */\nParseNode *\ntree_binop_new( Compile *compile, BinOp op, ParseNode *l, ParseNode *r )\n{\n\tParseNode *no = tree_new( compile );\n\n\tno->type = NODE_BINOP;\n\tno->biop = op;\n\tno->arg1 = l;\n\tno->arg2 = r;\n\n\treturn( no );\n}\n\n/* Make a function compose node.\n */\nParseNode *\ntree_compose_new( Compile *compile, ParseNode *f, ParseNode *g )\n{\n\tParseNode *no = tree_new( compile );\n\n\tno->type = NODE_COMPOSE;\n\tno->arg1 = f;\n\tno->arg2 = g;\n\n\treturn( no );\n}\n\n/* Make a generator node.\n */\nParseNode *\ntree_generator_new( Compile *compile, ParseNode *s, ParseNode *n, ParseNode *f )\n{\n\tParseNode *no = tree_new( compile );\n\n\tno->type = NODE_GENERATOR;\n\tno->arg1 = s;\n\tno->arg2 = n;\n\tno->arg3 = f;\n\n\treturn( no );\n}\n\n/* Make an IF node.\n */\nParseNode *\ntree_ifelse_new( Compile *compile, ParseNode *c, ParseNode *t, ParseNode *e )\n{\n\tParseNode *else_node = tree_lconst_new( compile, e );\n\tParseNode *then_node = tree_lconst_extend( compile, else_node, t );\n\tParseNode *if_node = tree_binop_new( compile, BI_IF, c, then_node );\n\n\treturn( if_node );\n}\n\n/* Make a class node.\n */\nParseNode *\ntree_class_new( Compile *compile )\n{\n\tParseNode *no = tree_new( compile );\n\tSymbol *this, *super, *name, *cons;\n\n\tg_assert( !compile->is_klass );\n\tg_assert( !compile->this );\n\tg_assert( !compile->super );\n\n\tno->type = NODE_CLASS;\n\tno->klass = compile;\n\n\t/* Make enclosing into a class.\n\t */\n\tcompile->is_klass = TRUE;\n\n\t/* Add builtin syms. \n\t */\n\tthis = symbol_new_defining( compile, MEMBER_THIS );\n\t(void) symbol_parameter_builtin_init( this );\n\tcompile->this = this;\n\n\tsuper = symbol_new_defining( compile, MEMBER_SUPER );\n\t(void) symbol_user_init( super );\n\t(void) compile_new_local( super->expr );\n\tsymbol_made( super );\n\tcompile->super = super;\n\n\tname = symbol_new_defining( compile, MEMBER_NAME );\n\t(void) symbol_parameter_builtin_init( name );\n\n\tcons = symbol_new_defining( compile, IOBJECT( compile->sym )->name );\n\t(void) symbol_user_init( cons );\n\t(void) compile_new_local( cons->expr );\n\tcons->expr->compile->tree = tree_leafsym_new( compile, compile->sym );\n\tsymbol_made( cons );\n\n\treturn( no );\n}\n\n/* Make a tag node.\n */\nParseNode *\ntree_tag_new( Compile *compile, const char *r )\n{\t\n\tParseNode *no = tree_new( compile );\n\n\tno->type = NODE_TAG;\n\tno->tag = im_strdupn( r );\n\n\treturn( no );\n}\n\n/* Make a unary operator node.\n */\nParseNode *\ntree_unop_new( Compile *compile, UnOp op, ParseNode *a )\n{\n\tParseNode *no = tree_new( compile );\n\n\tno->type = NODE_UOP;\n\tno->uop = op;\n\tno->arg1 = a;\n\n\treturn( no );\n}\n\nParseNode *\ntree_leaf_new( Compile *compile, const char *name )\n{\n\tParseNode *no = tree_new( compile );\n\n\tno->type = NODE_LEAF;\n\tno->leaf = symbol_new_reference( compile, name );\n\n\t/* Have we a reference to a ZOMBIE? If yes, we may need to patch this\n\t * leaf to point to a new symbol. Add the leaf's pointer to the\n\t * refedat list on the ZOMBIE.\n\t */\n\tif( no->leaf->type == SYM_ZOMBIE )\n\t\t(void) symbol_patch_add( (void **) &no->leaf, no->leaf );\n\n\treturn( no );\n}\n\n/* Make a new leaf node ... except we know the final symbol now. \n */\nParseNode *\ntree_leafsym_new( Compile *compile, Symbol *sym )\n{\n\tParseNode *no = tree_new( compile );\n\n\t/* Fill fields.\n\t */\n\tno->type = NODE_LEAF;\n\tno->leaf = sym;\n\n\t/* Note that this compile refs this sym.\n\t */\n\tcompile_link_make( compile, sym );\n\n\t/* Have we a reference to a ZOMBIE? If yes, we may need to patch this\n\t * leaf to point to a new symbol. Add the leaf's pointer to the\n\t * refedat list on the ZOMBIE.\n\t */\n\tif( sym->type == SYM_ZOMBIE )\n\t\t(void) symbol_patch_add( (void **) &no->leaf, sym );\n\n\treturn( no );\n}\n\n/* Init a clist.\n */\nParseNode *\ntree_lconst_new( Compile *compile, ParseNode *a )\n{\n\tParseNode *no = tree_new( compile );\n\n\t/* Fill fields.\n\t */\n\tno->type = NODE_LISTCONST;\n\tno->elist = NULL;\n\n\tno->elist = g_slist_prepend( no->elist, a );\n\n\treturn( no );\n}\n\n/* Extend a clist.\n */\nParseNode *\ntree_lconst_extend( Compile *compile, ParseNode *base, ParseNode *new )\n{\n\tg_assert( base->type == NODE_LISTCONST );\n\n\tbase->elist = g_slist_prepend( base->elist, new );\n\n\treturn( base );\n}\n\n/* Init a super.\n */\nParseNode *\ntree_super_new( Compile *compile )\n{\n\tParseNode *no = tree_new( compile );\n\n\tno->type = NODE_SUPER;\n\n\treturn( no );\n}\n\n/* Extend a super.\n */\nParseNode *\ntree_super_extend( Compile *compile, ParseNode *base, ParseNode *new )\n{\n\tg_assert( base->type == NODE_SUPER );\n\n\tbase->elist = g_slist_append( base->elist, new );\n\n\treturn( base );\n}\n\n/* Make a new constant node. \n */\nParseNode *\ntree_const_new( Compile *compile, ParseConst n )\n{\n\tParseNode *no = tree_new( compile );\n\n\tno->type = NODE_CONST;\n\tno->con = n;\n\n\treturn( no );\n}\n\n/* Make a new apply node. \n */\nParseNode *\ntree_appl_new( Compile *compile, ParseNode *l, ParseNode *r )\n{\t\n\tParseNode *no = tree_new( compile );\n\n\tno->type = NODE_APPLY;\n\tno->arg1 = l;\n\tno->arg2 = r;\n\n\treturn( no );\n}\n\nParseNode *\ntree_pattern_class_new( Compile *compile, const char *class_name, ParseNode *l )\n{\n\tParseNode *no = tree_new( compile );\n\n\tno->type = NODE_PATTERN_CLASS;\n\tno->arg1 = l;\n\tno->tag = im_strdupn( class_name );\n\n\treturn( no );\n}\n\nParseNode *\ntree_map( Compile *compile, tree_map_fn fn, ParseNode *node, void *a, void *b ) \n{\n\tParseNode *result;\n\tGSList *l;\n\n\tg_assert( node );\n\n\tif( (result = fn( compile, node, a, b )) )\n\t\treturn( result );\n\n\tswitch( node->type ) {\n\tcase NODE_GENERATOR:\n\t\tif( (result = tree_map( compile, fn, node->arg1, a, b )) )\n\t\t\treturn( result );\n\t\tif( node->arg2 &&\n\t\t\t(result = tree_map( compile, fn, node->arg2, a, b )) )\n\t\t\treturn( result );\n\t\tif( node->arg3 &&\n\t\t\t(result = tree_map( compile, fn, node->arg3, a, b )) )\n\t\t\treturn( result );\n\t\tbreak;\n\n\tcase NODE_APPLY:\n\tcase NODE_BINOP:\n\tcase NODE_COMPOSE:\n\t\tif( (result = tree_map( compile, fn, node->arg1, a, b )) ||\n\t\t\t(result = tree_map( compile, fn, node->arg2, a, b )) )\n\t\t\treturn( result );\n\t\tbreak;\n\n\tcase NODE_UOP:\n\t\tif( (result = tree_map( compile, fn, node->arg1, a, b )) )\n\t\t\treturn( result );\n\t\tbreak;\n\n\tcase NODE_SUPER:\n\tcase NODE_LISTCONST:\n\t\tfor( l = node->elist; l; l = l->next ) {\n\t\t\tParseNode *arg = (ParseNode *) l->data;\n\n\t\t\tif( (result = tree_map( compile, fn, arg, a, b )) )\n\t\t\t\treturn( result );\n\t\t}\n\t\tbreak;\n\n\tcase NODE_LEAF:\n\tcase NODE_CLASS:\n\tcase NODE_TAG:\n\tcase NODE_CONST:\n\t\tbreak;\n\n\tcase NODE_NONE:\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( NULL );\n}\n\n/* Copy a tree to a new context. Make all symbols afresh ... you need to link\n * after calling this. \n */\nParseNode *\ntree_copy( Compile *compile, ParseNode *node )\n{\n\tParseNode *copy;\n\tGSList *l;\n\n\tg_assert( node );\n\n\tswitch( node->type ) {\n\tcase NODE_GENERATOR:\n\tcase NODE_APPLY:\n\tcase NODE_BINOP:\n\tcase NODE_COMPOSE:\n\tcase NODE_UOP:\n\tcase NODE_TAG:\n\tcase NODE_CONST:\n\tcase NODE_PATTERN_CLASS:\n\t\tcopy = tree_new( compile );\n\t\tcopy->type = node->type;\n\t\tcopy->uop = node->uop;\n\t\tcopy->biop = node->biop;\n\t\tif( node->tag )\n\t\t\tcopy->tag = im_strdupn( node->tag );\n\t\ttree_const_copy( &node->con, &copy->con );\n\t\tif( node->arg1 )\n\t\t\tcopy->arg1 = tree_copy( compile, node->arg1 );\n\t\tif( node->arg2 )\n\t\t\tcopy->arg2 = tree_copy( compile, node->arg2 );\n\t\tif( node->arg3 )\n\t\t\tcopy->arg3 = tree_copy( compile, node->arg3 );\n\t\tbreak;\n\n\tcase NODE_SUPER:\n\tcase NODE_LISTCONST:\n\t\tcopy = tree_new( compile );\n\t\tfor( l = node->elist; l; l = l->next ) {\n\t\t\tParseNode *arg = (ParseNode *) l->data;\n\n\t\t\tcopy->elist = g_slist_append( copy->elist, \n\t\t\t\ttree_copy( compile, arg ) );\n\t\t}\n\t\tcopy->type = node->type;\n\t\tbreak;\n\n\tcase NODE_CLASS:\n\t\tcopy = tree_class_new( compile );\n\t\tbreak;\n\n\tcase NODE_LEAF:\n\t\tcopy = tree_leaf_new( compile, IOBJECT( node->leaf )->name );\n\t\tbreak;\n\n\tcase NODE_NONE:\n\tdefault:\n\t\tcopy = NULL; \n\t\tg_assert( FALSE );\n\t}\n\n\treturn( copy );\n}\n\n"
  },
  {
    "path": "src/tree.h",
    "content": "/* Declarations for the tree builder.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* The kinds of nodes we can have in a parse tree. \n */\ntypedef enum {\n\tNODE_NONE,\t\t/* Empty */\n\tNODE_APPLY,\t\t/* A function application */\n\tNODE_BINOP,\t\t/* A binary operator */\n\tNODE_UOP,\t\t/* A unary operator */\n\tNODE_LEAF,\t\t/* A leaf .. a symbol of some sort */\n\tNODE_CLASS,\t\t/* A class */\n\tNODE_TAG,\t\t/* A tag .. rhs of '.' */\n\tNODE_CONST,\t\t/* A constant */\n\tNODE_GENERATOR,\t\t/* A list generator */\n\tNODE_COMPOSE,\t\t/* Function composition */\n\tNODE_SUPER,\t\t/* Superclass constructor */\n\tNODE_PATTERN_CLASS,\t/* A class pattern match */\n\tNODE_LISTCONST\t\t/* A list expression \"[1, 2, 3]\" */\n} NodeTypes;\n\n/* Binary operators.\n\n\tOrder important! Keep changes in step with operator_table[] in\n\taction.c\n\n */\ntypedef enum {\n\tBI_NONE = 0,\t\t/* Nothing */\n\tBI_ADD,\t\t\t/* Addition and subtraction */\n\tBI_SUB,\n\tBI_REM,\t\t\t/* Remainder after division */\n\tBI_POW,\t\t\t/* Raise to power */\n\tBI_SELECT,\t\t/* Select a channel/subscript */\n\tBI_LSHIFT,\t\t/* Shift left */\n\tBI_RSHIFT,\t\t/* Shift right */\n\tBI_DIV,\t\t\t/* Divide by a constant */\n\tBI_JOIN,\t\t/* Join of two objects */\n\tBI_DOT,\t\t\t/* Projection operator */\n\tBI_COMMA,\t\t/* Form complex number */\n\tBI_MUL,\t\t\t/* Mult by a constant */\n\tBI_LAND,\t\t/* Logical and */\n\tBI_LOR,\t\t\t/* Logical or */\n\tBI_BAND,\t\t/* Bitwise and */\n\tBI_BOR,\t\t\t/* Bitwise or */\n\tBI_EOR,\t\t\t/* Either - or */\n\tBI_EQ,\t\t\t/* Equality */\n\tBI_NOTEQ,\n\tBI_PEQ,\t\t\t/* Pointer equality */\n\tBI_PNOTEQ,\n\tBI_LESS,\t\t/* Relational ops */\n\tBI_LESSEQ,\n\tBI_MORE,\t\t\n\tBI_MOREEQ,\n\tBI_IF,\t\t\t/* if-then-else */\n\tBI_CONS\t\t\t/* List cons ... has to be last, see below */\n} BinOp;\n\n/* Unary operators.\n\n\tOrder important! Keep changes in step with operator_table[] in\n\taction.c\n\n */\ntypedef enum {\n\tUN_NONE = BI_CONS + 1,\t/* Nothing */\n\tUN_CSCHAR,\t\t/* Convert to signed char */\n\tUN_CUCHAR,\t\t/* Convert to unsigned char */\n\tUN_CSSHORT,\t\t/* Convert to signed short */\n\tUN_CUSHORT,\t\t/* Convert to unsigned short */\n\tUN_CSINT,\t\t/* Convert to signed int */\n\tUN_CUINT,\t\t/* Convert to unsigned int */\n\tUN_CFLOAT,\t\t/* Convert to signed float */\n\tUN_CDOUBLE,\t\t/* Convert to signed double */\n\tUN_CCOMPLEX,\t\t/* Convert to complex */\n\tUN_CDCOMPLEX,\t\t/* Convert to double complex */\n\tUN_MINUS,\t\t/* Unary minus */\n\tUN_NEG,\t\t\t/* Logical negation, \"!\" */\n\tUN_COMPLEMENT,\t\t/* 1s complement, \"~\" */\n\tUN_PLUS,\t\t/* Unary plus */\n\tUN_LAST\t\t\t/* Sanity check with this */\n} UnOp;\n\n/* The sorts of constants we can have in expressions. \n */\ntypedef enum {\n\tPARSE_CONST_NONE,\n\tPARSE_CONST_STR,\n\tPARSE_CONST_BOOL,\n\tPARSE_CONST_NUM,\n\tPARSE_CONST_COMPLEX,\t\t/* Eg. 12j == (0, 12) */\n\tPARSE_CONST_CHAR,\n\tPARSE_CONST_ELIST\t\t/* Empty list [] */\n} ParseConstTypes;\n\n/* Constants in expressions. \n */\nstruct _ParseConst {\n\tParseConstTypes type;\n\tunion {\n\t\tdouble num;\n\t\tchar *str;\n\t\tgboolean bol;\n\t\tint ch;\n\t} val;\n};\n\n/* A parse tree node.\n */\nstruct _ParseNode {\n\t/* Compiled in here.\n\t */\n\tCompile *compile;\n\n\tNodeTypes type;\n\n\t/* Bundle for node types with up to two arguments.\n\t */\n\tBinOp biop;\n\tUnOp uop;\n\tParseNode *arg1;\n\tParseNode *arg2;\n\n\t/* Just for generators, eg. [a, b .. c]\n\t */\n\tParseNode *arg3;\n\n\t/* A symbol reference.\n\t */\n\tSymbol *leaf;\n\n\t/* A class.\n\t */\n\tCompile *klass;\n\n\t/* Expression list ... super constructor plus args, or list constant.\n\t */\n\tGSList *elist;\n\n\t/* A tag.\n\t */\n\tchar *tag;\n\n\t/* A constant.\n\t */\n\tParseConst con;\n};\n\nvoid tree_const_destroy( ParseConst *pc );\n\nParseNode *tree_binop_new( Compile *compile, \n\tBinOp op, ParseNode *l, ParseNode *r );\nParseNode *tree_generator_new( Compile *compile, \n\tParseNode *s, ParseNode *i, ParseNode *f );\nParseNode *tree_lconst_new( Compile *compile, ParseNode *s );\nParseNode *tree_lconst_extend( Compile *compile, ParseNode *s, ParseNode *n );\nParseNode *tree_super_new( Compile *compile );\nParseNode *tree_super_extend( Compile *compile, ParseNode *base, ParseNode *n );\nParseNode *tree_ifelse_new( Compile *compile, \n\tParseNode *c, ParseNode *t, ParseNode *e );\nParseNode *tree_appl_new( Compile *compile, ParseNode *l, ParseNode *r );\nParseNode *tree_tag_new( Compile *compile, const char *r );\nParseNode *tree_unop_new( Compile *compile, UnOp op, ParseNode *a );\nParseNode *tree_leaf_new( Compile *compile, const char *name );\nParseNode *tree_leafsym_new( Compile *compile, Symbol *sym );\nParseNode *tree_const_new( Compile *compile, ParseConst n );\nParseNode *tree_class_new( Compile *compile );\nParseNode *tree_compose_new( Compile *compile, ParseNode *f, ParseNode *g );\nParseNode *tree_pattern_new( Compile *compile );\nParseNode *tree_pattern_class_new( Compile *compile, \n\tconst char *class_name, ParseNode *l );\n\nvoid *tree_node_destroy( ParseNode *n );\n\ntypedef ParseNode *(*tree_map_fn)( Compile *, ParseNode *, void *, void * );\nParseNode *tree_map( Compile *compile, \n\ttree_map_fn fn, ParseNode *node, void *a, void *b );\n\n/* Copy a tree into a new context.\n */\nParseNode *tree_copy( Compile *compile, ParseNode *node );\n"
  },
  {
    "path": "src/tslider.c",
    "content": "/* a slider with an entry widget\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\n/* Our signals. \n */\nenum {\n\tCHANGED,\t\t\n\tACTIVATE,\t\n\tSLIDER_CHANGED,\n\tTEXT_CHANGED,\t\n\tLAST_SIGNAL\n};\n\nstatic GtkHBoxClass *parent_class = NULL;\n\nstatic guint tslider_signals[LAST_SIGNAL] = { 0 };\n\n/* Are two doubles more or less equal. We need this when we check the sliders\n * for update to stop loops. The 0.0001 is a bit of a fudge :-(\n */\n#define DEQ( A, B ) (ABS((A) - (B)) < 0.0001)\n\nstatic void\ntslider_destroy( GtkObject *object )\n{\n\tTslider *tslider;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_TSLIDER( object ) );\n\n\ttslider = TSLIDER( object );\n\n#ifdef DEBUG\n\tprintf( \"tslider_destroy: %p\\n\", tslider );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\tif( tslider->adj ) {\n\t\tgtk_signal_disconnect_by_data( GTK_OBJECT( tslider->adj ),\n\t\t\t(gpointer) tslider );\n\t\ttslider->adj = NULL;\n\t}\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\n/* Map a value to a slider position.\n */\nstatic double\ntslider_value_to_slider( Tslider *tslider, double value )\n{\n\t/* Map our range to 0-1.\n\t */\n\tconst double scale = 1.0 / (tslider->to - tslider->from);\n\tconst double to01 = (value - tslider->from) * scale;\n\n\t/* Pass through user fn.\n\t */\n\tconst double mapped = tslider->value_to_slider( \n\t\ttslider->from, tslider->to, to01 );\n\tconst double nvalue = mapped / scale + tslider->from;\n\n#ifdef DEBUG\n\tprintf( \"tslider_value_to_slider: %g, to %g\\n\", value, nvalue );\n#endif /*DEBUG*/\n\n\t/* Map back to main range.\n\t */\n\treturn( nvalue );\n}\n\n/* Map a slider position to a value.\n */\nstatic double\ntslider_slider_to_value( Tslider *tslider, double value )\n{\n\t/* Map our range to 0-1.\n\t */\n\tconst double scale = 1.0 / (tslider->to - tslider->from);\n\tconst double to01 = (value - tslider->from) * scale;\n\n\t/* Pass through user fn.\n\t */\n\tconst double mapped = tslider->slider_to_value( \n\t\ttslider->from, tslider->to, to01 );\n\tconst double nvalue = mapped / scale + tslider->from;\n\n#ifdef DEBUG\n\tprintf( \"tslider_slider_to_value: %g, to %g\\n\", value, nvalue );\n#endif /*DEBUG*/\n\n\t/* Map back to main range.\n\t */\n\treturn( nvalue );\n}\n\n/* from/to/value have changed ... update the widgets.\n */\nstatic void\ntslider_real_changed( Tslider *tslider )\n{\n\tGtkAdjustment *adj = tslider->adj;\n\tGtkWidget *entry = tslider->entry;\n\n#ifdef DEBUG\n\tprintf( \"tslider_real_changed: %p, val = %g\\n\", \n\t\ttslider, tslider->value );\n#endif /*DEBUG*/\n\n\tif( tslider->auto_link ) \n\t\ttslider->svalue = tslider_value_to_slider( tslider, \n\t\t\ttslider->value );\n\n\tgtk_signal_handler_block_by_data( GTK_OBJECT( adj ), tslider );\n\tgtk_signal_handler_block_by_data( GTK_OBJECT( entry ), tslider );\n\n\t/* Some libc's hate out-of-bounds precision, so clip, just in case.\n\t */\n\tset_gentry( tslider->entry, \"%.*f\", \n\t\tIM_CLIP( 0, tslider->digits, 100 ), tslider->value );\n\tgtk_scale_set_digits( GTK_SCALE( tslider->slider ), tslider->digits );\n\n\tif( !DEQ( tslider->from, tslider->last_from ) || \n\t\t!DEQ( tslider->to, tslider->last_to ) ) {\n\t\tdouble range = tslider->to - tslider->from;\n\n\t\tadj->step_increment = range / 100;\n\t\tadj->page_increment = range / 10;\n\t\tadj->page_size = range / 10;\n\n\t\tadj->lower = tslider->from;\n\t\tadj->upper = tslider->to + adj->page_size;\n\n\t\ttslider->last_to = tslider->to;\n\t\ttslider->last_from = tslider->from;\n\n\t\tgtk_adjustment_changed( adj );\n\t}\n\n\tif( !DEQ( tslider->svalue, tslider->last_svalue ) ) {\n\t\tadj->value = tslider->svalue;\n\t\ttslider->last_svalue = tslider->svalue;\n\n\t\tgtk_adjustment_value_changed( adj );\n\t}\n\n\tgtk_signal_handler_unblock_by_data( GTK_OBJECT( adj ), tslider );\n\tgtk_signal_handler_unblock_by_data( GTK_OBJECT( entry ), tslider );\n}\n\nstatic void\ntslider_class_init( TsliderClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = tslider_destroy;\n\n\tclass->changed = tslider_real_changed;\n\tclass->slider_changed = NULL;\n\tclass->activate = NULL;\n\n\t/* Create signals.\n\t */\n\ttslider_signals[CHANGED] = g_signal_new( \"changed\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( TsliderClass, changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\ttslider_signals[ACTIVATE] = g_signal_new( \"activate\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( TsliderClass, activate ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\ttslider_signals[SLIDER_CHANGED] = g_signal_new( \"slider_changed\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( TsliderClass, slider_changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\ttslider_signals[TEXT_CHANGED] = g_signal_new( \"text_changed\",\n\t\tG_OBJECT_CLASS_TYPE( gobject_class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( TsliderClass, text_changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__VOID,\n\t\tG_TYPE_NONE, 0 );\n\n\t/* Init methods.\n\t */\n}\n\n/* From/to/value have changed ... tell everyone.\n */\nvoid\ntslider_changed( Tslider *tslider )\n{\n#ifdef DEBUG\n\tprintf( \"tslider_changed\\n\" );\n#endif /*DEBUG*/\n\n\tg_signal_emit( G_OBJECT( tslider ), tslider_signals[CHANGED], 0 );\n}\n\n/* Activated!\n */\nstatic void\ntslider_activate( Tslider *tslider )\n{\n#ifdef DEBUG\n\tprintf( \"tslider_activate\\n\" );\n#endif /*DEBUG*/\n\n\tg_signal_emit( G_OBJECT( tslider ), tslider_signals[ACTIVATE], 0 );\n}\n\n/* Just the slider changed.\n */\nstatic void\ntslider_slider_changed( Tslider *tslider )\n{\n#ifdef DEBUG\n\tprintf( \"tslider_slider_changed\\n\" );\n#endif /*DEBUG*/\n\n\tg_signal_emit( G_OBJECT( tslider ), \n\t\ttslider_signals[SLIDER_CHANGED], 0 );\n}\n\n/* Text has been touched.\n */\nstatic void\ntslider_text_changed( Tslider *tslider )\n{\n#ifdef DEBUG\n\tprintf( \"tslider_text_changed\\n\" );\n#endif /*DEBUG*/\n\n\tg_signal_emit( G_OBJECT( tslider ), tslider_signals[TEXT_CHANGED], 0 );\n}\n\n/* Enter in entry widget\n */\nstatic void\ntslider_value_activate_cb( GtkWidget *entry, Tslider *tslider )\n{\n\tdouble value;\n\n\tif( !get_geditable_double( entry, &value ) ) {\n\t\tiwindow_alert( entry, GTK_MESSAGE_ERROR );\n\t\treturn;\n\t}\n\n\tif( tslider->value != value ) {\n\t\ttslider->value = value;\n\n\t\tif( tslider->auto_link ) \n\t\t\ttslider_changed( tslider );\n\t\telse\n\t\t\ttslider_activate( tslider );\n\t}\n}\n\n/* Drag on slider.\n */\nstatic void\ntslider_value_changed_cb( GtkAdjustment *adj, Tslider *tslider )\n{\n#ifdef DEBUG\n\tprintf( \"tslider_value_changed_cb\\n\" );\n#endif /*DEBUG*/\n\n\tif( tslider->svalue != adj->value ) {\n\t\ttslider->svalue = adj->value;\n\n\t\tif( tslider->auto_link ) {\n\t\t\ttslider->value = \n\t\t\t\ttslider_slider_to_value( tslider, adj->value );\n\n\t\t\ttslider_changed( tslider );\n\t\t}\n\t\telse \n\t\t\ttslider_slider_changed( tslider );\n\t}\n}\n\n/* Text has changed (and may need to be scanned later).\n */\nstatic void\ntslider_text_changed_cb( GtkWidget *widget, Tslider *tslider )\n{\n#ifdef DEBUG\n\tprintf( \"tslider_text_changed_cb\\n\" );\n#endif /*DEBUG*/\n\n\ttslider_text_changed( tslider );\n}\n\n/* Default identity conversion.\n */\nstatic double\ntslider_conversion_id( double from, double to, double value )\n{\n\treturn( value );\n}\n\nstatic gboolean\ntslider_scroll_cb( GtkWidget *wid, GdkEvent *event, Tslider *tslider )\n{\n\tgboolean handled;\n\n\thandled = FALSE;\n\n\t/* Stop any other scroll handlers running. We don't want the scroll \n\t * wheel to change widgets while we're moving.\n\t */\n\tif( tslider->ignore_scroll )\n\t\thandled = TRUE;\n\n\treturn( handled ); \n}\n\nstatic void\ntslider_init( Tslider *tslider )\n{\n#ifdef DEBUG\n\tprintf( \"tslider_init: %p\\n\", tslider );\n#endif /*DEBUG*/\n\n\t/* Any old start values ... overridden later.\n\t */\n\ttslider->from = -1;\n\ttslider->to = -1;\n\ttslider->value = -1;\n\ttslider->svalue = -1;\n\ttslider->digits = -1;\n\ttslider->last_to = -1;\n\ttslider->last_from = -1;\n\ttslider->last_svalue = -1;\n\ttslider->ignore_scroll = TRUE;\n\n        gtk_box_set_spacing( GTK_BOX( tslider ), 2 );\n\n\ttslider->entry = build_entry( 5 );\n\tgtk_entry_set_max_length( GTK_ENTRY( tslider->entry ), 10 );\n        set_tooltip( tslider->entry, _( \"Slider value ... edit!\" ) );\n        gtk_box_pack_start( GTK_BOX( tslider ), \n\t\ttslider->entry, FALSE, FALSE, 0 );\n        gtk_signal_connect( GTK_OBJECT( tslider->entry ), \"activate\",\n                GTK_SIGNAL_FUNC( tslider_value_activate_cb ), tslider );\n        gtk_signal_connect( GTK_OBJECT( tslider->entry ), \"changed\",\n                GTK_SIGNAL_FUNC( tslider_text_changed_cb ), tslider );\n\tgtk_widget_show( tslider->entry );\n\n        tslider->slider = gtk_hscale_new( NULL );\n\ttslider->adj = gtk_range_get_adjustment( GTK_RANGE( tslider->slider ) );\n        gtk_range_set_update_policy( GTK_RANGE( tslider->slider ),\n\t\tGTK_UPDATE_CONTINUOUS );\n#ifdef DEBUG\n        gtk_range_set_update_policy( GTK_RANGE( tslider->slider ),\n\t\tGTK_UPDATE_DISCONTINUOUS );\n#endif /*DEBUG*/\n        gtk_scale_set_draw_value( GTK_SCALE( tslider->slider ), FALSE );\n\tgtk_widget_set_size_request( GTK_WIDGET( tslider->slider ), 100, -1 );\n        gtk_box_pack_start( GTK_BOX( tslider ), \n\t\ttslider->slider, TRUE, TRUE, 0 );\n        set_tooltip( tslider->slider, _( \"Left-drag to set number\" ) );\n        gtk_signal_connect( GTK_OBJECT( tslider->adj ), \"value_changed\", \n\t\tGTK_SIGNAL_FUNC( tslider_value_changed_cb ), tslider );\n\tg_signal_connect( tslider->slider, \"scroll-event\", \n\t\tG_CALLBACK( tslider_scroll_cb ), tslider );\n\tgtk_widget_show( tslider->slider );\n\n\ttslider->auto_link = TRUE;\n\ttslider->slider_to_value = tslider_conversion_id;\n\ttslider->value_to_slider = tslider_conversion_id;\n}\n\nGtkType\ntslider_get_type( void )\n{\n\tstatic GtkType tslider_type = 0;\n\n\tif( !tslider_type ) {\n\t\tstatic const GtkTypeInfo sinfo = {\n\t\t\t\"Tslider\",\n\t\t\tsizeof( Tslider ),\n\t\t\tsizeof( TsliderClass ),\n\t\t\t(GtkClassInitFunc) tslider_class_init,\n\t\t\t(GtkObjectInitFunc) tslider_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttslider_type = gtk_type_unique( GTK_TYPE_HBOX, &sinfo );\n\t}\n\n\treturn( tslider_type );\n}\n\nTslider *\ntslider_new()\n{\n\tTslider *tslider = gtk_type_new( TYPE_TSLIDER );\n\n\treturn( tslider );\n}\n\nvoid\ntslider_set_conversions( Tslider *tslider, \n\ttslider_fn value_to_slider, tslider_fn slider_to_value )\n{\n\ttslider->value_to_slider = value_to_slider;\n\ttslider->slider_to_value = slider_to_value;\n\n\ttslider->auto_link = value_to_slider && slider_to_value;\n}\n\ndouble\ntslider_log_value_to_slider( double from, double to, double value )\n{\n\t/* What does 1.0 map to on our [0,1] scale?\n\t */\n\tconst double mapped1 = (1.0 - from) / (to - from);\n\n\t/* We want an exponent which maps the mid point on the slider to 1.\n\t */\n\tconst double a = log( mapped1 ) / log( 0.5 );\n\n\tconst double nvalue = pow( value, 1.0 / a );\n\n\treturn( nvalue );\n}\n\ndouble\ntslider_log_slider_to_value( double from, double to, double value )\n{\n\t/* What does 1.0 map to on our [0,1] scale?\n\t */\n\tconst double mapped1 = (1.0 - from) / (to - from);\n\n\t/* We want an exponent which maps the mid point on the slider to 1.\n\t */\n\tconst double a = log( mapped1 ) / log( 0.5 );\n\n\tconst double nvalue = pow( value, a );\n\n\treturn( nvalue );\n}\n\nvoid\ntslider_set_ignore_scroll( Tslider *tslider, gboolean ignore_scroll )\n{\n\ttslider->ignore_scroll = ignore_scroll;\n}\n"
  },
  {
    "path": "src/tslider.h",
    "content": "/* A slider with an entry widget.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_TSLIDER (tslider_get_type())\n#define TSLIDER( obj ) (GTK_CHECK_CAST( (obj), TYPE_TSLIDER, Tslider ))\n#define TSLIDER_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_TSLIDER, TsliderClass ))\n#define IS_TSLIDER( obj ) (GTK_CHECK_TYPE( (obj), TYPE_TSLIDER ))\n#define IS_TSLIDER_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_TSLIDER ))\n\ntypedef double (*tslider_fn)( double from, double to, double value );\n\ntypedef struct _Tslider {\n\tGtkHBox parent_class;\n\n\t/* Our state.\n\t */\n\tdouble from;\n\tdouble to;\n\n\tdouble value;\t\t/* Real value, as displayed in text */\n\tdouble svalue;\t\t/* Slider value ... secret linear scale */\n\tint digits;\t\t/* How many sf to display */\n\n\t/* Keep last from/to/value settings here. Can't\n\t * use from/to since double and float don't compare reliably.\n\t */\n\tdouble last_from, last_to, last_svalue;\n\n\tGtkWidget *entry;\n\tGtkWidget *slider;\n\tGtkAdjustment *adj;\n\n\t/* Optional functions ... how to make a value from a slider\n\t * position, how to make a slider position from a value.\n\t * If these are defined, text and slider are linked for you.\n\t */\n\tgboolean auto_link;\n\ttslider_fn value_to_slider;\n\ttslider_fn slider_to_value;\n\n\t/* Ignore scroll events. In workspaces, we want the scroll-wheel to\n\t * just scroll the workspace and not adjust sliders. \n\t */\n\tgboolean ignore_scroll;\n} Tslider;\n\ntypedef struct _TsliderClass {\n\tGtkHBoxClass parent_class;\n\n\tvoid (*changed)( Tslider * );\t\t/* from/to/value change */\n\tvoid (*activate)( Tslider * );\t\t/* enter in text */\n\tvoid (*slider_changed)( Tslider * );\t/* slider drag */\n\tvoid (*text_changed)( Tslider * );\t/* text has been touched */\n} TsliderClass;\n\nvoid tslider_changed( Tslider * );\n\nGtkType tslider_get_type( void );\nTslider *tslider_new( void );\n\nvoid tslider_set_conversions( Tslider *tslider, \n\ttslider_fn value_to_slider, tslider_fn slider_to_value );\ndouble tslider_log_value_to_slider( double from, double to, double value );\ndouble tslider_log_slider_to_value( double from, double to, double value );\n\nvoid tslider_set_ignore_scroll( Tslider *tslider, gboolean ignore_scroll );\n"
  },
  {
    "path": "src/util.c",
    "content": "/* Some basic util functions.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n/* Handy for tracing errors.\n#define DEBUG_ERROR\n */\n\n/* Prettyprint xml save files.\n\n \tFIXME ... slight mem leak, and save files are much larger ... but\n\tleave it on for convenience\n\n */\n#define DEBUG_SAVEFILE\n\n#include \"ip.h\"\n\n/* Track errors messages in this thing. We keep two messages: a principal\n * error, and extra informative text. For example \"Unable to load file.\",\n * \"Read failed for file blah, permission denied.\".\n */\nstatic char error_top_text[MAX_STRSIZE];\nstatic char error_sub_text[MAX_STRSIZE];\n\nVipsBuf error_top_buf = VIPS_BUF_STATIC( error_top_text );\nVipsBuf error_sub_buf = VIPS_BUF_STATIC( error_sub_text );\n\n/* Useful: Error message and quit. Emergencies only ... we don't tidy up\n * properly.\n */\nvoid\nerror( const char *fmt, ... )\n{\n\tva_list args;\n\n\tfprintf( stderr, IP_NAME \": \" );\n\n        va_start( args, fmt );\n        (void) vfprintf( stderr, fmt, args );\n        va_end( args );\n\n\tfprintf( stderr, \"\\n\" );\n\n#ifdef DEBUG\n\t/* Make a coredump.\n\t */\n\tabort();\n#endif /*DEBUG*/\n\n\texit( 1 );\n}\n\n/* Set this to block error messages. Useful if we've found an error, we want\n * to clean up, but we don't want any of the clean-up code to touch the error\n * buffer.\n */\nstatic int error_level = 0;\n\nvoid\nerror_block( void )\n{\n\terror_level++;\n}\n\nvoid\nerror_unblock( void )\n{\n\tg_assert( error_level );\n\n\terror_level--;\n}\n\n/* Set an error buffer.\n */\nstatic void\nerror_set( VipsBuf *buf, const char *fmt, va_list ap )\n{\n\tif( !error_level ) {\n\t\tchar txt[MAX_STRSIZE];\n\t\tVipsBuf tmp = VIPS_BUF_STATIC( txt );\n\n\t\t/* The string we write may contain itself ... write to an\n\t\t * intermediate, then copy to main.\n\t\t */\n\t\tvips_buf_vappendf( &tmp, fmt, ap );\n\n\t\tvips_buf_rewind( buf );\n\t\t(void) vips_buf_appends( buf, vips_buf_all( &tmp ) );\n\n#ifdef DEBUG_ERROR\n\t\tprintf( \"error: %p %s\\n\", buf, vips_buf_all( buf ) );\n#endif /*DEBUG_ERROR*/\n\t}\n}\n\nvoid\nerror_clear_nip( void )\n{\n\tif( !error_level ) {\n\t\tvips_buf_rewind( &error_top_buf );\n\t\tvips_buf_rewind( &error_sub_buf );\n\n#ifdef DEBUG_ERROR\n\t\tprintf( \"error_clear_nip\\n\" );\n#endif /*DEBUG_ERROR*/\n\t}\n}\n\nvoid\nerror_clear( void )\n{\n\tif( !error_level ) {\n\t\terror_clear_nip();\n\t\tim_error_clear();\n\t}\n}\n\nvoid\nerror_top( const char *fmt, ... )\n{\n\tva_list ap;\n\n\tva_start( ap, fmt );\n\terror_set( &error_top_buf, fmt, ap );\n\tva_end( ap );\n\n\t/* We could use error_clear_nip() before calling error_set(), but that\n\t * fails if the arg to us uses the contents of either error buffer.\n\t */\n\tif( !error_level ) \n\t\tvips_buf_rewind( &error_sub_buf );\n}\n\nvoid\nerror_sub( const char *fmt, ... )\n{\n\tva_list ap;\n\n\tva_start( ap, fmt );\n\terror_set( &error_sub_buf, fmt, ap );\n\tva_end( ap );\n}\n\n/* Append any VIPS errors to sub buffer.\n */\nvoid\nerror_vips( void )\n{\t\n\tif( !error_level && strlen( im_error_buffer() ) > 0 ) {\n\t\tif( !vips_buf_is_empty( &error_sub_buf ) )\n\t\t\t(void) vips_buf_appendf( &error_sub_buf, \"\\n\" );\n\t\t(void) vips_buf_appendf( &error_sub_buf, \n\t\t\t\"%s\", im_error_buffer() );\n\t\tim_error_clear();\n\t}\n}\n\nvoid\nerror_vips_all( void )\n{\n\terror_top( _( \"VIPS library error.\" ) );\n\terror_vips();\n}\n\nconst char *error_get_top( void ) { return( vips_buf_all( &error_top_buf ) ); }\nconst char *error_get_sub( void ) { return( vips_buf_all( &error_sub_buf ) ); }\n\n/* Set an xml property printf() style.\n */\ngboolean\nset_prop( xmlNode *xnode, const char *name, const char *fmt, ... )\n{\n\tva_list ap;\n\tchar value[MAX_STRSIZE];\n\n        va_start( ap, fmt );\n\t(void) im_vsnprintf( value, MAX_STRSIZE, fmt, ap );\n        va_end( ap );\n\n\tif( !xmlSetProp( xnode, (xmlChar *) name, (xmlChar *) value ) ) {\n\t\terror_top( _( \"Unable to set XML property.\" ) );\n\t\terror_sub( _( \"Unable to set property \\\"%s\\\" \"\n\t\t\t\"to value \\\"%s\\\".\" ),\n\t\t\tname, value );\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Set an xml property from an optionally NULL string.\n */\ngboolean\nset_sprop( xmlNode *xnode, const char *name, const char *value )\n{\n\tif( value && !set_prop( xnode, name, \"%s\", value ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Set an xml property from an optionally NULL string.\n */\ngboolean\nset_iprop( xmlNode *xnode, const char *name, int value )\n{\n\treturn( set_prop( xnode, name, \"%d\", value ) );\n}\n\n/* Save a list of strings. For name==\"fred\" and n strings in list, save as\n * \"fredn\" == n, \"fred0\" == list[0], etc.\n */\ngboolean\nset_slprop( xmlNode *xnode, const char *name, GSList *labels )\n{\n\tif( labels ) {\n\t\tchar buf[256];\n\t\tint i;\n\n\t\t(void) im_snprintf( buf, 256, \"%sn\", name );\n\t\tif( !set_prop( xnode, buf, \"%d\", g_slist_length( labels ) ) )\n\t\t\treturn( FALSE );\n\n\t\tfor( i = 0; labels; i++, labels = labels->next ) {\n\t\t\tconst char *label = (const char *) labels->data;\n\n\t\t\t(void) im_snprintf( buf, 256, \"%s%d\", name, i );\n\t\t\tif( !set_sprop( xnode, buf, label ) )\n\t\t\t\treturn( FALSE );\n\t\t}\n\t}\n\n\treturn( TRUE );\n}\n\n/* Set a double ... use non-localisable conversion, rather than %g.\n */\ngboolean\nset_dprop( xmlNode *xnode, const char *name, double value )\n{\n\tchar buf[G_ASCII_DTOSTR_BUF_SIZE];\n\n\tg_ascii_dtostr( buf, sizeof( buf ), value );\n\n\treturn( set_sprop( xnode, name, buf ) );\n}\n\n/* Save an array of double. For name==\"fred\" and n doubles in array, save as\n * \"fredn\" == n, \"fred0\" == array[0], etc.\n */\ngboolean\nset_dlprop( xmlNode *xnode, const char *name, double *values, int n )\n{\n\tchar buf[256];\n\tint i;\n\n\t(void) im_snprintf( buf, 256, \"%sn\", name );\n\tif( !set_prop( xnode, buf, \"%d\", n ) )\n\t\treturn( FALSE );\n\n\tfor( i = 0; i < n; i++ ) {\n\t\t(void) im_snprintf( buf, 256, \"%s%d\", name, i );\n\t\tif( !set_dprop( xnode, buf, values[i] ) )\n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\ngboolean\nget_sprop( xmlNode *xnode, const char *name, char *buf, int sz )\n{\n\tchar *value = (char *) xmlGetProp( xnode, (xmlChar *) name );\n\n\tif( !value ) \n\t\treturn( FALSE );\n\n\tim_strncpy( buf, value, sz );\n\tIM_FREEF( xmlFree, value );\n\n\treturn( TRUE );\n}\n\ngboolean\nget_spropb( xmlNode *xnode, const char *name, VipsBuf *buf )\n{\n\tchar *value = (char *) xmlGetProp( xnode, (xmlChar *) name );\n\n\tif( !value ) \n\t\treturn( FALSE );\n\n\tvips_buf_appends( buf, value );\n\tIM_FREEF( xmlFree, value );\n\n\treturn( TRUE );\n}\n\ngboolean\nget_iprop( xmlNode *xnode, const char *name, int *out )\n{\n\tchar buf[256];\n\n\tif( !get_sprop( xnode, name, buf, 256 ) ) \n\t\treturn( FALSE );\n\n\t*out = atoi( buf );\n\n\treturn( TRUE );\n}\n\ngboolean\nget_dprop( xmlNode *xnode, const char *name, double *out )\n{\n\tchar buf[256];\n\n\tif( !get_sprop( xnode, name, buf, 256 ) ) \n\t\treturn( FALSE );\n\n\t*out = g_ascii_strtod( buf, NULL );\n\n\treturn( TRUE );\n}\n\ngboolean\nget_bprop( xmlNode *xnode, const char *name, gboolean *out )\n{\n\tchar buf[256];\n\n\tif( !get_sprop( xnode, name, buf, 256 ) ) \n\t\treturn( FALSE );\n\n\t*out = strcasecmp( buf, \"true\" ) == 0;\n\n\treturn( TRUE );\n}\n\n/* Load a list of strings. For name==\"fred\", look for \"fredn\" == number of\n * strings to load, \"fred0\" == list[0], etc.\n */\ngboolean\nget_slprop( xmlNode *xnode, const char *name, GSList **out )\n{\n\tchar buf[256];\n\tint n, i;\n\n\t(void) im_snprintf( buf, 256, \"%sn\", name );\n\tif( !get_iprop( xnode, buf, &n ) )\n\t\treturn( FALSE );\n\n\t*out = NULL;\n\tfor( i = n - 1; i >= 0; i-- ) {\n\t\t(void) im_snprintf( buf, 256, \"%s%d\", name, i );\n\t\tif( !get_sprop( xnode, buf, buf, 256 ) )\n\t\t\treturn( FALSE );\n\n\t\t*out = g_slist_prepend( *out, g_strdup( buf ) );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Load an array of double. For name==\"fred\", look for \"fredn\" == length of\n * array, \"fred0\" == array[0], etc.\n */\ngboolean\nget_dlprop( xmlNode *xnode, const char *name, double **out )\n{\n\tchar buf[256];\n\tint n, i;\n\n\t(void) im_snprintf( buf, 256, \"%sn\", name );\n\tif( !get_iprop( xnode, buf, &n ) )\n\t\treturn( FALSE );\n\n\tif( !(*out = IARRAY( NULL, n, double )) )\n\t\treturn( FALSE );\n\n\tfor( i = 0; i < n; i++ ) {\n\t\t(void) im_snprintf( buf, 256, \"%s%d\", name, i );\n\t\tif( !get_dprop( xnode, buf, *out + i ) )\n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Find the first child node with a name.\n */\nxmlNode *\nget_node( xmlNode *base, const char *name )\n{\n\txmlNode *i;\n\n\tfor( i = base->children; i; i = i->next )\n\t\tif( strcmp( (char *) i->name, name ) == 0 )\n\t\t\treturn( i );\n\n\treturn( NULL );\n}\n\nstatic int rect_n_rects = 0;\n\n/* Allocate and free rects.\n */\nRect *\nrect_dup( Rect *init )\n{\n\tRect *new_rect;\n\n\tif( !(new_rect = INEW( NULL, Rect )) )\n\t\treturn( NULL );\n\n\t*new_rect = *init;\n\n\trect_n_rects += 1;\n\n\treturn( new_rect );\n}\n\nvoid *\nrect_free( Rect *rect )\n{\n\tim_free( rect );\n\trect_n_rects -= 1;\n\n\treturn( NULL );\n}\n\n/* Test two lists for eqality.\n */\ngboolean\nslist_equal( GSList *l1, GSList *l2 )\n{\n\twhile( l1 && l2 ) {\n\t\tif( l1->data != l2->data )\n\t\t\treturn( FALSE );\n\n\t\tl1 = l1->next;\n\t\tl2 = l2->next;\n\t}\n\n\tif( l1 || l2 )\n\t\treturn( FALSE );\n\t\n\treturn( TRUE );\n}\n\n/* Map over an slist.\n */\nvoid *\nslist_map( GSList *list, SListMapFn fn, gpointer a )\n{\n\tGSList *copy;\n\tGSList *i;\n\tvoid *result;\n\n\tcopy = g_slist_copy( list );\n\tresult = NULL;\n\tfor( i = copy; i && !(result = fn( i->data, a )); i = i->next ) \n\t\t;\n\tg_slist_free( copy );\n\n\treturn( result );\n}\n\nvoid *\nslist_map2( GSList *list, SListMap2Fn fn, gpointer a, gpointer b )\n{\n\tGSList *copy;\n\tGSList *i;\n\tvoid *result;\n\n\tcopy = g_slist_copy( list );\n\tresult = NULL;\n\tfor( i = copy; i && !(result = fn( i->data, a, b )); i = i->next ) \n\t\t;\n\tg_slist_free( copy );\n\n\treturn( result );\n}\n\nvoid *\nslist_map3( GSList *list, SListMap3Fn fn, gpointer a, gpointer b, gpointer c )\n{\n\tGSList *copy;\n\tGSList *i;\n\tvoid *result;\n\n\tcopy = g_slist_copy( list );\n\tresult = NULL;\n\tfor( i = copy; i && !(result = fn( i->data, a, b, c )); i = i->next ) \n\t\t;\n\tg_slist_free( copy );\n\n\treturn( result );\n}\n\nvoid *\nslist_map4( GSList *list, SListMap4Fn fn, \n\tgpointer a, gpointer b, gpointer c, gpointer d )\n{\n\tGSList *copy;\n\tGSList *i;\n\tvoid *result;\n\n\tcopy = g_slist_copy( list );\n\tresult = NULL;\n\tfor( i = copy; i && !(result = fn( i->data, a, b, c, d )); \n\t\ti = i->next ) \n\t\t;\n\tg_slist_free( copy );\n\n\treturn( result );\n}\n\nvoid *\nslist_map5( GSList *list, SListMap5Fn fn, \n\tgpointer a, gpointer b, gpointer c, gpointer d, gpointer e )\n{\n\tGSList *copy;\n\tGSList *i;\n\tvoid *result;\n\n\tcopy = g_slist_copy( list );\n\tresult = NULL;\n\tfor( i = copy; i && !(result = fn( i->data, a, b, c, d, e )); \n\t\ti = i->next ) \n\t\t;\n\tg_slist_free( copy );\n\n\treturn( result );\n}\n\n/* Map backwards.\n */\nvoid *\nslist_map_rev( GSList *list, SListMapFn fn, gpointer a )\n{\n\tGSList *copy;\n\tGSList *i;\n\tvoid *result;\n\n\tcopy = g_slist_copy( list );\n\tcopy = g_slist_reverse( copy );\n\tresult = NULL;\n\tfor( i = copy; i && !(result = fn( i->data, a )); i = i->next ) \n\t\t;\n\tg_slist_free( copy );\n\n\treturn( result );\n}\n\nvoid *\nslist_map2_rev( GSList *list, SListMap2Fn fn, gpointer a, gpointer b )\n{\n\tGSList *copy;\n\tGSList *i;\n\tvoid *result;\n\n\tcopy = g_slist_copy( list );\n\tcopy = g_slist_reverse( copy );\n\tresult = NULL;\n\tfor( i = copy; i && !(result = fn( i->data, a, b )); i = i->next ) \n\t\t;\n\tg_slist_free( copy );\n\n\treturn( result );\n}\n\nvoid *\nslist_map3_rev( GSList *list, SListMap3Fn fn, void *a, void *b, void *c )\n{\n\tGSList *copy;\n\tGSList *i;\n\tvoid *result;\n\n\tcopy = g_slist_copy( list );\n\tcopy = g_slist_reverse( copy );\n\tresult = NULL;\n\tfor( i = copy; i && !(result = fn( i->data, a, b, c )); i = i->next ) \n\t\t;\n\tg_slist_free( copy );\n\n\treturn( result );\n}\n\nvoid *\nmap_equal( void *a, void *b )\n{\n\tif( a == b )\n\t\treturn( a );\n\n\treturn( NULL );\n}\n\nvoid *\nslist_fold( GSList *list, void *start, SListFoldFn fn, void *a )\n{\n        void *c;\n        GSList *ths, *next;\n\n        for( c = start, ths = list; ths; ths = next ) {\n                next = ths->next;\n\n                if( !(c = fn( ths->data, c, a )) )\n\t\t\treturn( NULL );\n        }\n\n        return( c );\n}\n\nvoid *\nslist_fold2( GSList *list, void *start, SListFold2Fn fn, void *a, void *b )\n{\n        void *c;\n        GSList *ths, *next;\n\n        for( c = start, ths = list; ths; ths = next ) {\n                next = ths->next;\n\n                if( !(c = fn( ths->data, c, a, b )) )\n\t\t\treturn( NULL );\n        }\n\n        return( c );\n}\n\nstatic void\nslist_free_all_cb( gpointer thing, gpointer dummy )\n{\n\tg_free( thing );\n}\n\n/* Free a g_slist of things which need g_free()ing.\n */\nvoid\nslist_free_all( GSList *list )\n{\n\tg_slist_foreach( list, slist_free_all_cb, NULL );\n\tg_slist_free( list );\n}\n\n/* Remove all occurences of an item from a list.\n */\nGSList *\nslist_remove_all( GSList *list, gpointer data )\n{\n\tGSList *tmp;\n\tGSList *prev;\n\n\tprev = NULL;\n\ttmp = list;\n\n\twhile( tmp ) {\n\t\tif( tmp->data == data ) {\n\t\t\tGSList *next = tmp->next;\n\n\t\t\tif( prev )\n\t\t\t\tprev->next = next;\n\t\t\tif( list == tmp )\n\t\t\t\tlist = next;\n\n\t\t\ttmp->next = NULL;\n\t\t\tg_slist_free( tmp );\n\t\t\ttmp = next;\n\t\t}\n\t\telse {\n\t\t\tprev = tmp;\n\t\t\ttmp = tmp->next;\n\t\t}\n\t}\n\n\treturn( list );\n}\n\nQueue *\nqueue_new( void )\n{\n\tQueue *q = INEW( NULL, Queue );\n\n\tq->list = NULL;\n\tq->tail = NULL;\n\tq->length = 0;\n\n\treturn( q );\n}\n\nvoid *\nqueue_head( Queue *q )\n{\n\tvoid *data;\n\n\tg_assert( q );\n\n\tif( !q->list )\t\n\t\treturn( NULL );\n\n\tdata = q->list->data;\n\n\tq->list = g_slist_remove( q->list, data );\n\tif( !q->list )\n\t\tq->tail = NULL;\n\n\tq->length -= 1;\n\n\treturn( data );\n}\n\nvoid\nqueue_add( Queue *q, void *data )\n{\n\tif( !q->tail ) {\n\t\tg_assert( !q->list );\n\n\t\tq->list = q->tail = g_slist_append( q->list, data );\n\t}\n\telse {\n\t\tg_assert( q->list );\n\n\t\tq->tail = g_slist_append( q->tail, data );\n\t\tq->tail = q->tail->next;\n\t}\n\n\tq->length += 1;\n}\n\n/* Not very fast! But used infrequently. TRUE if the data was in the queue and\n * has now been removed.\n */\ngboolean \nqueue_remove( Queue *q, void *data )\n{\n\tGSList *ele;\n\n\tif( !(ele = g_slist_find( q->list, data )) ) \n\t\treturn( FALSE );\n\n\tq->list = g_slist_remove( q->list, data );\n\n\tif( ele == q->tail ) \n\t\tq->tail = g_slist_last( q->list );\n\n\tq->length -= 1;\n\n\treturn( TRUE );\n}\n\nint\nqueue_length( Queue *q )\n{\n\treturn( q->length );\n}\n\n/* Make an info string about an image.\n */\nvoid\nvips_buf_appendi( VipsBuf *buf, IMAGE *im )\n{\n\tif( !im ) {\n\t\tvips_buf_appends( buf, _( \"(no image)\" ) );\n\t\treturn;\n\t}\n\n\t/* Coded? Special warning.\n\t */\n\tif( im->Coding != IM_CODING_NONE )\n\t\tvips_buf_appendf( buf, \"%s, \", \n\t\t\tNN( im_Coding2char( im->Coding ) ) );\n\n\t/* Format string expands to (eg.) \n\t * \"2000x3000 128-bit complex, 3 bands, Lab\" \n\t */\n\tvips_buf_appendf( buf, \n\t\tngettext( \"%dx%d %s, %d band, %s\", \n\t\t\t\"%dx%d %s, %d bands, %s\", im->Bands ),\n\t\tim->Xsize, im->Ysize, decode_bandfmt( im->BandFmt ),\n\t\tim->Bands, decode_type( im->Type ) );\n}\n\n/* Append a string, escaping C stuff. Escape double quotes if quote is set.\n */\ngboolean\nvips_buf_appendsc( VipsBuf *buf, gboolean quote, const char *str )\n{\n\tchar buffer[FILENAME_MAX];\n\tchar buffer2[FILENAME_MAX];\n\n\t/* /2 to leave a bit of space.\n\t */\n\tim_strncpy( buffer, str, FILENAME_MAX / 2 );\n\n\t/* FIXME ... possible buffer overflow :-(\n\t */\n\tmy_strecpy( buffer2, buffer, quote );\n\n\treturn( vips_buf_appends( buf, buffer2 ) );\n}\n\n/* Test for string a ends string b. \n */\ngboolean\nis_postfix( const char *a, const char *b )\n{\t\n\tint n = strlen( a );\n\tint m = strlen( b );\n\n\tif( m < n )\n\t\treturn( FALSE );\n\n\treturn( !strcmp( a, b + m - n ) );\n}\n\n/* Test for string a ends string b, case independent.\n */\ngboolean\nis_casepostfix( const char *a, const char *b )\n{\t\n\tint n = strlen( a );\n\tint m = strlen( b );\n\n\tif( m < n )\n\t\treturn( FALSE );\n\n\treturn( !strcasecmp( a, b + m - n ) );\n}\n\n/* Test for string a starts string b. \n */\ngboolean\nis_prefix( const char *a, const char *b )\n{\n\tint n = strlen( a );\n\tint m = strlen( b );\n\tint i;\n\n\tif( m < n )\n\t\treturn( FALSE );\n\tfor( i = 0; i < n; i++ )\n\t\tif( a[i] != b[i] )\n\t\t\treturn( FALSE );\n\t\n\treturn( TRUE );\n}\n\n/* Test for string a starts string b ... case insensitive. \n */\ngboolean\nis_caseprefix( const char *a, const char *b )\n{\n\tint n = strlen( a );\n\tint m = strlen( b );\n\tint i;\n\n\tif( m < n )\n\t\treturn( FALSE );\n\tfor( i = 0; i < n; i++ )\n\t\tif( toupper( a[i] ) != toupper( b[i] ) )\n\t\t\treturn( FALSE );\n\t\n\treturn( TRUE );\n}\n\n/* Like strstr(), but case-insensitive.\n */\nchar *\nmy_strcasestr( const char *haystack, const char *needle )\n{\n\tint i;\n\tint hlen = strlen( haystack );\n\tint nlen = strlen( needle );\n\n\tfor( i = 0; i <= hlen - nlen; i++ )\n\t\tif( is_caseprefix( needle, haystack + i ) )\n\t\t\treturn( (char *) (haystack + i) );\n\n\treturn( NULL );\n}\n\n/* Copy a string, interpreting (a few) C-language escape codes.\n\n\tFIXME ... yuk! dangerous and not that useful, needs a proper function\n\tto do this\n\n */\nchar *\nmy_strccpy( char *output, const char *input )\n{\n\tconst char *p;\n\tchar *q;\n\n\tfor( p = input, q = output; *p; p++, q++ )\n\t\tif( p[0] == '\\\\' ) {\n\t\t\tswitch( p[1] ) {\n\t\t\tcase 'n':\n\t\t\t\tq[0] = '\\n';\n\t\t\t\tbreak;\n\n\t\t\tcase 't':\n\t\t\t\tq[0] = '\\t';\n\t\t\t\tbreak;\n\n\t\t\tcase 'r':\n\t\t\t\tq[0] = '\\r';\n\t\t\t\tbreak;\n\n\t\t\tcase '\"':\n\t\t\t\tq[0] = '\\\"';\n\t\t\t\tbreak;\n\n\t\t\tcase '\\'':\n\t\t\t\tq[0] = '\\'';\n\t\t\t\tbreak;\n\n\t\t\tcase '\\\\':\n\t\t\t\tq[0] = '\\\\';\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t/* Leave uninterpreted.\n\t\t\t\t */\n\t\t\t\tq[0] = p[0];\n\t\t\t\tq[1] = p[1];\n\t\t\t\tq++;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tp++;\n\t\t}\n\t\telse\n\t\t\tq[0] = p[0];\n\tq[0] = '\\0';\n\n\treturn( output );\n}\n\n/* Copy a string, expanding escape characters into C-language escape codes.\n * Escape double quotes if quote is set.\n */\nchar *\nmy_strecpy( char *output, const char *input, gboolean quote )\n{\n\tconst char *p;\n\tchar *q;\n\n\tfor( p = input, q = output; *p; p++, q++ )\n\t\tswitch( p[0] ) {\n\t\tcase '\\n':\n\t\t\tq[0] = '\\\\';\n\t\t\tq[1] = 'n';\n\t\t\tq++;\n\t\t\tbreak;\n\n\t\tcase '\\t':\n\t\t\tq[0] = '\\\\';\n\t\t\tq[1] = 't';\n\t\t\tq++;\n\t\t\tbreak;\n\n\t\tcase '\\r':\n\t\t\tq[0] = '\\\\';\n\t\t\tq[1] = 'r';\n\t\t\tq++;\n\t\t\tbreak;\n\n\t\tcase '\\\"':\n\t\t\tif( quote ) {\n\t\t\t\tq[0] = '\\\\';\n\t\t\t\tq[1] = '\\\"';\n\t\t\t\tq++;\n\t\t\t}\n\t\t\telse\n\t\t\t\tq[0] = p[0];\n\t\t\tbreak;\n\n\t\tcase '\\'':\n\t\t\tq[0] = '\\\\';\n\t\t\tq[1] = '\\'';\n\t\t\tq++;\n\t\t\tbreak;\n\n\t\tcase '\\\\':\n\t\t\tq[0] = '\\\\';\n\t\t\tq[1] = '\\\\';\n\t\t\tq++;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tq[0] = p[0];\n\t\t\tbreak;\n\t\t}\n\tq[0] = '\\0';\n\n\treturn( output );\n}\n\n/* Is a character in a string?\n */\nstatic int\ninstr( char c, const char *spn )\n{\n\tconst char *p;\n\n\tfor( p = spn; *p; p++ )\n\t\tif( *p == c )\n\t\t\treturn( 1 );\n\t\n\treturn( 0 );\n}\n\n/* Doh ... not everyone has strrspn(), define one. Return a pointer to the\n * start of the trailing segment of p which contains only chars in spn. \n */\nconst char *\nmy_strrspn( const char *p, const char *spn )\n{\n\tconst char *p1;\n\n\tfor( p1 = p + strlen( p ) - 1; p1 >= p && instr( *p1, spn ); p1-- )\n\t\t;\n\tp1++;\n\n\treturn( p1 );\n}\n\n/* Find a pointer to the start of the trailing segment of p which contains\n * only chars not in spn.\n */\nconst char *\nmy_strrcspn( const char *p, const char *spn )\n{\n\tconst char *p1;\n\n\tfor( p1 = p + strlen( p ) - 1; p1 >= p && !instr( *p1, spn ); p1-- )\n\t\t;\n\tp1++;\n\n\treturn( p1 );\n}\n\n/* Find the rightmost occurence of string a in string b.\n */\nconst char *\nfindrightmost( const char *a, const char *b )\n{\t\n\tint la = strlen( a );\n\tint lb = strlen( b );\n\tint i;\n\n\tif( lb < la )\n\t\treturn( NULL );\n\n\tfor( i = lb - la; i > 0; i-- )\n\t\tif( strncmp( a, &b[i], la ) == 0 )\n\t\t\treturn( &b[i] );\n\n\treturn( NULL );\n}\n\n/* Useful transformation: strip off a set of suffixes (eg. \".v\", \".icon\",\n * \".hr\"), add a single new suffix (eg. \".hr.v\"). \n */\nvoid\nchange_suffix( const char *name, char *out, \n\tconst char *new, const char **olds, int nolds )\n{\t\n\tchar *p;\n\tint i;\n\n\t/* Copy start string.\n\t */\n\tstrcpy( out, name );\n\n\t/* Drop all matching suffixes.\n\t */\n\twhile( (p = strrchr( out, '.' )) ) {\n\t\t/* Found suffix - test against list of alternatives. Ignore\n\t\t * case.\n\t\t */\n\t\tfor( i = 0; i < nolds; i++ )\n\t\t\tif( strcasecmp( p, olds[i] ) == 0 ) {\n\t\t\t\t*p = '\\0';\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t/* Found match? If not, break from loop.\n\t\t */\n\t\tif( *p )\n\t\t\tbreak;\n\t}\n\n\t/* Add new suffix.\n\t */\n\tstrcat( out, new );\n}\n\n/* Drop leading and trim trailing non-alphanum characters. NULL if nothing \n * left. The result can be a variable name.\n */\nchar *\ntrim_nonalpha( char *text )\n{\n\tchar *p, *q;\n\n\t/* Skip any initial non-alpha characters.\n\t */\n\tfor( q = text; *q && !isalpha( (int)(*q) ); q++ )\n\t\t;\n\n\t/* Find next non-alphanumeric character. \n\t */\n\tfor( p = q; *p && isalnum( (int)(*p) ); p++ )\n\t\t;\n\t*p = '\\0';\n\n\tif( strlen( q ) == 0 )\n\t\treturn( NULL );\n\telse\n\t\treturn( q );\n}\n\n/* Drop leading and trim trailing whitespace characters. NULL if nothing \n * left. \n */\nchar *\ntrim_white( char *text )\n{\n\tchar *p, *q;\n\n\t/* Skip any initial whitespace characters.\n\t */\n\tfor( q = text; *q && isspace( (int)(*q) ); q++ )\n\t\t;\n\n\t/* Find rightmost non-space char.\n\t */\n\tfor( p = q + strlen( q ) - 1; p > q && isspace( (int)(*p) ); p-- )\n\t\t;\n\tp[1] = '\\0';\n\n\tif( strlen( q ) == 0 )\n\t\treturn( NULL );\n\telse\n\t\treturn( q );\n}\n\n/* Get a pointer to a band element in a region.\n */\nvoid *\nget_element( REGION *ireg, int x, int y, int b )\n{\n\tIMAGE *im = ireg->im;\n\n\t/* Return a pointer to this on error.\n\t */\n\tstatic PEL empty[50] = { 0 };\n\n\tPEL *data;\n\tint es = IM_IMAGE_SIZEOF_ELEMENT( im );\n\tRect iarea;\n\n\t/* Make sure we can read from this descriptor.\n\t */\n\tif( im_pincheck( im ) )\n\t\t/* Help!\n\t\t */\n\t\treturn( empty );\n\n\t/* Ask for the area we need.\n\t */\n\tiarea.left = x;\n\tiarea.top = y;\n\tiarea.width = 1;\n\tiarea.height = 1;\n\tif( im_prepare( ireg, &iarea ) )\n\t\treturn( empty );\n\n\t/* Find a pointer to the start of the data.\n\t */\n\tdata = (PEL *) IM_REGION_ADDR( ireg, x, y ) + b * es;\n\n\treturn( (void *) data );\n}\n\n/* Decode band formats in a friendly way.\n */\nstatic const char *bandfmt_names[] = {\n\tN_( \"8-bit unsigned integer\" ),\t/* IM_BANDFMT_UCHAR */ \n\tN_( \"8-bit signed integer\" ),\t/* IM_BANDFMT_CHAR */\n\tN_( \"16-bit unsigned integer\" ),/* IM_BANDFMT_USHORT */\n\tN_( \"16-bit signed integer\" ), \t/* IM_BANDFMT_SHORT */\n\tN_( \"32-bit unsigned integer\" ),/* IM_BANDFMT_UINT */\n\tN_( \"32-bit signed integer\" ), \t/* IM_BANDFMT_INT */\n\tN_( \"32-bit float\" ), \t\t/* IM_BANDFMT_FLOAT */\n\tN_( \"64-bit complex\" ), \t/* IM_BANDFMT_COMPLEX */\n\tN_( \"64-bit float\" ), \t\t/* IM_BANDFMT_DOUBLE */\n\tN_( \"128-bit complex\" )\t\t/* IM_BANDFMT_DPCOMPLEX */\n};\nstatic const int nbandfmt_names = IM_NUMBER( bandfmt_names );\n\nconst char *\ndecode_bandfmt( int f )\n{\n\tif( f > nbandfmt_names - 1 || f < 0 )\n\t\treturn( _( \"<unknown format>\" ) );\n\telse\n\t\treturn( _( bandfmt_names[f] ) );\n}\n\n/* Decode type names in a way consistent with the menus.\n */\nstatic const char *type_names[] = {\n\t\"multiband\",\t\t/* IM_TYPE_MULTIBAND\t0 */\n\t\"mono\",\t\t\t/* IM_TYPE_B_W\t\t1 */\n\t\"luminance\",\t\t/* LUMINACE\t\t2 */\n\t\"xray\",\t\t\t/* XRAY\t\t\t3 */\n\t\"infrared\",\t\t/* IR\t\t\t4 */\n\t\"Yuv\",\t\t\t/* YUV\t\t\t5 */\n\t\"red_only\",\t\t/* RED_ONLY\t\t6 */\n\t\"green_only\",\t\t/* GREEN_ONLY\t\t7 */\n\t\"blue_only\",\t\t/* BLUE_ONLY\t\t8 */\n\t\"power_spectrum\",\t/* POWER_SPECTRUM\t9 */\n\t\"histogram\",\t\t/* IM_TYPE_HISTOGRAM\t10 */\n\t\"lookup_table\",\t\t/* LUT\t\t\t11 */\n\t\"XYZ\",\t\t\t/* IM_TYPE_XYZ\t\t12 */\n\t\"Lab\",\t\t\t/* IM_TYPE_LAB\t\t13 */\n\t\"CMC\",\t\t\t/* CMC\t\t\t14 */\n\t\"CMYK\",\t\t\t/* IM_TYPE_CMYK\t\t15 */\n\t\"LabQ\",\t\t\t/* IM_TYPE_LABQ\t\t16 */\n\t\"RGB\",\t\t\t/* IM_TYPE_RGB\t\t17 */\n\t\"UCS\",\t\t\t/* IM_TYPE_UCS\t\t18 */\n\t\"LCh\",\t\t\t/* IM_TYPE_LCH\t\t19 */\n\t\"<undefined>\",\t\t/* ??\t\t\t20 */\n\t\"LabS\",\t\t\t/* IM_TYPE_LABS\t\t21 */\n\t\"sRGB\",\t\t\t/* IM_TYPE_sRGB\t\t22 */\n\t\"Yxy\",\t\t\t/* IM_TYPE_YXY\t\t23 */\n\t\"Fourier\",\t\t/* IM_TYPE_FOURIER\t24 */\n\t\"RGB16\",\t\t/* IM_TYPE_RGB16\t25 */\n\t\"GREY16\",\t\t/* IM_TYPE_GREY16\t26 */\n\t\"Array\",\t\t/* VIPS_INTERPRETATION_ARRAY = 27 */\n\t\"scRGB\"\t\t\t/* VIPS_INTERPRETATION_scRGB = 28 */\n};\nstatic const int ntype_names = IM_NUMBER( type_names );\n\nconst char *\ndecode_type( int t )\n{\n\tif( t > ntype_names - 1 || t < 0 )\n\t\treturn( _( \"<unknown type>\" ) );\n\telse\n\t\treturn( type_names[t] );\n}\n\n/* Make an info string about a file.\n */\nvoid\nget_image_info( VipsBuf *buf, const char *name )\n{\n\tchar name2[FILENAME_MAX];\n\tstruct stat st;\n\n\texpand_variables( name, name2 );\n\tvips_buf_appendf( buf, \"%s, \", im_skip_dir( name ) );\n\n\t/* Read size and file/dir.\n\t */\n\tif( stat( name2, &st ) == -1 ) {\n\t\tvips_buf_appendf( buf, \"%s\", g_strerror( errno ) );\n\t\treturn;\n\t}\n\n\tif( S_ISDIR( st.st_mode ) )\n\t\tvips_buf_appends( buf, _( \"directory\" ) );\n\telse if( S_ISREG( st.st_mode ) ) {\n\t\tIMAGE *im;\n\n\t\t/* Spot workspace files from the filename. These are XML files\n\t\t * and if imagemagick sees them it'll try to load them as SVG\n\t\t * or somethiing awful like that.\n\t\t */\n\t\tif( is_file_type( &filesel_wfile_type, name2 ) ) {\n\t\t\tvips_buf_appends( buf, _( \"workspace\" ) );\n\t\t}\n\t\telse if( (im = im_open( name2, \"r\" )) ) {\n\t\t\tvips_buf_appendi( buf, im ); \n\t\t\tim_close( im );\n\t\t}\n\t\telse\n\t\t\t/* No idea wtf this is, just put the size in.\n\t\t\t */\n\t\t\tvips_buf_append_size( buf, st.st_size );\n\t}\n}\n\n/* A char that can be part of an environment variable name? A-Za-z0-9_\n */\nstatic gboolean\nisvariable( int ch )\n{\n\treturn( isalnum( ch ) || ch == '_' );\n}\n\n/* Expand environment variables from in to out. Return true if we performed an\n * expansion, false for no variables there.\n */\nstatic gboolean\nexpand_once( char *in, char *out )\n{\n\tchar *p, *q;\n\tgboolean have_substituted = FALSE;\n\n\t/* Scan and copy.\n\t */\n\tfor( p = in, q = out; (*q = *p) && (q - out) < FILENAME_MAX; p++, q++ )\n\t\t/* Did we just copy a '$'?\n\t\t */\n\t\tif( *p == '$' ) {\n\t\t\tchar vname[FILENAME_MAX];\n\t\t\tchar *r;\n\t\t\tconst char *subst;\n\t\t\tconst char *s;\n\n\t\t\t/* Extract the variable name.\n\t\t\t */\n\t\t\tp++;\n\t\t\tfor( r = vname; \n\t\t\t\tisvariable( (int)(*r = *p) ) && \n\t\t\t\t\t(r - vname) < FILENAME_MAX;\n\t\t\t\tp++, r++ )\n\t\t\t\t;\n\t\t\t*r = '\\0';\n\t\t\tp--;\n\n\t\t\t/* Look up variable.\n\t\t\t */\n\t\t\tsubst = g_getenv( vname );\n\n\t\t\t/* Copy variable contents.\n\t\t\t */\n\t\t\tif( subst ) {\n\t\t\t\tfor( s = subst; \n\t\t\t\t\t(*q = *s) && (q - out) < FILENAME_MAX; \n\t\t\t\t\ts++, q++ )\n\t\t\t\t\t;\n\t\t\t}\n\t\t\tq--;\n\n\t\t\t/* Remember we have performed a substitution.\n\t\t\t */\n\t\t\thave_substituted = TRUE;\n\t\t}\n\t\t/* Or a '~' at the start of the string?\n\t\t */\n\t\telse if( *p == '~' && p == in ) {\n\t\t\tconst char *subst = g_getenv( \"HOME\" );\n\t\t\tconst char *r;\n\n\t\t\t/* Copy variable contents.\n\t\t\t */\n\t\t\tif( subst ) {\n\t\t\t\tfor( r = subst; \n\t\t\t\t\t(*q = *r) && (q - out) < FILENAME_MAX;\n\t\t\t\t\tr++, q++ )\n\t\t\t\t\t;\n\t\t\t}\n\t\t\tq--;\n\n\t\t\t/* Remember we have performed a substitution.\n\t\t\t */\n\t\t\thave_substituted = TRUE;\n\t\t}\n\n\treturn( have_substituted );\n}\n\n/* Expand all variables! Don't touch in, assume out[] is at least\n * FILENAME_MAX bytes. in and out must not point to the same place!\n */\nvoid\nexpand_variables( const char *in, char *out )\n{\n\tchar buf[FILENAME_MAX];\n\tchar *p1 = (char *) in;\t\t/* Discard const, but safe */\n\tchar *p2 = out;\n\n\tg_assert( in != out );\n\n\t/* Expand any environment variables in component.\n\t */\n\twhile( expand_once( p1, p2 ) ) \n\t\t/* We have expanded --- swap the buffers and try\n\t\t * again.\n\t\t */\n\t\tif( p2 == out ) {\n\t\t\tp1 = out;\n\t\t\tp2 = buf;\n\t\t}\n\t\telse {\n\t\t\tp1 = buf;\n\t\t\tp2 = out;\n\t\t}\n}\n\nstatic void\nswap_chars( char *buf, char from, char to )\n{\n\tint i;\n\n\tfor( i = 0; buf[i]; i++ )\n\t\tif( buf[i] == from )\n\t\t\tbuf[i] = to;\n}\n\n/* If we use '/' seps, swap all '\\' for '/' ... likewise vice versa. Only in\n * the filename part, though. We don't want to junk '\\,', for example.\n */\nvoid\nnativeize_path( char *buf )\n{\n\tchar filename[FILENAME_MAX];\n\tchar mode[FILENAME_MAX];\n\n\tim_filename_split( buf, filename, mode );\n\n\tif( G_DIR_SEPARATOR == '/' )\n\t\tswap_chars( filename, '\\\\', '/' );\n\telse\n\t\tswap_chars( filename, '/', '\\\\' );\n\n\tif( strcmp( mode, \"\" ) != 0 )\n\t\tim_snprintf( buf, FILENAME_MAX, \"%s:%s\", filename, mode );\n\telse\n\t\tim_snprintf( buf, FILENAME_MAX, \"%s\", filename );\n}\n\n/* Change all occurences of \"from\" into \"to\". This will loop if \"to\" contains\n * \"from\", beware.\n */\nstatic void\nswap_string( char *buffer, const char *from, const char *to )\n{\n\tchar *p;\n\n\twhile( (p = strstr( buffer, from )) ) {\n\t\tint off = p - buffer;\n\t\tchar buf2[FILENAME_MAX];\n\n\t\tim_strncpy( buf2, buffer, FILENAME_MAX );\n\t\tbuf2[off] = '\\0';\n\t\tim_snprintf( buffer, FILENAME_MAX,\n\t\t\t\"%s%s%s\", buf2, to, buf2 + off + strlen( from ) );\n\t}\n}\n\n/* Remove \".\" and \"..\" from an absolute path (if we can).\n */\nvoid\ncanonicalize_path( char *path )\n{\n\tgboolean found;\n\n\tg_assert( is_absolute( path ) );\n\n\t/* Any \"/./\" can go.\n\t */\n\tswap_string( path, \n\t\tG_DIR_SEPARATOR_S \".\" G_DIR_SEPARATOR_S, G_DIR_SEPARATOR_S );\n\n\t/* Any \"//\" can go.\n\t */\n\tswap_string( path, \n\t\tG_DIR_SEPARATOR_S G_DIR_SEPARATOR_S, G_DIR_SEPARATOR_S );\n\n\t/* Repeatedly search for \"/[^/]+/../\" and remove it.\n\n\t\tFIXME ... yuk, should search backwards from the end of the\n\t\tstring\n\n\t */\n\tdo {\n\t\tchar *p;\n\n\t\tfound = FALSE;\n\n\t\tfor( p = path; (p = strchr( p, G_DIR_SEPARATOR )); p++ ) {\n\t\t\tchar *q;\n\n\t\t\tq = strchr( p + 1, G_DIR_SEPARATOR );\n\n\t\t\tif( q && is_prefix( G_DIR_SEPARATOR_S \"..\", q ) ) {\n\t\t\t\tmemmove( p, q + 3, strlen( q + 3 ) + 1 );\n\t\t\t\tfound = TRUE;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} while( found );\n\n\t/* We may have the empty string ... that's just '/'.\n\t */\n\tif( strcmp( path, \"\" ) == 0 )\n\t\tstrcpy( path, G_DIR_SEPARATOR_S );\n}\n\n/* Absoluteize a path. Must be FILENAME_MAX chars available.\n */\nvoid\nabsoluteize_path( char *path )\n{\n\tif( !is_absolute( path ) ) {\n\t\tchar buf[FILENAME_MAX];\n\t\tchar *cwd;\n\n\t\tim_strncpy( buf, path, FILENAME_MAX );\n\t\tcwd = g_get_current_dir();\n\t\tim_snprintf( path, FILENAME_MAX,\n\t\t\t\"%s%s%s\", cwd, G_DIR_SEPARATOR_S, buf );\n\t\tg_free( cwd );\n\t\tcanonicalize_path( path );\n\t}\n}\n\n/* Call a void*-valued function, building a string arg. We expand env. \n * variables, but that's all.\n */\nvoid *\ncallv_string( callv_string_fn fn, const char *arg, void *a, void *b, void *c )\n{\n\tchar buf[FILENAME_MAX];\n\n\texpand_variables( arg, buf );\n\n\treturn( fn( buf, a, b, c ) );\n}\n\nvoid *\ncallv_stringva( callv_string_fn fn, \n\tconst char *fmt, va_list ap, void *a, void *b, void *c )\n{\n\tchar buf[FILENAME_MAX];\n\n        (void) im_vsnprintf( buf, FILENAME_MAX, fmt, ap );\n\n\treturn( callv_string( fn, buf, a, b, c ) );\n}\n\nvoid *\ncallv_stringf( callv_string_fn fn, const char *fmt, ... )\n{\n\tva_list ap;\n\tvoid *res;\n\n        va_start( ap, fmt );\n        res = callv_stringva( fn, fmt, ap, NULL, NULL, NULL );\n        va_end( ap );\n\n\treturn( res );\n}\n\n/* Call a function, building a filename arg. Nativize and absoluteize too.\n */\nvoid *\ncallv_string_filename( callv_string_fn fn, \n\tconst char *filename, void *a, void *b, void *c )\n{\n\tchar buf[FILENAME_MAX];\n\n\texpand_variables( filename, buf );\n        nativeize_path( buf );\n\tabsoluteize_path( buf );\n\n\treturn( fn( buf, a, b, c ) );\n}\n\nvoid *\ncallv_string_filenameva( callv_string_fn fn, \n\tconst char *fmt, va_list ap, void *a, void *b, void *c )\n{\n\tchar buf[FILENAME_MAX];\n\n        (void) im_vsnprintf( buf, FILENAME_MAX, fmt, ap );\n\n\treturn( callv_string_filename( fn, buf, a, b, c ) );\n}\n\nvoid *\ncallv_string_filenamef( callv_string_fn fn, const char *fmt, ... )\n{\n\tva_list ap;\n\tvoid *res;\n\n        va_start( ap, fmt );\n        res = callv_string_filenameva( fn, fmt, ap, NULL, NULL, NULL );\n        va_end( ap );\n\n\treturn( res );\n}\n\n/* Call an int-valued function, building a string arg. We expand env. \n * variables, but that's all.\n */\nint\ncalli_string( calli_string_fn fn, const char *arg, void *a, void *b, void *c )\n{\n\tchar buf[FILENAME_MAX];\n\n\texpand_variables( arg, buf );\n\n\treturn( fn( buf, a, b, c ) );\n}\n\nint\ncalli_stringva( calli_string_fn fn, \n\tconst char *fmt, va_list ap, void *a, void *b, void *c )\n{\n\tchar buf[FILENAME_MAX];\n\n        (void) im_vsnprintf( buf, FILENAME_MAX, fmt, ap );\n\n\treturn( calli_string( fn, buf, a, b, c ) );\n}\n\nint\ncalli_stringf( calli_string_fn fn, const char *fmt, ... )\n{\n\tva_list ap;\n\tint res;\n\n        va_start( ap, fmt );\n        res = calli_stringva( fn, fmt, ap, NULL, NULL, NULL );\n        va_end( ap );\n\n\treturn( res );\n}\n\n/* Call a function, building a filename arg. Nativize and absoluteize too.\n */\nint\ncalli_string_filename( calli_string_fn fn, \n\tconst char *filename, void *a, void *b, void *c )\n{\n\tchar buf[FILENAME_MAX];\n\n\texpand_variables( filename, buf );\n        nativeize_path( buf );\n\tabsoluteize_path( buf );\n\n\treturn( fn( buf, a, b, c ) );\n}\n\nint\ncalli_string_filenameva( calli_string_fn fn, \n\tconst char *fmt, va_list ap, void *a, void *b, void *c )\n{\n\tchar buf[FILENAME_MAX];\n\n        (void) im_vsnprintf( buf, FILENAME_MAX, fmt, ap );\n\n\treturn( calli_string_filename( fn, buf, a, b, c ) );\n}\n\nint\ncalli_string_filenamef( calli_string_fn fn, const char *fmt, ... )\n{\n\tva_list ap;\n\tint res;\n\n        va_start( ap, fmt );\n        res = calli_string_filenameva( fn, fmt, ap, NULL, NULL, NULL );\n        va_end( ap );\n\n\treturn( res );\n}\n\n/* Convert a filename to utf8 ... g_free the result.\n */\nchar *\nf2utf8( const char *filename )\n{\n\tchar *utf8;\n\n\tif( !(utf8 = g_filename_to_utf8( filename, -1, NULL, NULL, NULL )) ) \n\t\tutf8 = g_strdup( _( \"<charset conversion error>\" ) );\n\n\treturn( utf8 );\n}\n\nvoid\nsetenvf( const char *name, const char *fmt, ... )\n{\n\tva_list ap;\n\tchar buf[FILENAME_MAX];\n\n        va_start( ap, fmt );\n        (void) im_vsnprintf( buf, FILENAME_MAX, fmt, ap );\n        va_end( ap );\n\n\tg_setenv( name, buf, TRUE );\n}\n\nint\ncheck( const char *filename )\n{\n\t/* Need to work on filenames containing %.\n\t */\n\treturn( im_existsf( \"%s\", filename ) );\n}\n\n/* File exists? \n */\ngboolean\nexistsf( const char *name, ... )\n{\n\tva_list ap;\n\tgboolean res;\n\n        va_start( ap, name );\n        res = calli_string_filenameva( \n\t\t(calli_string_fn) check, name, ap, NULL, NULL, NULL );\n        va_end( ap );\n\n\treturn( res );\n}\n\nint\nisdir_sub( const char *filename )\n{\n\tstruct stat st;\n\n\t/* Read size and file/dir.\n\t */\n\tif( stat( filename, &st ) == -1 ) \n\t\treturn( FALSE );\n\tif( !S_ISDIR( st.st_mode ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\ngboolean\nisdir( const char *filename, ... )\n{\n\tva_list ap;\n\tgboolean res;\n\n        va_start( ap, filename );\n        res = calli_string_filenameva( \n\t\t(calli_string_fn) isdir_sub, filename, ap, NULL, NULL, NULL );\n        va_end( ap );\n\n\treturn( res );\n}\n\n\nstatic void *\nmtime_sub( const char *filename, time_t *time )\n{\n\tstruct stat st;\n\n\tif( stat( filename, &st ) == -1 )\n\t\treturn( NULL );\n#ifdef HAVE_GETEUID\n\tif( st.st_uid != geteuid() )\n\t\treturn( NULL );\n#endif /*HAVE_GETEUID*/\n\t*time = st.st_mtime;\n\n\treturn( NULL );\n}\n\ntime_t\nmtime( const char *filename, ... )\n{\n\tva_list ap;\n\ttime_t time;\n\n\ttime = 0;\n        va_start( ap, filename );\n        (void) callv_string_filenameva( \n\t\t(callv_string_fn) mtime_sub, filename, ap, &time, NULL, NULL );\n        va_end( ap );\n\n\treturn( time );\n}\n\ngboolean\nmkdirf( const char *name, ... )\n{\n\tva_list ap;\n\tgboolean res;\n\n        va_start( ap, name );\n        res = calli_string_filenameva( \n\t\t(calli_string_fn) g_mkdir, \n\t\t\tname, ap, GINT_TO_POINTER( 0755 ), NULL, NULL ) == 0;\n        va_end( ap );\n\n\treturn( res );\n}\n\n/* system(), with printf() args and $xxx expansion.\n */\nint\nsystemf( const char *fmt, ... )\n{\n\tva_list ap;\n\tint res;\n\n        va_start( ap, fmt );\n        res = calli_stringva( \n\t\t(calli_string_fn) system, fmt, ap, NULL, NULL, NULL );\n        va_end( ap );\n\n\treturn( res );\n}\n\ngboolean\ntouchf( const char *fmt, ... )\n{\n\tva_list ap;\n\tint fd;\n\n        va_start( ap, fmt );\n        fd = calli_string_filenameva( \n\t\t(calli_string_fn) creat, \n\t\t\tfmt, ap, GINT_TO_POINTER( S_IRUSR | S_IWUSR ), \n\t\t\t\tNULL, NULL );\n        va_end( ap );\n\t(void) close( fd );\n\n\treturn( fd != -1 );\n}\n\nint\nunlinkf( const char *fmt, ... )\n{\n\tva_list ap;\n\tint res;\n\n        va_start( ap, fmt );\n        res = calli_string_filenameva( \n\t\t(calli_string_fn) unlink, fmt, ap, NULL, NULL, NULL );\n        va_end( ap );\n\n\treturn( res );\n}\n\n/* Relative or absolute dir path? Have to expand env vars to see.\n */\ngboolean\nis_absolute( const char *fname )\n{\n\tchar buf[FILENAME_MAX];\n\n\texpand_variables( fname, buf );\n\tnativeize_path( buf );\n\n\t/* We can't use g_path_is_absolute(), we might be given a Windows path\n\t * including a drive specifier, and g_path_is_absolute() on unix does\n\t * not know about Windows paths.\n\t *\n\t * We should probably look out for whitespace.\n\t */\n\tif( buf[0] == '/' ||\n\t\t(buf[0] != '\\0' && buf[1] == ':') )\n\t\treturn( TRUE );\n\telse\n\t\treturn( FALSE );\n}\n\n/* OK filename? Ban ':' characters, they may confuse im_open(). Except on\n * winders :-(\n */\ngboolean\nis_valid_filename( const char *name )\n{\n\tconst char *p;\n\n\tif( strlen( name ) > FILENAME_MAX ) {\n\t\terror_top( _( \"Bad filename.\" ) );\n\t\terror_sub( _( \"Filename is too long.\" ) );\n\t\treturn( FALSE );\n\t}\n\tif( (p = im_skip_dir( name )) && \n\t\tstrspn( p, WHITESPACE ) == strlen( p ) ) {\n\t\terror_top( _( \"Bad filename.\" ) );\n\t\terror_sub( _( \"Filename contains only blank characters.\" ) );\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* im_strdup(), with NULL supplied.\n */\nchar *im_strdupn( const char *txt ) { return( im_strdup( NULL, txt ) ); }\n\n/* Free an iOpenFile.\n */\nvoid\nifile_close( iOpenFile *of )\n{\n\tIM_FREEF( fclose, of->fp );\n\tIM_FREE( of->fname );\n\tIM_FREE( of->fname_real );\n\tIM_FREE( of );\n}\n\n/* Make an iOpenFile*.\n */\nstatic iOpenFile *\nifile_build( const char *fname )\n{\n\tiOpenFile *of;\n\n\tif( !(of = INEW( NULL, iOpenFile )) )\n\t\treturn( NULL );\n\n\tof->fp = NULL;\n\tof->fname = NULL;\n\tof->fname_real = NULL;\n\tof->last_errno = 0;\n\n\tIM_SETSTR( of->fname, fname );\n\tif( !of->fname ) {\n\t\tifile_close( of );\n\t\treturn( NULL );\n\t}\n\n\treturn( of );\n}\n\n/* Find and open for read.\n */\niOpenFile *\nifile_open_read( const char *name, ... )\n{\n\tva_list ap;\n\tchar buf[FILENAME_MAX];\n\tiOpenFile *of;\n\n        va_start( ap, name );\n        (void) im_vsnprintf( buf, FILENAME_MAX, name, ap );\n        va_end( ap );\n        of = ifile_build( buf );\n\n\tif( !of )\n\t\treturn( NULL );\n\tif( !(of->fname_real = path_find_file( of->fname )) ) {\n\t\terror_top( _( \"Unable to open.\" ) );\n\t\terror_sub( _( \"Unable to open file \\\"%s\\\" for reading.\\n%s.\" ),\n\t\t\tof->fname, g_strerror( errno ) );\n\t\tifile_close( of );\n\t\treturn( NULL );\n\t}\n\n\tif( !(of->fp = (FILE *) callv_string_filename( (callv_string_fn) fopen, \n\t\tof->fname_real, \"r\", NULL, NULL )) ) {\n\t\terror_top( _( \"Unable to open.\" ) );\n\t\terror_sub( _( \"Unable to open file \\\"%s\\\" for reading.\\n%s.\" ),\n\t\t\tof->fname_real, g_strerror( errno ) );\n\t\tifile_close( of );\n\t\treturn( NULL );\n\t}\n\n\tof->read = TRUE;\n\n\treturn( of );\n}\n\n/* Open stdin for read.\n */\niOpenFile *\nifile_open_read_stdin()\n{\n\tiOpenFile *of;\n\n\tif( !(of = ifile_build( \"stdin\" )) )\n\t\treturn( NULL );\n\tIM_SETSTR( of->fname_real, of->fname );\n\tif( !of->fname_real ) {\n\t\tifile_close( of );\n\t\treturn( NULL );\n\t}\n\tof->fp = stdin;\n\tof->read = TRUE;\n\n\treturn( of );\n}\n\n/* Find and open for write.\n */\niOpenFile *\nifile_open_write( const char *name, ... )\n{\n\tva_list ap;\n\tchar buf[FILENAME_MAX];\n\tiOpenFile *of;\n\n        va_start( ap, name );\n        (void) im_vsnprintf( buf, FILENAME_MAX, name, ap );\n        va_end( ap );\n        of = ifile_build( buf );\n\n\tif( !of )\n\t\treturn( NULL );\n\tIM_SETSTR( of->fname_real, of->fname );\n\tif( !of->fname_real ) {\n\t\tifile_close( of );\n\t\treturn( NULL );\n\t}\n\tif( !(of->fp = (FILE *) callv_string_filename( (callv_string_fn) fopen,\n\t\tof->fname_real, \"w\", NULL, NULL )) ) {\n\t\terror_top( _( \"Unable to open.\" ) );\n\t\terror_sub( _( \"Unable to open file \\\"%s\\\" for writing.\\n%s.\" ),\n\t\t\tof->fname_real, g_strerror( errno ) );\n\t\tifile_close( of );\n\t\treturn( NULL );\n\t}\n\n\tof->read = FALSE;\n\n\treturn( of );\n}\n\n/* fprintf() to a file, checking result.\n */\ngboolean\nifile_write( iOpenFile *of, const char *fmt, ... )\n{\n\tva_list ap;\n\n        va_start( ap, fmt );\n\tif( vfprintf( of->fp, fmt, ap ) == EOF ) {\n\t\tof->last_errno = errno;\n\t\terror_top( _( \"Unable to write.\" ) );\n\t\terror_sub( _( \"Unable to write to file \\\"%s\\\".\\n%s.\" ),\n\t\t\tof->fname_real, g_strerror( of->last_errno ) );\n\t\treturn( FALSE );\n\t}\n        va_end( ap );\n\n\treturn( TRUE );\n}\n\n/* Save a string ... if non-NULL. Eg. \n *\tfred=\"boink!\"\n */\ngboolean\nifile_write_var( iOpenFile *of, const char *name, const char *value )\n{\n\tif( value )\n\t\treturn( ifile_write( of, \" %s=\\\"%s\\\"\", name, value ) );\n\t\n\treturn( TRUE );\n}\n\n/* Load up a file as a string.\n */\nchar *\nifile_read( iOpenFile *of )\n{\n\tlong len;\n\tsize_t len2;\n\tchar *str;\n\n\t/* Find length.\n\t */\n\tfseek( of->fp, 0L, 2 );\n\tlen = ftell( of->fp );\n\trewind( of->fp );\n\tif( len < 0 || len > 1024 * 1024 ) {\n\t\terror_top( _( \"Unable to read.\" ) );\n\t\terror_sub( _( \"File \\\"%s\\\" too large.\" ), of->fname_real );\n\t\treturn( NULL );\n\t}\n\n\t/* Allocate memory and fill.\n\t */\n\tif( !(str = imalloc( NULL, len + 1 )) ) \n\t\treturn( NULL );\n\n\t/* We can't check len2 against len, since we may be reading a text\n\t * file on Windows, in which case this fread will change CRLF to LF\n\t * and len2 will be less than len.\n\t */\n\tlen2 = fread( str, sizeof( char ), (size_t) len, of->fp );\n\n\tstr[len2] = '\\0';\n\n\treturn( str );\n}\n\n/* Load a file into a buffer. Useful for OpenFiles we can't seek in, like\n * stdin. \n */\nchar *\nifile_read_buffer( iOpenFile *of, char *buffer, size_t max )\n{\n\tsize_t len;\n\n\t/* -1 off max to leave space for the '\\0'.\n\t */\n\tlen = fread( buffer, sizeof( char ), max - 1, of->fp );\n\tif( !feof( of->fp ) ) {\n\t\t/* File too large for buffer.\n\t\t */\n\t\tof->last_errno = errno;\n\t\terror_top( _( \"Unable to read.\" ) );\n\t\terror_sub( _( \"Unable to read from file \\\"%s\\\".\\n%s.\" ),\n\t\t\tof->fname_real, g_strerror( of->last_errno ) );\n\t\treturn( NULL );\n\t}\n\tbuffer[len] = '\\0';\n\n\treturn( buffer );\n}\n\n/* Return '\\0' for EOF, -1 for error.\n */\nint\nifile_getc( iOpenFile *of )\n{\n\tint ch;\n\n\tch = fgetc( of->fp );\n\n\tif( ch == EOF && feof( of->fp ) )\n\t\treturn( 0 );\n\telse if( ch == EOF )\n\t\treturn( -1 );\n\telse \n\t\treturn( ch );\n}\n\noff_t\nstatf( const char *fmt, ... )\n{\n\tva_list ap;\n\tstruct stat st;\n\tint result;\n\n        va_start( ap, fmt );\n        result = calli_string_filenameva( \n\t\t(calli_string_fn) stat, fmt, ap, &st, NULL, NULL );\n        va_end( ap );\n\n\tif( result == -1 || S_ISDIR( st.st_mode ) )\n\t\treturn( 0 );\n\telse\n\t\treturn( st.st_size );\n}\n\nstatic void *\ndirectory_size_sub( const char *filename, double *total )\n{\n\t*total += statf( \"%s\", filename );\n\n\treturn( NULL );\n}\n\n/* Find the amount of 'stuff' in a directory. Result in bytes. Don't look in\n * sub-dirs.\n */\ndouble\ndirectory_size( const char *dirname )\n{\n\tdouble total;\n\n\ttotal = 0;\n\tpath_map_dir( dirname, \"*\",\n\t\t(path_map_fn) directory_size_sub, &total );\n\n\treturn( total );\n}\n\n/* Escape \"%\" characters in a string.\n */\nchar *\nescape_percent( const char *in, char *out, int len )\n{\n\tconst char *p;\n\tchar *q;\n\n\tfor( p = in, q = out; *p && q - out < len - 3; p++, q++ )\n\t\tif( *p == '%' ) {\n\t\t\tq[0] = '%';\n\t\t\tq[1] = '%';\n\t\t\tq++;\n\t\t}\n\t\telse\n\t\t\t*q = *p;\n\n\t*q = '\\0';\n\n\treturn( out );\n}\n\nchar *\nescape_markup( const char *in, char *out, int len )\n{\n\tconst char *p;\n\tchar *q;\n\n\tfor( p = in, q = out; *p && q - out < len - 5; p++, q++ )\n\t\tif( *p == '<' ) {\n\t\t\tstrcpy( q, \"&lt;\" );\n\t\t\tq += 3;\n\t\t}\n\t\telse if( *p == '>' ) {\n\t\t\tstrcpy( q, \"&gt;\" );\n\t\t\tq += 3;\n\t\t}\n\t\telse if( *p == '&' ) {\n\t\t\tstrcpy( q, \"&amp;\" );\n\t\t\tq += 4;\n\t\t}\n\t\telse\n\t\t\t*q = *p;\n\n\t*q = '\\0';\n\n\treturn( out );\n}\n\n/* VIPS filenames can have embedded modes. Mode strings are punctuated with\n * ',' and ':' chars. So strings in modes must have these chars escaped.\n */\nchar *\nescape_mode( const char *in, char *out, int len )\n{\n\tconst char *p;\n\tchar *q;\n\n\tfor( p = in, q = out; *p && q - out < len - 5; p++, q++ ) {\n\t\tif( *p == ':' || *p == ',' )\n\t\t\t*q++ = '\\\\';\n\n\t\t*q = *p;\n\t}\n\n\t*q = '\\0';\n\n\treturn( out );\n}\n\n/* Return a string of n characters. Buffer is zapped each time!\n */\nconst char *\nrpt( char ch, int n )\n{\n\tint i;\n\tstatic char buf[200];\n\n\tn = IM_MIN( 190, n );\n\n\tfor( i = 0; i < n; i++ )\n\t\tbuf[i] = ch;\n\tbuf[i] = '\\0';\n\n\treturn( buf );\n}\n\n/* Return a string of n spaces. Buffer is zapped each time!\n */\nconst char *\nspc( int n )\n{\n\treturn( rpt( ' ', n ) );\n}\n\n/* Like strtok(), but better. Give a string and a list of break characters;\n * write a '\\0' into the string over the first break character and return a\n * pointer to the next non-break character. If there are no break characters,\n * then return a pointer to the end of the string. If passed a pointer to an\n * empty string or NULL, then return NULL.\n */\nchar *\nbreak_token( char *str, const char *brk )\n{\n\tchar *p;\n\n\t/* Is the string empty? If yes, return NULL immediately.\n\t */\n\tif( !str || !*str )\n\t\treturn( NULL );\n\n\t/* Skip initial break characters.\n\t */\n\tp = str + strspn( str, brk );\n\n\t/* Search for the first break character after the token.\n\t */\n\tp += strcspn( p, brk );\n\n\t/* Is there string left?\n\t */\n\tif( *p ) {\n\t\t/* Write in an end-of-string mark and return the start of the\n\t\t * next token.\n\t\t */\n\t\t*p++ = '\\0';\n\t\tp += strspn( p, brk );\n\t}\n\t\n\treturn( p );\n}\n\n/* Turn a number to a string. 0 is \"A\", 1 is \"B\", 25 is \"Z\", 26 is \"AA\", 27 is\n * \"AB\", etc.\n */\nvoid\nnumber_to_string( int n, char *buf )\n{\n\tdo {\n\t\tint rem = n % 26;\n\n\t\t*buf++ = (char) (rem + (int) 'A');\n\t\tn /= 26;\n\t} while( n > 0 );\n\n\t*buf ='\\0';\n}\n\n/* Find the space remaining in a directory, in bytes. A double for >32bit\n * problem avoidance. <0 for error.\n */\n#ifdef HAVE_SYS_STATVFS_H\ndouble\nfind_space( const char *name )\n{\n\tstruct statvfs st;\n\tdouble sz;\n\n\tif( calli_string_filename( (calli_string_fn) statvfs, \n\t\t(gpointer) name, &st, NULL, NULL ) )\n\t\t/* Set to error value. \n\t\t */\n\t\tsz = -1;\n\telse\n\t\tsz = IM_MAX( 0, (double) st.f_frsize * st.f_bavail );\n\n\treturn( sz );\n}\n#elif (HAVE_SYS_VFS_H || HAVE_SYS_MOUNT_H)\ndouble\nfind_space( const char *name )\n{\n\tstruct statfs st;\n\tdouble sz;\n\n\tif( calli_string_filename( (calli_string_fn) statfs, \n\t\t(gpointer) name, &st, NULL, NULL ) )\n\t\tsz = -1;\n\telse\n\t\tsz = IM_MAX( 0, (double) st.f_bsize * st.f_bavail );\n\n\treturn( sz );\n}\n#elif defined OS_WIN32\ndouble\nfind_space( const char *name )\n{\n\tULARGE_INTEGER avail;\n\tULARGE_INTEGER total;\n\tULARGE_INTEGER free;\n\tdouble sz;\n\tchar name2[FILENAME_MAX];\n\n\texpand_variables( name, name2 );\n\n\t/* Truncate to just the drive letter.\n\t */\n\tif( name2[1] == ':' )\n\t\tname2[3] = 0;\n\n\tif( !GetDiskFreeSpaceEx( name2, &avail, &total, &free ) )\n\t\tsz = -1;\n\telse\n\t\tsz = IM_MAX( 0, (double) free.QuadPart );\n\n\treturn( sz );\n}\n#else\ndouble \nfind_space( const char *name )\n{\n\treturn( -1 );\n}\n#endif /*HAVE_SYS_STATVFS_H*/\n\n/* Make a name for a temp file. Add the specified extension.\n */\ngboolean\ntemp_name( char *name, const char *type )\n{\n\t/* Some mkstemp() require files to actually exist before they don't\n\t * reuse the filename :-( add an extra field.\n\t */\n\tstatic int n = 0;\n\n\tconst char *dir;\n\tint fd;\n\tchar buf[FILENAME_MAX];\n\n\tdir = PATH_TMP;\n\tif( !existsf( \"%s\", dir ) )\n\t\tdir = G_DIR_SEPARATOR_S;\n\n\tim_snprintf( name, FILENAME_MAX, \"%s\" G_DIR_SEPARATOR_S \n\t\t\"untitled-\" PACKAGE \"-%d-XXXXXXX\", \n\t\tdir, n++ );\n\texpand_variables( name, buf );\n\n\tfd = g_mkstemp( buf );\n\tif( fd == -1 ) {\n\t\terror_top( _( \"Unable to create temporary file.\" ) );\n\t\terror_sub( _( \"Unable to make file \\\"%s\\\"\\n%s\" ),\n\t\t\tbuf, g_strerror( errno ) );\n\t\treturn( FALSE );\n\t}\n\tclose( fd );\n\tunlinkf( \"%s\", buf );\n\n\tim_snprintf( name, FILENAME_MAX, \"%s.%s\", buf, type );\n\n\treturn( TRUE );\n}\n\n/* Max/min of an area.\n */\nint\nfindmaxmin( IMAGE *in, \n\tint left, int top, int width, int height, double *min, double *max )\n{\n\tDOUBLEMASK *msk;\n\tIMAGE *t1;\n\n\tif( !(t1 = im_open( \"temp\", \"p\" )) )\n\t\treturn( -1 );\n\tif( im_extract_area( in, t1, left, top, width, height ) ||\n\t\t!(msk = im_stats( t1 )) )\n\t\treturn( -1 );\n\tim_close( t1 );\n\t\n\t*min = msk->coeff[0];\n\t*max = msk->coeff[1];\n\n\tim_free_dmask( msk );\n\n#ifdef DEBUG\n\tprintf( \"findmaxmin: left = %d, top = %d, width = %d, height = %d\\n\",\n\t\tleft, top, width, height );\n\tprintf( \"findmaxmin: max = %g, min = %g\\n\", *max, *min );\n#endif /*DEBUG*/\n\n\treturn( 0 );\n}\n\ngboolean\nchar_to_bool( char *str, void *out )\n{\t\n\tgboolean *t = (gboolean *) out;\n\t\n\tif( strcasecmp( \"TRUE\", str ) == 0 )\n\t\t*t = TRUE;\n\telse\n\t\t*t = FALSE;\n\t\n\treturn( TRUE );\n}\n\nchar *\nbool_to_char( gboolean b )\n{\t\n\tif( b )\n\t\treturn( \"true\" );\n\telse\n\t\treturn( \"false\" );\n}\n\n/* Increment a name ... strip any trailing numbers, add one, put numbers back.\n * Start at 1 if no number there. buf should be at least namelen chars. Keep\n * leading zeros, if any.\n */\nvoid\nincrement_name( char *buf )\n{\n\tchar *p;\n\tint n;\n\tchar fmt[256];\n\n\t/* If there's no number, p will point at the '\\0'.\n\t */\n        p = (char *) my_strrspn( buf, NUMERIC );\n\tif( *p ) {\n                n = atoi( p );\n\t\tim_snprintf( fmt, 256, \"%%0%dd\", (int) strlen( p ) );\n\t}\n\telse {\n\t\tstrcpy( fmt, \"%d\" );\n\t\tn = 0;\n\t}\n\n        im_snprintf( p, MAX_STRSIZE - (p - buf), fmt, n + 1 ); \n}\n\n/* Increment filename. Eg. \"/home/jim/fred_00_tn.tif\" becomes \n * \"/home/jim/fred_01_tn.tif\"\n */\nvoid\nincrement_filename( char *filename )\n{\n        char buf[FILENAME_MAX];\n        char suf[FILENAME_MAX];\n        char tail[FILENAME_MAX];\n        char *file, *p;\n\n\tim_strncpy( buf, filename, FILENAME_MAX );\n\n\t/* Save and replace the suffix around an increment_name.\n\t */\n\tfile = (char *) im_skip_dir( buf );\n\tif( !(p = strrchr( file, '.' )) )\n\t\tp = file + strlen( file );\n\tim_strncpy( suf, p, FILENAME_MAX );\n\t*p = '\\0';\n\n\t/* Also save any chars to the right of the number component (if any) of\n\t * the filename.\n\t */\n\tp = (char *) my_strrcspn( file, NUMERIC );\n\n\t/* No numbers there? Take nothing as the tail and put the number at\n\t * the end.\n\t */\n\tif( p == file ) \n\t\tp = file + strlen( file );\n\n\tim_strncpy( tail, p, FILENAME_MAX );\n\t*p = '\\0';\n\n\tincrement_name( buf );\n\n\tstrcpy( filename, buf );\n\tstrcat( filename, tail );\n\tstrcat( filename, suf );\n}\n\n/* Extract the first line of a string in to buf, extract no more than len\n * chars.\n */\nint\nextract_first_line( char *buf, char *str, int len )\n{\n        char *p;\n        int n;\n\n        /* Find next '\\n' or '\\0'.\n         */\n        if( (p = strchr( str, '\\n' )) )\n                n = p - str;\n        else\n                n = strlen( str );\n        n = IM_MIN( len - 1, n );\n        \n        /* Copy those characters and make sure we have a '\\0'.\n         */\n        strncpy( buf, str, n );\n        buf[n] = '\\0';\n\n        return( n );\n}\n\n/* Make a valid ip name from a filename. \n */\nvoid\nname_from_filename( const char *in, char *out )\n{\n\tconst char *p;\n\n\t/* Skip leading path prefix, and any non-alpha.\n\t * Don't use isalnum(), since we don't want leading digits.\n\t */\n\tp = im_skip_dir( in ); \n\twhile( *p && !(isalpha( *p ) || *p == '_') )\n\t\tp += 1;\n\n\tif( !*p )\n\t\tstrcpy( out, \"untitled\" );\n\telse {\n\t\tchar *q;\n\n\t\t/* Filter non-identifier chars. Stop at the first '.' \n\t\t * character, so we don't get the suffix in there too.\n\t\t */\n\t\tfor( q = out; *p && *p != '.'; p++ )\n\t\t\tif( isalnum( *p ) || *p == '_' || *p == '\\'' )\n\t\t\t\t*q++ = *p;\n\t\t*q = '\\0';\n\t}\n}\n\n/* Do any leak checking we can.\n */\nvoid\nutil_check_all_destroyed( void )\n{\n\tif( rect_n_rects )\n\t\tprintf( \"rect_n_rects == %d\\n\", rect_n_rects );\n}\n\n/* Like im_malloc(), but set our error stuff.\n */\nvoid *\nimalloc( IMAGE *im, size_t len )\n{\n\tvoid *mem;\n\n\tif( !(mem = im_malloc( im, len )) ) {\n\t\tchar txt[256];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\tvips_buf_append_size( &buf, len );\n\t\terror_top( _( \"Out of memory.\" ) );\n\t\terror_sub( _( \"Request for %s of RAM triggered memory \"\n\t\t\t\"allocation failure.\" ), vips_buf_all( &buf ) );\n\t\terror_vips();\n\n\t\treturn( NULL );\n\t}\n\n\treturn( mem );\n}\n\n/* Add a filename to a recent list. If there are more than MAX_RECENT items,\n * drop the last one off. If this is a dupe, move it to the head of the list.\n */\nGSList *\nrecent_add( GSList *recent, const char *filename )\n{\n\tchar absolute[FILENAME_MAX];\n\tint n;\n\tGSList *p;\n\n\tim_strncpy( absolute, filename, FILENAME_MAX );\n\tabsoluteize_path( absolute );\n\n\tfor( p = recent; p; p = p->next ) {\n\t\tconst char *stored = p->data;\n\n\t\tif( strcmp( absolute, stored ) == 0 ) {\n\t\t\trecent = g_slist_remove( recent, stored );\n\t\t\trecent = g_slist_prepend( recent, (void *) stored );\n\n\t\t\treturn( recent );\n\t\t}\n\t}\n\n\trecent = g_slist_prepend( recent, g_strdup( absolute ) );\n\n\tif( (n = g_slist_length( recent )) > MAX_RECENT ) {\n\t\tconst char *item;\n\n\t\titem = g_slist_nth_data( recent, n - 1 );\n\t\trecent = g_slist_remove( recent, item );\n\t\tg_free( (char *) item );\n\t}\n\n\treturn( recent );\n}\n\nGSList *\nrecent_load( const char *filename )\n{\n\tiOpenFile *of;\n\tGSList *recent;\n\n\trecent = NULL;\n\n\tif( (of = ifile_open_read( \"%s\" G_DIR_SEPARATOR_S \"%s\", \n\t\tget_savedir(), filename )) ) {\n\t\tchar buf[256];\n\n\t\twhile( fgets( buf, 256, of->fp ) ) {\n\t\t\tint n;\n\n\t\t\tif( (n = strlen( buf )) > 0 ) {\n\t\t\t\tif( buf[n - 1] == '\\n' )\n\t\t\t\t\tbuf[n - 1] = '\\0';\n\t\t\t\trecent = recent_add( recent, buf );\n\t\t\t}\n\t\t}\n\n\t\tifile_close( of );\n\t}\n\n\treturn( recent );\n}\n\nvoid\nrecent_free( GSList *recent )\n{\n\tGSList *p;\n\n\tfor( p = recent; p; p = p->next ) {\n\t\tconst char *item = (const char *) p->data;\n\n\t\tg_free( (char *) item );\n\t}\n\n\tg_slist_free( recent );\n}\n\nstatic void *\nrecent_save_sub( const char *filename, GSList **old_recent )\n{\n\t*old_recent = recent_add( *old_recent, filename );\n\n\treturn( NULL );\n}\n\nstatic void *\nrecent_save_sub2( const char *filename, iOpenFile *of )\n{\n\tfprintf( of->fp, \"%s\\n\", filename );\n\n\treturn( NULL );\n}\n\nvoid\nrecent_save( GSList *recent, const char *filename )\n{\n\tiOpenFile *of;\n\tGSList *old_recent;\n\n\t/* If there are several nips running, we could be saving over a file\n\t * that's been modified since we loaded it. Try to make this less\n\t * awful by merging our recent list over the one in the file.\n\t */\n\told_recent = recent_load( filename );\n\tslist_map_rev( recent, \n\t\t(SListMapFn) recent_save_sub, &old_recent );\n\n\tif( (of = ifile_open_write( \"%s\" G_DIR_SEPARATOR_S \"%s\", \n\t\tget_savedir(), filename )) ) {\n\t\tslist_map_rev( old_recent,\n\t\t\t(SListMapFn) recent_save_sub2, of );\n\t\tifile_close( of );\n\t}\n\n\trecent_free( old_recent );\n}\n\n/* Return the name of the save dir we use ... eg. \"$HOME/.nip2-7.10.8\",\n * or maybe \"C:\\Documents and Settings\\john\\Application Data\"\n */\nconst char *\nget_savedir( void )\n{\n#ifdef OS_WIN32\n\t/* If APPDATA is not defined, default to HOME, we know that will\n\t * exist (since we make it if necessary in main()).\n\t */\n\tif( g_getenv( \"APPDATA\" ) && existsf( \"%s\", g_getenv( \"APPDATA\" ) ) )\n\t\treturn( \"$APPDATA\" G_DIR_SEPARATOR_S IP_NAME );\n\telse\n\t\treturn( \"$HOME\" G_DIR_SEPARATOR_S \".\" IP_NAME );\n#elif OS_DARWIN\n\t/* Darwin ... in ~/Library\n\t */\n\treturn( \"$HOME\" G_DIR_SEPARATOR_S \"Library\" G_DIR_SEPARATOR_S IP_NAME );\n#else \n\t/* *nix-style system .. .dot file in home area.\n\t */\n\treturn( \"$HOME\" G_DIR_SEPARATOR_S \".\" IP_NAME );\n#endif /*OS_WIN32*/\n}\n\n/* Turn an slist into a null-terminated array.\n */\nvoid **\nslist_to_array( GSList *list )\n{\n\tvoid **array;\n\tint i;\n\n\tarray = g_new( void *, g_slist_length( list ) + 1 );\n\tfor( i = 0; list ; list = list->next, i++ )\n\t\tarray[i] = list->data;\n\tarray[i] = NULL;\n\n\treturn( array );\n}\n\n/* Length of a NULL-terminated array.\n */\nint\narray_len( void **array )\n{\n\tint i;\n\n\tfor( i = 0; array[i]; i++ )\n\t\t;\n\n\treturn( i );\n}\n"
  },
  {
    "path": "src/util.h",
    "content": "/* Declarations for some basic util functions.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n/* chartype strings. Useful with break_token().\n */\n#define NUMERIC \"0123456789\"\n#define WHITESPACE \" \\t\\r\\b\\n\"\n\n/* Like IM_NEW() etc, but set ip's error buffer.\n */\n#define INEW(IM,A) ((A *)imalloc((IM),sizeof(A)))\n#define IARRAY(IM,N,T) ((T *)imalloc((IM),(N) * sizeof(T)))\n\n/* No nulls! Handy for printf() %s\n */\n#define NN( S ) ((S)?(S):\"(null)\")\n\n#define UNREF( X ) do { \\\n\tif( X ) { \\\n\t\tg_object_unref( G_OBJECT( X ) ); \\\n\t\t(X) = NULL; \\\n\t} \\\n} while( 0 )\n\n#define GOG_UNREF( X ) do { \\\n\tif( X ) { \\\n\t\tgog_object_clear_parent( GOG_OBJECT( X ) ); \\\n\t\tg_object_unref( G_OBJECT( X ) ); \\\n\t\t(X) = NULL; \\\n\t} \\\n} while( 0 )\n\n#define FREESID( SID, OBJ ) do { \\\n\tif( (SID) && (OBJ) ) { \\\n\t\tg_signal_handler_disconnect( (OBJ), (SID) ); \\\n\t\t(SID) = 0; \\\n\t} \\\n} while( 0 )\n\n/* Swap two pointers.\n */\n#define SWAPP( A, B ) { \\\n\tvoid *swapp_t; \\\n \t\\\n\tswapp_t = (A); \\\n\t(A) = (B); \\\n\t(B) = swapp_t; \\\n}\n\nvoid vips_buf_appendi( VipsBuf *buf, IMAGE *im );\ngboolean vips_buf_appendsc( VipsBuf *buf, gboolean quote, const char *str );\n\ngboolean set_prop( xmlNode *xnode, const char *name, const char *fmt, ... )\n\t__attribute__((format(printf, 3, 4)));\ngboolean set_sprop( xmlNode *xnode, const char *name, const char *value );\ngboolean set_iprop( xmlNode *xnode, const char *name, int value );\ngboolean set_dprop( xmlNode *xnode, const char *name, double value );\ngboolean set_slprop( xmlNode *xnode, const char *name, GSList *labels );\ngboolean set_dlprop( xmlNode *xnode, const char *name, double *values, int n );\n\ngboolean get_sprop( xmlNode *xnode, const char *name, char *buf, int sz );\ngboolean get_spropb( xmlNode *xnode, const char *name, VipsBuf *buf );\ngboolean get_iprop( xmlNode *xnode, const char *name, int *out );\ngboolean get_dprop( xmlNode *xnode, const char *name, double *out );\ngboolean get_bprop( xmlNode *xnode, const char *name, gboolean *out );\ngboolean get_slprop( xmlNode *xnode, const char *name, GSList **out );\ngboolean get_dlprop( xmlNode *xnode, const char *name, double **out );\n\nxmlNode *get_node( xmlNode *base, const char *name );\n\nRect *rect_dup( Rect *init );\nvoid *rect_free( Rect *rect );\n\n/* Like GFunc, but return a value.\n */\ntypedef gpointer (*SListMapFn)( gpointer, gpointer );\ntypedef gpointer (*SListMap2Fn)( gpointer, gpointer, gpointer );\ntypedef gpointer (*SListMap3Fn)( gpointer, gpointer, gpointer, gpointer );\ntypedef gpointer (*SListMap4Fn)( gpointer, gpointer, gpointer, gpointer,\n\tgpointer );\ntypedef gpointer (*SListMap5Fn)( gpointer, gpointer, gpointer, gpointer,\n\tgpointer, gpointer );\ntypedef gpointer (*SListFoldFn)( gpointer, gpointer, gpointer );\ntypedef gpointer (*SListFold2Fn)( gpointer, gpointer, gpointer, gpointer );\n\n/* Like foreach, but allow abandon.\n */\nvoid *slist_map( GSList *list, SListMapFn fn, gpointer a );\nvoid *slist_map2( GSList *list, SListMap2Fn fn, gpointer a, gpointer b );\nvoid *slist_map3( GSList *list, \n\tSListMap3Fn fn, gpointer a, gpointer b, gpointer c );\nvoid *slist_map4( GSList *list, \n\tSListMap4Fn fn, gpointer a, gpointer b, gpointer c, gpointer d );\nvoid *slist_map5( GSList *list, \n\tSListMap5Fn fn, gpointer a, gpointer b, gpointer c, gpointer d,\n\tgpointer e );\nvoid *slist_map_rev( GSList *list, SListMapFn fn, gpointer a );\nvoid *slist_map2_rev( GSList *list, \n\tSListMap2Fn fn, gpointer a, gpointer b );\nvoid *slist_map3_rev( GSList *list, \n\tSListMap3Fn fn, void *a, void *b, void *c );\nvoid *map_equal( void *a, void *b );\ngboolean slist_equal( GSList *l1, GSList *l2 );\nvoid *slist_fold( GSList *list, void *start, SListFoldFn fn, void *a );\nvoid *slist_fold2( GSList *list, \n\tvoid *start, SListFold2Fn fn, void *a, void *b );\nvoid slist_free_all( GSList *list );\nGSList *slist_remove_all( GSList *list, gpointer data );\n\n/* An slist, which tracks the end of the list, for fast append.\n */\ntypedef struct _Queue {\n\tGSList *list;\n\tGSList *tail;\n\tint length;\n} Queue;\n\nQueue *queue_new( void );\n\n/* All we need for now.\n */\nvoid *queue_head( Queue *queue );\nvoid queue_add( Queue *queue, void *data );\ngboolean queue_remove( Queue *q, void *data );\nint queue_length( Queue *q );\n\nextern VipsBuf error_top_buf;\nextern VipsBuf error_sub_buf;\n\nvoid error( const char *fmt, ... )\n\t__attribute__((noreturn, format(printf, 1, 2)));\nvoid error_block( void );\t\t/* Block updates to error_string */\nvoid error_unblock( void );\nvoid error_clear( void );\nvoid error_top( const char *fmt, ... )\n\t__attribute__((format(printf, 1, 2)));\nvoid error_sub( const char *fmt, ... )\n\t__attribute__((format(printf, 1, 2)));\nvoid error_vips( void );\nvoid error_vips_all( void );\nconst char *error_get_top( void );\nconst char *error_get_sub( void );\n\ngboolean is_postfix( const char *a, const char *b );\ngboolean is_prefix( const char *a, const char *b );\ngboolean is_caseprefix( const char *a, const char *b );\ngboolean is_casepostfix( const char *a, const char *b );\nconst char *findrightmost( const char *a, const char *b );\nchar *my_strcasestr( const char *haystack, const char *needle );\nvoid change_suffix( const char *name, char *out, \n\tconst char *new, const char **olds, int nolds );\n\nchar *my_strccpy( char *output, const char *input );\nchar *my_strecpy( char *output, const char *input, gboolean quote );\nconst char *my_strrspn( const char *p, const char *spn );\n\nchar *trim_nonalpha( char *text );\nchar *trim_white( char *text );\n\nvoid *get_element( REGION *ireg, int x, int y, int b );\n\nconst char *decode_bandfmt( int f );\nconst char *decode_type( int t );\n\nvoid get_image_info( VipsBuf *buf, const char *name );\n\nvoid expand_variables( const char *in, char *out );\nvoid nativeize_path( char *buf );\nvoid absoluteize_path( char *path );\nvoid canonicalize_path( char *path );\nconst char *get_vipshome( const char *argv0 );\n\ntypedef void *(*callv_string_fn)( const char *name, void *a, void *b, void *c );\n\nvoid *callv_string( callv_string_fn fn, \n\tconst char *name, void *a, void *b, void *c );\nvoid *callv_stringva( callv_string_fn fn, \n\tconst char *name, va_list ap, void *a, void *b, void *c );\nvoid *callv_stringf( callv_string_fn fn, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\n\nvoid *callv_string_filename( callv_string_fn fn, \n\tconst char *filename, void *a, void *b, void *c );\nvoid *callv_string_filenameva( callv_string_fn fn, \n\tconst char *name, va_list ap, void *a, void *b, void *c );\nvoid *callv_string_filenamef( callv_string_fn fn, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\n\ntypedef int (*calli_string_fn)( const char *name, void *a, void *b, void *c );\n\nint calli_string( calli_string_fn fn, \n\tconst char *name, void *a, void *b, void *c );\nint calli_stringva( calli_string_fn fn, \n\tconst char *name, va_list ap, void *a, void *b, void *c );\nint calli_stringf( calli_string_fn fn, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\n\nint calli_string_filename( calli_string_fn fn, \n\tconst char *filename, void *a, void *b, void *c );\nint calli_string_filenameva( calli_string_fn fn, \n\tconst char *name, va_list ap, void *a, void *b, void *c );\nint calli_string_filenamef( calli_string_fn fn, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\n\nchar *f2utf8( const char *filename );\n\nchar *im_strdupn( const char *str );\nvoid setenvf( const char *name, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\ngboolean existsf( const char *name, ... )\n\t__attribute__((format(printf, 1, 2)));\ngboolean isdir( const char *filename, ... )\n\t__attribute__((format(printf, 1, 2)));\ntime_t mtime( const char *filename, ... )\n\t__attribute__((format(printf, 1, 2)));\ngboolean mkdirf( const char *name, ... )\n\t__attribute__((format(printf, 1, 2)));\nint systemf( const char *fmt, ... )\n\t__attribute__((format(printf, 1, 2)));\nFILE *popenf( const char *fmt, const char *mode, ... )\n\t__attribute__((format(printf, 1, 3)));\ngboolean touchf( const char *fmt, ... )\n\t__attribute__((format(printf, 1, 2)));\nint unlinkf( const char *fmt, ... )\n\t__attribute__((format(printf, 1, 2)));\ngboolean is_absolute( const char *fname );\ngboolean is_valid_filename( const char *name );\n\n/* Text IO to/from files. Track the filename too, to help error messages.\n */\ntypedef struct _iOpenFile {\n\tFILE *fp;\t\n\tchar *fname;\t\t/* File we were passed to make this open_file */\n\tchar *fname_real;\t/* File we opened (maybe after search) */\n\tint last_errno;\t\t/* On error, last value for errno */\n\tgboolean read;\t\t/* True for open read, false for open write */\n} iOpenFile;\n\nvoid ifile_close( iOpenFile *of );\niOpenFile *ifile_open_read( const char *name, ... )\n\t__attribute__((format(printf, 1, 2)));\niOpenFile *ifile_open_read_stdin();\niOpenFile *ifile_open_write( const char *name, ... )\n\t__attribute__((format(printf, 1, 2)));\ngboolean ifile_write( iOpenFile *of, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\ngboolean ifile_write_var( iOpenFile *of, const char *name, const char *value );\nchar *ifile_read( iOpenFile *of );\nchar *ifile_read_buffer( iOpenFile *of, char *buffer, size_t len );\nint ifile_getc( iOpenFile *of );\n\ndouble directory_size( const char *dirname );\n\nchar *escape_percent( const char *in, char *out, int len );\nchar *escape_markup( const char *in, char *out, int len );\nchar *escape_mode( const char *in, char *out, int len );\nchar *break_token( char *str, const char *brk );\nconst char *rpt( char ch, int n );\nconst char *spc( int n );\nvoid number_to_string( int n, char *buf );\n\ndouble find_space( const char *name );\ngboolean temp_name( char *name, const char *ext );\nint findmaxmin( IMAGE *in, \n\tint left, int top, int width, int height, double *min, double *max );\n\ngboolean char_to_bool( char *str, void *out );\nchar *bool_to_char( gboolean b );\n\nvoid increment_name( char *buf );\nvoid increment_filename( char *filename );\n\nint extract_first_line( char *buf, char *str, int len );\n\nvoid name_from_filename( const char *in, char *out );\n\nvoid util_check_all_destroyed( void );\n\nvoid *imalloc( IMAGE *im, size_t len );\n\nGSList *recent_add( GSList *recent, const char *filename );\nGSList *recent_load( const char *filename );\nvoid recent_free( GSList *recent );\nvoid recent_save( GSList *recent, const char *filename );\n\nconst char *get_savedir( void );\n\nvoid **slist_to_array( GSList *list );\nint array_len( void **array );\n"
  },
  {
    "path": "src/value.c",
    "content": "/* an input value ... put/get methods\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ClassmodelClass *parent_class = NULL;\n\nstatic void\nvalue_finalize( GObject *gobject )\n{\n\tValue *value;\n\n#ifdef DEBUG\n\tprintf( \"value_finalize\\n\" );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_VALUE( gobject ) );\n\n\tvalue = VALUE( gobject );\n\n\t/* My instance finalize stuff.\n\t */\n\tvips_buf_destroy( &value->caption_buffer );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\n/* Default caption: just \"class-name class.value\".\n */\nstatic const char *\nvalue_generate_caption( iObject *iobject )\n{\n\tValue *value = VALUE( iobject );\n\tValueClass *value_class = VALUE_GET_CLASS( value );\n\tVipsBuf *buf = &value->caption_buffer;\n\n\tvips_buf_rewind( buf );\n\tif( !heapmodel_name( HEAPMODEL( value ), buf ) ) \n\t\tvips_buf_appends( buf, G_OBJECT_CLASS_NAME( value_class ) );\n\tvips_buf_appends( buf, \" \" );\n\theapmodel_value( HEAPMODEL( value ), buf );\n\n\treturn( vips_buf_all( buf ) );\n}\n\nstatic View *\nvalue_view_new( Model *model, View *parent )\n{\n\treturn( valueview_new() );\n}\n\nstatic void\nvalue_class_init( ValueClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\tgobject_class->finalize = value_finalize;\n\n\tiobject_class->generate_caption = value_generate_caption;\n\n\tmodel_class->view_new = value_view_new;\n}\n\nstatic void\nvalue_init( Value *value )\n{\n\tvips_buf_init_dynamic( &value->caption_buffer, MAX_LINELENGTH );\n}\n\nGType\nvalue_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( ValueClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) value_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Value ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) value_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_CLASSMODEL, \n\t\t\t\"Value\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/value.h",
    "content": "/* abstract base class for real/group/vector\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_VALUE (value_get_type())\n#define VALUE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_VALUE, Value ))\n#define VALUE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_VALUE, ValueClass))\n#define IS_VALUE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_VALUE ))\n#define IS_VALUE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_VALUE ))\n#define VALUE_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_VALUE, ValueClass ))\n\ntypedef struct _Value {\n\tClassmodel model;\n\n\t/* Build caption buffer here.\n\t */\n\tVipsBuf caption_buffer;\n} Value;\n\ntypedef struct _ValueClass {\n\tClassmodelClass parent_class;\n\n\t/* My methods.\n\t */\n} ValueClass;\n\nGType value_get_type( void );\n"
  },
  {
    "path": "src/valueview.c",
    "content": "/* display a minimal graphic for an object (just the caption)\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic GraphicviewClass *parent_class = NULL;\n\nstatic void \nvalueview_refresh( vObject *vobject )\n{\n\tValueview *valueview = VALUEVIEW( vobject );\n\tModel *model = MODEL( vobject->iobject );\n\n#ifdef DEBUG\n\tprintf( \"valueview_refresh: \" );\n\trow_name_print( HEAPMODEL( model )->row );\n\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\tset_gcaption( valueview->label, \"%s\", NN( IOBJECT( model )->caption ) );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\nvalueview_link( View *view, Model *model, View *parent )\n{\n\tValueview *valueview = VALUEVIEW( view );\n\tRowview *rview = ROWVIEW( parent->parent );\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\t(void) rowview_menu_attach( rview, valueview->eb );\n}\n\nstatic void\nvalueview_class_init( ValueviewClass *class )\n{\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tvobject_class->refresh = valueview_refresh;\n\n\tview_class->link = valueview_link;\n}\n\nstatic gboolean\nvalueview_event_cb( GtkWidget *widget, GdkEvent *ev, \n\tValueview *valueview )\n{\n\tModel *model = MODEL( VOBJECT( valueview )->iobject );\n\tRow *row = HEAPMODEL( model )->row;\n\n\tgboolean handled = FALSE;\n\n        switch( ev->type ) {\n        case GDK_BUTTON_PRESS:\n\t\tif( ev->button.button == 1 ) {\n\t\t\trow_select_modifier( row, ev->button.state );\n\t\t\thandled = TRUE;\n\t\t}\n\t\tbreak;\n\n        case GDK_2BUTTON_PRESS:\n\t\tif( ev->button.button == 1 ) {\n\t\t\tmodel_edit( widget, MODEL( model ) );\n\n\t\t\thandled = TRUE;\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn( handled );\n}\n\nstatic void\nvalueview_init( Valueview *valueview )\n{\n#ifdef DEBUG\n\tprintf( \"valueview_init\\n\" );\n#endif /*DEBUG*/\n\n        valueview->eb = gtk_event_box_new();\n\tgtk_widget_add_events( GTK_WIDGET( valueview->eb ), \n\t\tGDK_POINTER_MOTION_HINT_MASK ); \n        gtk_box_pack_start( GTK_BOX( valueview ), \n\t\tvalueview->eb, FALSE, FALSE, 0 );\n\tvalueview->label = gtk_label_new( \"\" );\n        gtk_misc_set_alignment( GTK_MISC( valueview->label ), 0, 0.5 );\n        gtk_misc_set_padding( GTK_MISC( valueview->label ), 2, 0 );\n        gtk_container_add( GTK_CONTAINER( valueview->eb ), valueview->label );\n\tgtk_widget_set_name( valueview->eb, \"caption_widget\" );\n        gtk_signal_connect( GTK_OBJECT( valueview->eb ), \"event\",\n                GTK_SIGNAL_FUNC( valueview_event_cb ), valueview );\n\n        gtk_widget_show_all( GTK_WIDGET( valueview->eb ) );\n}\n\nGtkType\nvalueview_get_type( void )\n{\n\tstatic GtkType valueview_type = 0;\n\n\tif( !valueview_type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Valueview\",\n\t\t\tsizeof( Valueview ),\n\t\t\tsizeof( ValueviewClass ),\n\t\t\t(GtkClassInitFunc) valueview_class_init,\n\t\t\t(GtkObjectInitFunc) valueview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tvalueview_type = gtk_type_unique( TYPE_GRAPHICVIEW, &info );\n\t}\n\n\treturn( valueview_type );\n}\n\nView *\nvalueview_new( void )\n{\n\tValueview *valueview = gtk_type_new( TYPE_VALUEVIEW );\n\n\treturn( VIEW( valueview ) );\n}\n"
  },
  {
    "path": "src/valueview.h",
    "content": "/* a basic view of a model ... just show the caption\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_VALUEVIEW (valueview_get_type())\n#define VALUEVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_VALUEVIEW, Valueview ))\n#define VALUEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_VALUEVIEW, ValueviewClass ))\n#define IS_VALUEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_VALUEVIEW ))\n#define IS_VALUEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_VALUEVIEW ))\n\ntypedef struct _Valueview {\n\tGraphicview parent_object;\n\n\tGtkWidget *eb;\n\tGtkWidget *label;\n} Valueview;\n\ntypedef struct _ValueviewClass {\n\tGraphicviewClass parent_class;\n\n\t/* My methods.\n\t */\n} ValueviewClass;\n\nGtkType valueview_get_type( void );\nView *valueview_new( void );\n"
  },
  {
    "path": "src/vector.c",
    "content": "/* display a vector\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ValueClass *parent_class = NULL;\n\nstatic void\nvector_class_init( VectorClass *class )\n{\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\nvector_init( Vector *vector )\n{\n\tiobject_set( IOBJECT( vector ), CLASS_VECTOR, NULL );\n}\n\nGType\nvector_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( VectorClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) vector_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Vector ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) vector_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_VALUE, \n\t\t\t\"Vector\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n"
  },
  {
    "path": "src/vector.h",
    "content": "/* a vector in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_VECTOR (vector_get_type())\n#define VECTOR( obj ) (GTK_CHECK_CAST( (obj), TYPE_VECTOR, Vector ))\n#define VECTOR_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_VECTOR, VectorClass ))\n#define IS_VECTOR( obj ) (GTK_CHECK_TYPE( (obj), TYPE_VECTOR ))\n#define IS_VECTOR_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_VECTOR ))\n\ntypedef struct _Vector {\n\tValue parent_object;\n\n} Vector;\n\ntypedef struct _VectorClass {\n\tValueClass parent_class;\n\n\t/* My methods.\n\t */\n} VectorClass;\n\nGType vector_get_type( void );\n"
  },
  {
    "path": "src/view.c",
    "content": "/* abstract base class for items which can form a row in a tally\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n#define DEBUG_VIEWCHILD\n */\n\n/* Time each refresh\n#define DEBUG_TIME\n */\n\n#include \"ip.h\"\n\nstatic vObjectClass *parent_class = NULL;\n\nstatic GSList *view_scannable = NULL;\n\nstatic GSList *view_resettable = NULL;\n\nvoid\nview_scannable_register( View *view )\n{\n\t/* Must have a scan method.\n\t */\n\tg_assert( VIEW_GET_CLASS( view )->scan );\n\n\tif( !view->scannable ) {\n\t\tview_scannable = g_slist_prepend( view_scannable, view );\n\t\tview->scannable = TRUE;\n\t}\n}\n\nvoid\nview_scannable_unregister( View *view )\n{\n\tif( view->scannable ) {\n\t\tview_scannable = g_slist_remove( view_scannable, view );\n\t\tview->scannable = FALSE;\n\t}\n}\n\ngboolean\nview_scan_all( void )\n{\n\tif( slist_map( view_scannable, (SListMapFn) view_scan, NULL ) )\n\t\treturn( FALSE );\n\n\tview_reset_all();\n\n\treturn( TRUE );\n}\n\nvoid\nview_resettable_register( View *view )\n{\n\t/* Must have a reset method.\n\t */\n\tg_assert( VIEW_GET_CLASS( view )->reset );\n\n\tif( !view->resettable ) {\n\t\tview_resettable = g_slist_prepend( view_resettable, view );\n\t\tview->resettable = TRUE;\n\t}\n}\n\nvoid\nview_resettable_unregister( View *view )\n{\n\tif( view->resettable ) {\n\t\tview_resettable = g_slist_remove( view_resettable, view );\n\t\tview->resettable = FALSE;\n\t}\n}\n\nvoid\nview_reset_all( void )\n{\n\t(void) slist_map( view_resettable, (SListMapFn) view_reset, NULL );\n}\n\n/* Should a viewchild be displayed? If model->display is true, also give the\n * enclosing view a chance to filter.\n */\nstatic gboolean\nview_viewchild_display( ViewChild *viewchild )\n{\n\tView *parent_view = viewchild->parent_view;\n\tModel *child_model = viewchild->child_model;\n\tViewClass *parent_view_class = VIEW_GET_CLASS( parent_view );\n\n\tif( child_model->display && parent_view_class->display )\n\t\treturn( parent_view_class->display( parent_view, \n\t\t\tchild_model ) );\n\n\treturn( child_model->display );\n}\n\n/* One of the children of the model we watch has changed ... create or destroy\n * the child view as required.\n */\nstatic void\nview_viewchild_changed( Model *model, ViewChild *viewchild )\n{\n\tgboolean display = view_viewchild_display( viewchild );\n\tView *child = viewchild->child_view;\n\n\tif( !display && child ) {\n#ifdef DEBUG_VIEWCHILD\n\t\tprintf( \"view_viewchild_changed: %s \\\"%s\\\", removing view\\n\", \n\t\t\tG_OBJECT_TYPE_NAME( model ), \n\t\t\tNN( IOBJECT( model )->name ) );\n\n\t\tprintf( \"view_viewchild_changed: %s\\n\", \n\t\t\tG_OBJECT_TYPE_NAME( child ) ); \n#endif /*DEBUG_VIEWCHILD*/\n\n\t\tDESTROY_GTK( child );\n\t}\n\telse if( display && !child ) {\n#ifdef DEBUG_VIEWCHILD\n\t\tprintf( \"view_viewchild_changed: %s \\\"%s\\\", adding view\\n\", \n\t\t\tG_OBJECT_TYPE_NAME( model ), \n\t\t\tNN( IOBJECT( model )->name ) );\n#endif /*DEBUG_VIEWCHILD*/\n\n\t\tmodel_view_new( model, viewchild->parent_view );\n\t}\n}\n\nstatic ViewChild *\nview_viewchild_new( View *parent_view, Model *child_model )\n{\n\tViewChild *viewchild;\n\n#ifdef DEBUG_VIEWCHILD\n\tprintf( \"view_viewchild_new: view \\\"%s\\\" watching %s \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( parent_view ), \n\t\tG_OBJECT_TYPE_NAME( child_model ), \n\t\tNN( IOBJECT( child_model )->name ) );\n#endif /*DEBUG_VIEWCHILD*/\n\n\tif( !(viewchild = INEW( NULL, ViewChild )) )\n\t\treturn( NULL );\n\n\tviewchild->parent_view = parent_view;\n\tviewchild->child_model = child_model;\n\tviewchild->child_model_changed_sid = \n\t\tg_signal_connect( child_model, \"changed\", \n\t\t\tG_CALLBACK( view_viewchild_changed ), viewchild );\n\tviewchild->child_view = NULL;\n\n\tparent_view->managed = \n\t\tg_slist_append( parent_view->managed, viewchild );\n\n\treturn( viewchild );\n}\n\nstatic void *\nview_viewchild_destroy( ViewChild *viewchild )\n{\n\tView *parent_view = viewchild->parent_view;\n\tView *child_view = viewchild->child_view;\n\n#ifdef DEBUG_VIEWCHILD\n\tprintf( \"view_viewchild_destroy: view %s watching model %s\\n\",\n\t\tG_OBJECT_TYPE_NAME( viewchild->parent_view ), \n\t\tG_OBJECT_TYPE_NAME( viewchild->child_model ) );\n#endif /*DEBUG_VIEWCHILD*/\n\n\tif( child_view ) { \n\t\tg_assert( child_view->parent == parent_view );\n\t\tchild_view->parent = NULL;\n\t}\n\tFREESID( viewchild->child_model_changed_sid, viewchild->child_model );\n\tparent_view->managed = \n\t\tg_slist_remove( parent_view->managed, viewchild );\n\n\tim_free( viewchild );\n\n\treturn( NULL );\n}\n\nstatic void *\nview_viewchild_test_child_model( ViewChild *viewchild, Model *child_model )\n{\n#ifdef DEBUG\n\tprintf( \"view_viewchild_test_child_model: model %s \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( child_model ), \n\t\tNN( IOBJECT( child_model )->name ) );\n#endif /*DEBUG*/\n\n\tif( viewchild->child_model == child_model )\n\t\treturn( viewchild );\n\n\treturn( NULL );\n}\n\n/* Do we have a model?\n */\ngboolean \nview_hasmodel( View *view ) \n{ \n\treturn( VOBJECT( view )->iobject != NULL ); \n}\n\nvoid *\nview_model_test( View *view, Model *model )\n{\n\tif( VOBJECT( view )->iobject == IOBJECT( model ) )\n\t\treturn( view );\n\n\treturn( NULL );\n}\n\n/* Link to enclosing model and view. \n */\nvoid \nview_link( View *view, Model *model, View *parent )\n{\n\tVIEW_GET_CLASS( view )->link( view, model, parent );\n}\n\n/* Add a child.\n */\nvoid\nview_child_add( View *parent, View *child )\n{\n\tVIEW_GET_CLASS( parent )->child_add( parent, child );\n}\n\n/* Remove a child.\n */\nvoid\nview_child_remove( View *child )\n{\n\tView *parent = child->parent;\n\n\tVIEW_GET_CLASS( parent )->child_remove( parent, child );\n}\n\n/* Child needs repositioning.\n */\nvoid\nview_child_position( View *child )\n{\n\tView *parent = child->parent;\n\n\tVIEW_GET_CLASS( parent )->child_position( parent, child );\n}\n\n/* Pop child to front of stacking order.\n */\nvoid\nview_child_front( View *child )\n{\n\tView *parent = child->parent;\n\n\tif( parent )\n\t\tVIEW_GET_CLASS( parent )->child_front( parent, child );\n}\n\n/* Break link to model. \n */\nvoid \nview_unlink( View *view )\n{\n\tg_assert( view != NULL );\n\tg_assert( VOBJECT( view )->iobject != NULL );\n\tg_assert( IS_VIEW( view ) && IS_MODEL( VOBJECT( view )->iobject ) );\n\n\tFREESID( view->pos_changed_sid, VOBJECT( view )->iobject );\n\tFREESID( view->scrollto_sid, VOBJECT( view )->iobject );\n\tFREESID( view->layout_sid, VOBJECT( view )->iobject );\n\tFREESID( view->reset_sid, VOBJECT( view )->iobject );\n\tFREESID( view->front_sid, VOBJECT( view )->iobject );\n\tFREESID( view->child_add_sid, VOBJECT( view )->iobject );\n\tFREESID( view->child_remove_sid, VOBJECT( view )->iobject );\n\tFREESID( view->child_detach_sid, VOBJECT( view )->iobject );\n\tFREESID( view->child_attach_sid, VOBJECT( view )->iobject );\n}\n\nstatic void\nview_destroy( GtkObject *object )\n{\n\tView *view;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_VIEW( object ) );\n\n\tview = VIEW( object );\n\n#ifdef DEBUG\n\tprintf( \"view_destroy: \\\"%s\\\"\\n\", G_OBJECT_TYPE_NAME( object ) );\n#endif /*DEBUG*/\n\n\t/* We're probably changing the size of our enclosing column.\n\t */\n\tview_resize( view );\n\n\tif( view->scannable )\n\t\tview_scannable_unregister( view );\n\tif( view->resettable )\n\t\tview_resettable_unregister( view );\n\n\tif( VOBJECT( view )->iobject )\n\t\tview_unlink( view );\n\n\tif( view->parent )\n\t\tview_child_remove( view );\n\n\tslist_map( view->managed,\n\t\t(SListMapFn) view_viewchild_destroy, NULL );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void \nview_finalize( GObject *gobject )\n{\n#ifdef DEBUG\n\tprintf( \"view_finalize: \\\"%s\\\"\\n\", G_OBJECT_TYPE_NAME( gobject ) );\n#endif /*DEBUG*/\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\n/* Called for model pos_changed signal ... queue a refresh. \n */\nstatic void\nview_model_pos_changed( Model *model, View *view )\n{\n        g_assert( IS_MODEL( model ) );\n        g_assert( IS_VIEW( view ) );\n\n#ifdef DEBUG\n        printf( \"view_model_pos_changed: %s %s \\\"%s\\\"\\n\",\n                G_OBJECT_TYPE_NAME( view ),\n                G_OBJECT_TYPE_NAME( model ),\n                NN( IOBJECT( model )->name ) );\n#endif /*DEBUG*/\n\n        vobject_refresh_queue( VOBJECT( view ) );\n}\n\n/* Called for model scrollto signal ... try scrolling.\n */\nstatic void\nview_model_scrollto( Model *model, ModelScrollPosition position, View *view )\n{\n\tg_assert( IS_MODEL( model ) );\n\tg_assert( IS_VIEW( view ) );\n\n#ifdef DEBUG\n\tprintf( \"view_model_scrollto: %s\\n\", IOBJECT( model )->name );\n#endif /*DEBUG*/\n\n\tview_scrollto( view, position );\n}\n\n/* Called for model layout signal ... try to lay out children.\n */\nstatic void\nview_model_layout( Model *model, View *view )\n{\n\tg_assert( IS_MODEL( model ) );\n\tg_assert( IS_VIEW( view ) );\n\n#ifdef DEBUG\n\tprintf( \"view_model_layout: %s\\n\", IOBJECT( model )->name );\n#endif /*DEBUG*/\n\n\tview_layout( view );\n}\n\n/* Called for model reset signal ... try resetting.\n */\nstatic void\nview_model_reset( Model *model, View *view )\n{\n\tg_assert( IS_MODEL( model ) );\n\tg_assert( IS_VIEW( view ) );\n\n#ifdef DEBUG\n\tprintf( \"view_model_reset: %s\\n\", IOBJECT( model )->name );\n#endif /*DEBUG*/\n\n\tview_reset( view );\n}\n\n/* Called for model front signal ... bring view to front.\n */\nstatic void\nview_model_front( Model *model, View *view )\n{\n\tg_assert( IS_MODEL( model ) );\n\tg_assert( IS_VIEW( view ) );\n\n#ifdef DEBUG\n\tprintf( \"view_model_front: model %s \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( model ), NN( IOBJECT( model )->name ) );\n\tprintf( \"\\tview %s\\n\", G_OBJECT_TYPE_NAME( view ) );\n#endif /*DEBUG*/\n\n\tview_child_front( view );\n}\n\n/* Called for model child_add signal ... start watching that child.\n */\nstatic void\nview_model_child_add( Model *parent, Model *child, int pos, View *parent_view )\n{\n\tViewChild *viewchild;\n\n#ifdef DEBUG\n\tprintf( \"view_model_child_add: parent %s \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ) );\n#endif /*DEBUG*/\n\n\tg_assert( IS_MODEL( parent ) );\n\tg_assert( IS_MODEL( child ) );\n\tg_assert( IS_VIEW( parent_view ) );\n\n#ifdef DEBUG\n\tviewchild = slist_map( parent_view->managed,\n\t\t(SListMapFn) view_viewchild_test_child_model, child );\n\tg_assert( !viewchild );\n#endif /*DEBUG*/\n\n\tviewchild = view_viewchild_new( parent_view, child ); \n\tview_viewchild_changed( child, viewchild );\n}\n\n/* Called for model child_remove signal ... stop watching that child. child\n * may have been finalized already.\n */\nstatic void\nview_model_child_remove( iContainer *parent, iContainer *child, \n\tView *parent_view )\n{\n\tViewChild *viewchild;\n\n#ifdef DEBUG\n{\n\tprintf( \"view_model_child_remove: child %s \\\"%s\\\"; \"\n\t\t\"parent %s \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( child ), NN( IOBJECT( child )->name ),\n\t\tG_OBJECT_TYPE_NAME( parent ), NN( IOBJECT( parent )->name ) );\n\n\tprintf( \"view_model_child_remove: parent_view = view of %s \\\"%s\\\"\\n\",\n\t\tG_OBJECT_TYPE_NAME( VOBJECT( parent_view )->iobject ), \n\t\tNN( IOBJECT( VOBJECT( parent_view )->iobject )->name ) );\n}\n#endif /*DEBUG*/\n\n\tviewchild = slist_map( parent_view->managed,\n\t\t(SListMapFn) view_viewchild_test_child_model, child );\n\n\tg_assert( viewchild );\n\n\t(void) view_viewchild_destroy( viewchild ); \n}\n\n/* Called for model parent_detach signal ... remove the viewchild for this\n * child. child_attach will build a new one. \n */\nstatic void\nview_model_child_detach( iContainer *old_parent, iContainer *child, \n\tView *old_parent_view )\n{\n\tViewChild *viewchild;\n\n#ifdef DEBUG\n{\n\tprintf( \"view_model_child_detach: child %s \\\"%s\\\"; \"\n\t\t\"old_parent %s \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( child ), \n\t\tNN( IOBJECT( child )->name ),\n\t\tG_OBJECT_TYPE_NAME( old_parent ), \n\t\tNN( IOBJECT( old_parent )->name ) );\n\n\tprintf( \"view_model_child_detach: old_parent_view = \"\n\t\t\t\"view of %s \\\"%s\\\"\\n\",\n\t\tG_OBJECT_TYPE_NAME( VOBJECT( old_parent_view )->iobject ), \n\t\tNN( IOBJECT( VOBJECT( old_parent_view )->iobject )->name ) );\n}\n#endif /*DEBUG*/\n\n\tviewchild = slist_map( old_parent_view->managed,\n\t\t(SListMapFn) view_viewchild_test_child_model, child );\n\n\tg_assert( viewchild );\n\tg_assert( !child->temp_view );\n\n\tchild->temp_view = viewchild->child_view;\n\n\t(void) view_viewchild_destroy( viewchild ); \n}\n\n/* Called for model child_attach signal ... make a new viewchild on the new\n * parent view.\n */\nstatic void\nview_model_child_attach( iContainer *new_parent, iContainer *child, int pos,\n\tView *new_parent_view )\n{\n\tViewChild *viewchild;\n\n\tg_assert( !slist_map( new_parent_view->managed,\n\t\t(SListMapFn) view_viewchild_test_child_model, child ) ); \n\n\tviewchild = view_viewchild_new( new_parent_view, MODEL( child ) ); \n\n\tg_assert( child->temp_view && IS_VIEW( child->temp_view ) );\n\tviewchild->child_view = child->temp_view;\n\tchild->temp_view = NULL;\n\n\tviewchild->child_view->parent = new_parent_view;\n}\n\nstatic void *\nview_real_link_sub( Model *child_model, View *parent_view )\n{\n\tViewChild *viewchild;\n\n\tviewchild = view_viewchild_new( parent_view, child_model ); \n\tview_viewchild_changed( child_model, viewchild );\n\n\treturn( NULL );\n}\n\n/* Link to model and to enclosing view. \n */\nstatic void \nview_real_link( View *view, Model *model, View *parent_view )\n{\n\tg_assert( view != NULL );\n\tg_assert( IS_VIEW( view ) && IS_MODEL( model ) );\n\tg_assert( !VOBJECT( view )->iobject );\n\n#ifdef DEBUG\n\tprintf( \"view_real_link: linking %s to model %s \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( view ), \n\t\tG_OBJECT_TYPE_NAME( model ), NN( IOBJECT( model )->name ) );\n#endif /*DEBUG*/\n\n\tvobject_link( VOBJECT( view ), IOBJECT( model ) );\n\tif( parent_view )\n\t\tview_child_add( parent_view, view );\n\n\tview->pos_changed_sid = g_signal_connect( model, \"pos_changed\", \n\t\tG_CALLBACK( view_model_pos_changed ), view );\n\tview->scrollto_sid = g_signal_connect( model, \"scrollto\", \n\t\tG_CALLBACK( view_model_scrollto ), view );\n\tview->layout_sid = g_signal_connect( model, \"layout\", \n\t\tG_CALLBACK( view_model_layout ), view );\n\tview->reset_sid = g_signal_connect( model, \"reset\", \n\t\tG_CALLBACK( view_model_reset ), view );\n\tview->front_sid = g_signal_connect( model, \"front\", \n\t\tG_CALLBACK( view_model_front ), view );\n\tview->child_add_sid = g_signal_connect( model, \"child_add\", \n\t\tG_CALLBACK( view_model_child_add ), view );\n\tview->child_remove_sid = g_signal_connect( model, \"child_remove\", \n\t\tG_CALLBACK( view_model_child_remove ), view );\n\tview->child_detach_sid = g_signal_connect( model, \"child_detach\", \n\t\tG_CALLBACK( view_model_child_detach ), view );\n\tview->child_attach_sid = g_signal_connect( model, \"child_attach\", \n\t\tG_CALLBACK( view_model_child_attach ), view );\n\n\ticontainer_map( ICONTAINER( model ),\n\t\t(icontainer_map_fn) view_real_link_sub, view, NULL );\n\n\tgtk_widget_show( GTK_WIDGET( view ) );\n}\n\nstatic void\nview_real_child_add( View *parent, View *child )\n{\n\tViewChild *viewchild;\n\n\tg_assert( IS_VIEW( parent ) && IS_VIEW( child ) );\n\tg_assert( child->parent == NULL );\n\n#ifdef DEBUG\n\tprintf( \"view_real_child_add: parent %p %s, child %p %s\\n\", \n\t\tparent,\n\t\tG_OBJECT_TYPE_NAME( parent ), \n\t\tchild,\n\t\tG_OBJECT_TYPE_NAME( child ) );\n#endif /*DEBUG*/\n\n\tviewchild = slist_map( parent->managed,\n\t\t(SListMapFn) view_viewchild_test_child_model, \n\t\tVOBJECT( child)->iobject );\n\n\tg_assert( viewchild );\n\tg_assert( viewchild->child_view == NULL );\n\n\t/* Not all views are true widgets (ie. get _ref()'s and _sink()'d by a\n\t * parent in gtk_container()). Ref and sink ourselves to ensure that\n\t * even these odd views get unfloated. See also\n\t * view_real_child_remove(). Affects the tool/toolkit views, and\n\t * rowview at least.\n\t */\n\tchild->parent = parent;\n\tviewchild->child_view = child;\n\tg_object_ref( GTK_OBJECT( child ) );\n\tgtk_object_sink( GTK_OBJECT( child ) );\n}\n\nstatic void\nview_real_child_remove( View *parent, View *child )\n{\n\tViewChild *viewchild;\n\n#ifdef DEBUG\n\tprintf( \"view_real_child_remove: parent %s, child %s\\n\", \n\t\tG_OBJECT_TYPE_NAME( parent ), G_OBJECT_TYPE_NAME( child ) );\n#endif /*DEBUG*/\n\n\tviewchild = slist_map( parent->managed,\n\t\t(SListMapFn) view_viewchild_test_child_model, \n\t\tVOBJECT( child )->iobject );\n\n\t/* Can have floating views which are not part of the viewchild system.\n\t */\n\tif( viewchild &&\n\t\tviewchild->child_view == child ) { \n\t\tviewchild->child_view = NULL;\n\t\tg_object_unref( G_OBJECT( child ) );\n\t}\n\n\tchild->parent = NULL;\n}\n\nstatic void\nview_real_child_position( View *parent, View *child )\n{\n}\n\nstatic void\nview_real_child_front( View *parent, View *child )\n{\n}\n\nstatic void \nview_real_reset( View *view )\n{\n\tview_resettable_unregister( view );\n}\n\nstatic void *\nview_real_scan( View *view )\n{\n\tModel *model = MODEL( VOBJECT( view )->iobject );\n\tHeapmodel *heapmodel;\n\n\tview_scannable_unregister( view );\n\n\t/* If we've changed something in this model, mark it for recomp.\n\t */\n\tif( model && IS_HEAPMODEL( model ) && \n\t\t(heapmodel = HEAPMODEL( model ))->modified && \n\t\theapmodel->row ) {\n\t\tExpr *expr = heapmodel->row->expr;\n\n\t\tif( expr )\n\t\t\t(void) expr_dirty( expr, link_serial_new() );\n\t}\n\n\treturn( NULL );\n}\n\nstatic void\nview_class_init( ViewClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tGtkObjectClass *object_class = (GtkObjectClass*) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = view_finalize;\n\n\tobject_class->destroy = view_destroy;\n\n\t/* Create signals.\n\t */\n\n\t/* Init default methods.\n\t */\n\tclass->link = view_real_link;\n\tclass->child_add = view_real_child_add;\n\tclass->child_remove = view_real_child_remove;\n\tclass->child_position = view_real_child_position;\n\tclass->child_front = view_real_child_front;\n\tclass->display = NULL;\n\n\tclass->reset = view_real_reset;\n\tclass->scan = view_real_scan;\n\tclass->scrollto = NULL;\n\tclass->layout = NULL;\n}\n\nstatic void\nview_init( View *view )\n{\n\t/* Init our instance fields.\n\t */\n\tview->pos_changed_sid = 0;\n\tview->scrollto_sid = 0;\n\tview->layout_sid = 0;\n\tview->reset_sid = 0;\n\tview->front_sid = 0;\n\tview->child_add_sid = 0;\n\tview->child_remove_sid = 0;\n\tview->child_detach_sid = 0;\n\tview->child_attach_sid = 0;\n\n\tview->parent = NULL;\n\n\tview->scannable = FALSE;\n\tview->resettable = FALSE;\n}\n\nGtkType\nview_get_type( void )\n{\n\tstatic GtkType view_type = 0;\n\n\tif( !view_type ) {\n\t\tstatic const GtkTypeInfo view_info = {\n\t\t\t\"View\",\n\t\t\tsizeof( View ),\n\t\t\tsizeof( ViewClass ),\n\t\t\t(GtkClassInitFunc) view_class_init,\n\t\t\t(GtkObjectInitFunc) view_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tview_type = gtk_type_unique( TYPE_VOBJECT, &view_info );\n\t}\n\n\treturn( view_type );\n}\n\n/* Trigger the reset method for a view.\n */\nvoid *\nview_reset( View *view )\n{\n\tViewClass *view_class = VIEW_GET_CLASS( view );\n\n\tif( view_class->reset )\n\t\tview_class->reset( view );\n\n\treturn( NULL );\n}\n\n/* Trigger the scan method for a view.\n */\nvoid *\nview_scan( View *view )\n{\n\tViewClass *view_class = VIEW_GET_CLASS( view );\n\n\tif( view_class->scan )\n\t\treturn( view_class->scan( view ) );\n\n\treturn( NULL );\n}\n\n/* Trigger the scrollto method for a view.\n */\nvoid *\nview_scrollto( View *view, ModelScrollPosition position )\n{\n\tViewClass *view_class = VIEW_GET_CLASS( view );\n\n\tif( view_class->scrollto )\n\t\tview_class->scrollto( view, position );\n\n\treturn( NULL );\n}\n\n/* Trigger the layout method for a view.\n */\nvoid *\nview_layout( View *view )\n{\n\tViewClass *view_class = VIEW_GET_CLASS( view );\n\n\tif( view_class->layout )\n\t\tview_class->layout( view );\n\n\treturn( NULL );\n}\n\nstatic void *\nview_map_sub( ViewChild *viewchild, view_map_fn fn, void *a, void *b )\n{\n\tif( viewchild->child_view )\n\t\treturn( fn( viewchild->child_view, a, b ) );\n\t\n\treturn( NULL );\n}\n\n/* Map over a view's children.\n */\nvoid *\nview_map( View *view, view_map_fn fn, void *a, void *b )\n{\n\treturn( slist_map3( view->managed, \n\t\t(SListMap3Fn) view_map_sub, (void *) fn, a, b ) );\n}\n\n/* Apply a function to view, and to all it's children.\n */\nvoid *\nview_map_all( View *view, view_map_fn fn, void *a )\n{\n\tView *result;\n\n\tif( (result = fn( view, a, NULL )) )\n\t\treturn( result );\n\n\treturn( view_map( view, \n\t\t(view_map_fn) view_map_all, (void *) fn, a ) );\n}\n\nvoid\nview_save_as_cb( GtkWidget *menu, GtkWidget *host, View *view )\n{\n\tModel *model = MODEL( VOBJECT( view )->iobject );\n\n\tif( IS_FILEMODEL( model ) ) {\n\t\tiWindow *iwnd = IWINDOW( view_get_toplevel( view ) );\n\n\t\tfilemodel_inter_saveas( iwnd, FILEMODEL( model ) );\n\t}\n}\n\nvoid\nview_save_cb( GtkWidget *menu, GtkWidget *host, View *view )\n{\n\tModel *model = MODEL( VOBJECT( view )->iobject );\n\n\tif( IS_FILEMODEL( model ) ) {\n\t\tiWindow *iwnd = IWINDOW( view_get_toplevel( view ) );\n\n\t\tfilemodel_inter_save( iwnd, FILEMODEL( model ) );\n\t}\n}\n\nvoid\nview_close_cb( GtkWidget *menu, GtkWidget *host, View *view )\n{\n\tModel *model = MODEL( VOBJECT( view )->iobject );\n\n\tif( IS_FILEMODEL( model ) ) {\n\t\tiWindow *iwnd = IWINDOW( view_get_toplevel( view ) );\n\n\t\tfilemodel_inter_savenclose( iwnd, FILEMODEL( model ) );\n\t}\n}\n\n/* Callback for \"activate\" on a view.\n */\nvoid\nview_activate_cb( View *view )\n{\n\tview_scannable_register( view );\n\tsymbol_recalculate_all();\n}\n\n/* Callback for \"changed\" on a view.\n */\nvoid \nview_changed_cb( View *view )\n{\n\t/* Make sure it's on the scannable list.\n\t */\n\tview_scannable_register( view );\n}\n\nvoid\nview_not_implemented_cb( GtkWidget *menu, GtkWidget *host, View *view )\n{\n\terror_top( _( \"Not implemented.\" ) );\n\tiwindow_alert( GTK_WIDGET( view ), GTK_MESSAGE_ERROR );\n}\n\nGtkWidget *\nview_get_toplevel( View *view )\n{\n\twhile( IS_VIEW( view ) && view->parent )\n\t\tview = view->parent;\n\n\treturn( gtk_widget_get_toplevel( GTK_WIDGET( view ) ) );\n}\n\nColumnview *\nview_get_columnview( View *child )\n{\n\tView *view;\n\n\tfor( view = child; view && !IS_COLUMNVIEW( view ); view = view->parent )\n\t\t;\n\n\tif( !view )\n\t\treturn( NULL );\n\n\treturn( COLUMNVIEW( view ) );\n}\n\n/* A view has changed size ... rethink the enclosing column geo. Helps table\n * to not break.\n */\nvoid *\nview_resize( View *view )\n{\n\tColumnview *cview = view_get_columnview( view );\n\n\tif( cview )\n\t\tgtk_widget_queue_resize( GTK_WIDGET( cview ) );\n\n\treturn( NULL );\n}\n"
  },
  {
    "path": "src/view.h",
    "content": "/* abstract base class for our UI widgets\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_VIEW (view_get_type())\n#define VIEW( obj ) (GTK_CHECK_CAST( (obj), TYPE_VIEW, View ))\n#define VIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_VIEW, ViewClass ))\n#define IS_VIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_VIEW ))\n#define IS_VIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_VIEW ))\n#define VIEW_GET_CLASS( obj ) \\\n\t(GTK_CHECK_GET_CLASS( (obj), TYPE_VIEW, ViewClass ))\n\n/* We track all of the children of our model, listening to \"changed\", so we\n * can lazily add or remove child views of us as the model requests.\n */\ntypedef struct {\n\tView *parent_view;\t\t/* Us */\n\tModel *child_model;\t\t/* The child we are watching */\n\tguint child_model_changed_sid;\t/* Listen to \"changed\" on child here */\n\tView *child_view;\t\t/* The child view for this model */\n} ViewChild;\n\nstruct _View {\n\tvObject parent_object;\n\n\t/* My instance vars.\n\t */\n\tguint pos_changed_sid;\t\t/* Signals we use to watch iObject */\n\tguint scrollto_sid;\n\tguint layout_sid;\n\tguint front_sid;\n\tguint reset_sid;\n\tguint child_add_sid;\n\tguint child_remove_sid;\n\tguint child_detach_sid;\n\tguint child_attach_sid;\n\n\tView *parent;\t\t\t/* Enclosing view (if any) */\n\tGSList *managed;\t\t/* List of ViewChild for us */\n\n\tgboolean scannable;\t\t/* On scannable list */\n\tgboolean resettable;\t\t/* On resettable list */\n};\n\ntypedef struct _ViewClass {\n\tvObjectClass parent_class;\n\n\t/* Create/destroy\n\n\t\tlink \t\tthis view is about to be linked to this model\n\t\t\t\twith this parent view\n\n\t\tchild_add\tthis view has just gained a child \n\n\t\tchild_remove\tthis view is about to lose a child \n\n\t\tchild_position\tthis child needs repositioning\n\n\t\tchild_front\tpop this child to the front\n\n\t\tdisplay\t\tshould this child be displayed\n\t\n\t */\n\n\tvoid (*link)( View *, Model *, View * );\n\tvoid (*child_add)( View *parent, View *child );\n\tvoid (*child_remove)( View *parent, View *child );\n\tvoid (*child_position)( View *parent, View *child );\n\tvoid (*child_front)( View *parent, View *child );\n\tgboolean (*display)( View *parent, Model *child );\n\n\t/* State change\n\n\t\treset\t\treset edit mode ... eg. text pops back to \n\t\t\t\tvalue display\n\n\t\tscan\t\tscan widgets, reading any new text off the\n\t\t\t\tdisplay\n\n\t\tscrollto\ttry to make this view visible\n\n\t\tlayout\t\ttry to lay children out\n\n\t */\n\tvoid (*reset)( View * );\n\tvoid *(*scan)( View * );\t\n\tvoid (*scrollto)( View *, ModelScrollPosition );\n\tvoid (*layout)( View * );\n} ViewClass;\n\nvoid view_scannable_register( View *view );\nvoid view_scannable_unregister( View *view );\ngboolean view_scan_all( void );\n\nvoid view_resettable_register( View *view );\nvoid view_resettable_unregister( View *view );\nvoid view_reset_all( void );\n\ngboolean view_hasmodel( View *view );\nvoid *view_model_test( View *child, Model *model );\n\nGtkType view_get_type( void );\n\nvoid view_link( View *view, Model *model, View *parent );\nvoid view_unlink( View *view );\nvoid view_child_add( View *parent, View *child );\nvoid view_child_remove( View *child );\nvoid view_child_position( View *child );\nvoid view_child_front( View *child );\n\nvoid *view_reset( View *view );\nvoid *view_scan( View *view );\nvoid *view_scrollto( View *view, ModelScrollPosition );\nvoid *view_layout( View *view );\n\nvoid *view_map( View *view, view_map_fn fn, void *a, void *b );\nvoid *view_map_all( View *view, view_map_fn fn, void *a );\n\nvoid view_save_as_cb( GtkWidget *menu, GtkWidget *host, View *view );\nvoid view_save_cb( GtkWidget *menu, GtkWidget *host, View *view );\nvoid view_close_cb( GtkWidget *menu, GtkWidget *host, View *view );\n\nvoid view_activate_cb( View *view );\nvoid view_changed_cb( View *view );\n\nvoid view_not_implemented_cb( GtkWidget *menu, GtkWidget *host, View *view );\n\nGtkWidget *view_get_toplevel( View *view );\n\nColumnview *view_get_columnview( View *child );\nvoid *view_resize( View *view );\n"
  },
  {
    "path": "src/vipsobject.c",
    "content": "/* Interface to VipsObject.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/*\n#define DEBUG\n */\n\n/* Maxiumum number of args to constructor.\n */\n#define MAX_VIPS_ARGS (100)\n\n/* What we track during construct.\n */\ntypedef struct _Vo {\n\t Reduce *rc;\n\n\t/* Object we are building.\n\t */\n\tVipsObject *object;\n\tconst char *name;\n\n\t/* Required args supplied to us from nip.\n\t */\n\tPElement args[MAX_VIPS_ARGS];\n\tint nargs_supplied;\n\n\t/* Number of required input args the object has.\n\t */\n\tint nargs_required;\n\n\t/* Number of output args the object has.\n\t */\n\tint nargs_output;\n\n\t/* A place to build the output, safe from the GC.\n\t */\n\tElement out;\n} Vo;\n\nstatic void\nvo_free( Vo *vo )\n{\n\theap_unregister_element( vo->rc->heap, &vo->out );\n\tVIPS_UNREF( vo->object );\n\n\tim_free( vo );\n}\n\nstatic Vo *\nvo_new( Reduce *rc, const char *name )\n{\n\tconst VipsObjectClass *class;\n\tVo *vo;\n\n\tif( !(class = vips_class_find( \"VipsObject\", name )) )\n\t\treturn( NULL );\n\n\tif( !(vo = INEW( NULL, Vo )) ) \n\t\treturn( NULL );\n\tvo->rc = rc;\n\tvo->object = g_object_new( G_OBJECT_CLASS_TYPE( class ), NULL );\n\tvo->name = class->nickname;\n\tvo->nargs_supplied = 0;\n\tvo->nargs_required = 0;\n\tvo->nargs_output = 0;\n\tvo->out.type = ELEMENT_NOVAL;\n\tvo->out.ele = (void *) 12;\n\n\theap_register_element( rc->heap, &vo->out );\n\n\treturn( vo );\n}\n\nstatic void *\nvo_gather_required( PElement *item, Vo *vo )\n{\n\tif( vo->nargs_supplied >= MAX_VIPS_ARGS ) {\n\t\terror_top( _( \"Too many arguments.\" ) );\n\t\terror_sub( _( \"No more than %d arguments allowed.\" ),\n\t\t\tMAX_VIPS_ARGS );\n\t\treturn( item );\n\t}\n\n\tvo->args[vo->nargs_supplied] = *item;\n\n\tvo->nargs_supplied += 1;\n\n\treturn( NULL );\n}\n\nstatic int\nvo_set_property( Vo *vo, \n\tconst char *name, GParamSpec *pspec, GValue *value )\n{\n\t/* If we're setting an enum from a string, look up the enum nickname.\n\t */\n\tif( G_IS_PARAM_SPEC_ENUM( pspec ) &&\n\t\tG_VALUE_TYPE( value ) == VIPS_TYPE_REF_STRING ) {\n\t\tconst char *str = vips_value_get_ref_string( value, NULL );\n\n\t\tif( vips_object_set_argument_from_string( vo->object, \n\t\t\tname, str ) )\n\t\t\treturn( -1 );\n\t}\n\telse\n\t\tg_object_set_property( G_OBJECT( vo->object ), name, value );\n\n\treturn( 0 );\n}\n\nstatic void *\nvo_set_required_input( VipsObject *object, GParamSpec *pspec,\n        VipsArgumentClass *argument_class, \n\tVipsArgumentInstance *argument_instance, Vo *vo )\n{\n\t/* Looking for required input args ... these are the ones we can set\n\t * from the supplied required list. \n\t */\n\tif( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&\n\t\t(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&\n\t\t(argument_class->flags & VIPS_ARGUMENT_INPUT) &&\n\t\t!argument_instance->assigned &&\n\t\tvo->nargs_required < vo->nargs_supplied ) {\n\t\tconst char *name = g_param_spec_get_name( pspec );\n\t\tint i = vo->nargs_required;\n\n\t\tGValue gvalue = { 0 };\n\n\t\tif( !heap_ip_to_gvalue( &vo->args[i], &gvalue ) )\n\t\t\treturn( object );\n\t\tif( vo_set_property( vo, name, pspec, &gvalue ) ) {\n\t\t\tg_value_unset( &gvalue );\n\t\t\treturn( object );\n\t\t}\n\t\tg_value_unset( &gvalue );\n\n\t\tvo->nargs_required += 1;\n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\nvo_set_optional_arg( const char *name, PElement *value, Vo *vo )\n{\n\tGParamSpec *pspec;\n\tVipsArgumentClass *argument_class;\n\tVipsArgumentInstance *argument_instance;\n\n\t/* Looking for construct-time optional input args.\n\t */\n\n\t/* For optional args, we should ignore properties that don't exist. For\n\t * example, we might supply ($sharpening => 12) to all interpolators,\n\t * though only one interpolator uses this property.\n\t */\n\tif( vips_object_get_argument( vo->object, name,\n\t\t&pspec, &argument_class, &argument_instance ) )\n\t\treturn( NULL );\n\n\tif( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&\n\t\t(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&\n\t\t(argument_class->flags & VIPS_ARGUMENT_INPUT) &&\n\t\t!argument_instance->assigned ) {\n\t\tGValue gvalue = { 0 };\n\n\t\tif( !heap_ip_to_gvalue( value, &gvalue ) ) {\n\t\t\tg_value_unset( &gvalue );\n\t\t\treturn( value );\n\t\t}\n\t\tif( vo_set_property( vo, name, pspec, &gvalue ) ) {\n\t\t\tg_value_unset( &gvalue );\n\t\t\treturn( value );\n\t\t}\n\t\tg_value_unset( &gvalue );\n\t}\n\n\treturn( NULL );\n}\n\n/* Set a set of optional args ... of the form [[\"caption\", 12], [\"label\", 42]]\n * etc.\n */\nstatic gboolean\nvo_set_optional( Vo *vo, PElement *optional )\n{\n\tif( heap_map_dict( optional,\n\t\t(heap_map_dict_fn) vo_set_optional_arg, vo, NULL ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Make a vo and supply args from nip2.\n */\nstatic gboolean\nvo_args( Vo *vo, PElement *required, PElement *optional )\n{\n\t/* Gather supplied required input args list.\n\t */\n\tif( heap_map_list( required, \n\t\t(heap_map_list_fn) vo_gather_required, vo, NULL ) ) \n\t\treturn( FALSE );\n\n\t/* Set required input arguments.\n\t */\n\tif( vips_argument_map( VIPS_OBJECT( vo->object ),\n\t\t(VipsArgumentMapFn) vo_set_required_input, vo, NULL ) ) \n\t\treturn( FALSE );\n\tif( vo->nargs_supplied != vo->nargs_required ) {\n\t\terror_top( _( \"Wrong number of required arguments.\" ) );\n\t\terror_sub( _( \"Operation \\\"%s\\\" has %d required arguments, \"\n\t\t\t\"you supplied %d.\" ),\n\t\t\tvo->name,\n\t\t\tvo->nargs_required,\n\t\t\tvo->nargs_supplied );\n\t\treturn( FALSE );\n\t}\n\n\t/* Set all optional input args.\n\t */\n\tif( !vo_set_optional( vo, optional ) ) \n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Make a VipsObject.\n */\nvoid\nvo_object_new( Reduce *rc, const char *name, \n\tPElement *required, PElement *optional, PElement *out )\n{\n\tVo *vo;\n\tManagedgobject *managedgobject;\n\n\tif( !(vo = vo_new( rc, name )) ) \n\t\treduce_throw( rc );\n\n\tif( !vo_args( vo, required, optional ) ) {\n\t\tvo_free( vo );\n\t\treduce_throw( rc );\n\t}\n\n\t/* Ask the object to construct.\n\t */\n\tif( vips_object_build( vo->object ) ) {\n\t\terror_top( _( \"VIPS library error.\" ) );\n\t\terror_sub( \"%s\", im_error_buffer() );\n\t\tim_error_clear();\n\t\tvo_free( vo );\n\t\treduce_throw( rc );\n\t}\n\n\t/* Return the constructed object.\n\t */\n\tif( !(managedgobject = managedgobject_new( vo->rc->heap, \n\t\tG_OBJECT( vo->object ) )) ) {\n\t\tvo_free( vo );\n\t\treduce_throw( rc );\n\t}\n\n\tPEPUTP( out, ELEMENT_MANAGED, managedgobject );\n\n#ifdef DEBUG\n{\n\tchar txt[1000];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tvips_object_to_string( vo->object, &buf );\n\tprintf( \"vo_object_new: built %s\\n\", vips_buf_all( &buf ) );\n}\n#endif /*DEBUG*/\n\n\tvo_free( vo );\n}\n\n/* Looking for required output args ... append to out.\n */\nstatic void *\nvo_get_required_output( VipsObject *object, GParamSpec *pspec,\n        VipsArgumentClass *argument_class, \n\tVipsArgumentInstance *argument_instance, Vo *vo, PElement *out )\n{\n\tif( (argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&\n\t\t(argument_class->flags & VIPS_ARGUMENT_OUTPUT) &&\n\t\targument_instance->assigned ) {\n\t\tconst char *name = g_param_spec_get_name( pspec );\n\t\tGType type = G_PARAM_SPEC_VALUE_TYPE( pspec );\n\t\tPElement lhs;\n\n\t\tGValue value = { 0 };\n\n\t\tif( !heap_list_add( vo->rc->heap, out, &lhs ) )\n\t\t\treturn( object );\n\t\tg_value_init( &value, type );\n\t\tg_object_get_property( G_OBJECT( object ), name, &value );\n\t\tif( !heap_gvalue_to_ip( &value, &lhs ) ) {\n\t\t\tg_value_unset( &value );\n\t\t\treturn( object );\n\t\t}\n\t\tg_value_unset( &value );\n\n\t\t(void) heap_list_next( out );\n\t}\n\n\treturn( NULL );\n}\n\n/* Looking for construct-time optional output args. Append them to out.\n */\nstatic void *\nvo_get_optional_arg( const char *name, PElement *value, Vo *vo, PElement *out )\n{\n\tGParamSpec *pspec;\n\tVipsArgumentClass *argument_class;\n\tVipsArgumentInstance *argument_instance;\n\n\tif( vips_object_get_argument( vo->object, name,\n\t\t&pspec, &argument_class, &argument_instance ) )\n\t\treturn( NULL );\n\n\tif( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&\n\t\t(argument_class->flags & VIPS_ARGUMENT_OUTPUT) &&\n\t\targument_instance->assigned ) {\n\t\tGType type = G_PARAM_SPEC_VALUE_TYPE( pspec );\n\t\tGValue gvalue = { 0 };\n\t\tPElement lhs;\n\n\t\tif( !heap_list_add( vo->rc->heap, out, &lhs ) )\n\t\t\treturn( value );\n\t\tg_value_init( &gvalue, type );\n\t\tg_object_get_property( G_OBJECT( vo->object ), name, &gvalue );\n\t\tif( !heap_gvalue_to_ip( &gvalue, &lhs ) ) {\n\t\t\tg_value_unset( &gvalue );\n\t\t\treturn( value );\n\t\t}\n\t\tg_value_unset( &gvalue );\n\n\t\t(void) heap_list_next( out );\n\t}\n\n\treturn( NULL );\n}\n\n/* Get a set of optional args ... of the form [[\"caption\", []], [\"label\", []]]\n * etc.\n */\nstatic gboolean\nvo_get_optional( Vo *vo, PElement *optional, PElement *out )\n{\n\tif( heap_map_dict( optional,\n\t\t(heap_map_dict_fn) vo_get_optional_arg, vo, out ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\n/* Run a VipsOperation. Like vo_object_new(), but we return the output args\n * rather than the operation.\n */\nvoid\nvo_call( Reduce *rc, const char *name, \n\tPElement *required, PElement *optional, PElement *out )\n{\n\tVo *vo;\n\tPElement pe;\n\n\tif( !(vo = vo_new( rc, name )) ) \n\t\treduce_throw( rc );\n\n\tif( !vo_args( vo, required, optional ) ) {\n\t\tvo_free( vo );\n\t\treduce_throw( rc );\n\t}\n\n\t/* Ask the object to construct. This can update vo->operation with an\n\t * old one from the cache.\n\t */\n\tif( vips_cache_operation_buildp( (VipsOperation **) &vo->object ) ) {\n\t\terror_top( _( \"VIPS library error.\" ) );\n\t\terror_sub( \"%s\", im_error_buffer() );\n\t\tim_error_clear();\n\t\tvips_object_unref_outputs( vo->object );\n\t\tvo_free( vo );\n\t\treduce_throw( rc );\n\t}\n\n\t/* We can't build the output object directly on out, since it might be\n\t * one of our inputs. We use the safe Element in vo for the build,\n\t * then copy at the end.\n\t */\n\n\t/* Empty output list.\n\t */\n\tPEPOINTE( &pe, &vo->out );\n\theap_list_init( &pe );\n\n\t/* Append required outputs.\n\t */\n\tif( vips_argument_map( VIPS_OBJECT( vo->object ),\n\t\t(VipsArgumentMapFn) vo_get_required_output, vo, &pe ) ) {\n\t\tvips_object_unref_outputs( vo->object );\n\t\tvo_free( vo );\n\t\treduce_throw( rc );\n\t}\n\n\t/* Append optional outputs.\n\t */\n\tif( !vo_get_optional( vo, optional, &pe ) ) {\n\t\tvips_object_unref_outputs( vo->object );\n\t\tvo_free( vo );\n\t\treduce_throw( rc );\n\t}\n\n\t/* Now write the output object to out.\n\t */\n\tPEPUTE( out, &vo->out );\n\n\tvips_object_unref_outputs( vo->object );\n\tvo_free( vo );\n}\n"
  },
  {
    "path": "src/vipsobject.h",
    "content": "/* Links to VipsObject.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\nvoid vo_object_new( Reduce *rc, const char *name, \n\tPElement *required, PElement *optional, PElement *out );\nvoid vo_call( Reduce *rc, const char *name,\n        PElement *required, PElement *optional, PElement *out );\n\n"
  },
  {
    "path": "src/vobject.c",
    "content": "/* abstract base class for a vobject object ... watch an iobject and call \n * _refresh in idle if it changes.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n/* Time each refresh\n#define DEBUG_TIME\n */\n\n#include \"ip.h\"\n\nstatic GtkVBoxClass *parent_class = NULL;\n\nstatic Queue *vobject_dirty = NULL;\n\nstatic gint vobject_refresh_timeout = 0;\n\n/* Remove from refresh queue.\n */\nstatic void \nvobject_refresh_dequeue( vObject *vobject )\n{\n\tif( vobject->dirty ) {\n#ifdef DEBUG\n\t\tprintf( \"vobject_refresh_dequeue: \\\"%s\\\"\\n\", \n\t\t\tG_OBJECT_TYPE_NAME( vobject ) );\n#endif /*DEBUG*/\n\n\t\tvobject->dirty = FALSE;\n\t\tqueue_remove( vobject_dirty, vobject );\n\t}\n}\n\n#ifdef DEBUG_TIME\n/* Refresh all vobjects at once and time them.\n */\nstatic gboolean\nvobject_refresh_timeout_cb( gpointer user_data )\n{\n\tstatic GTimer *refresh_timer = NULL;\n\tdouble last_elapsed;\n\tdouble worst_time = 0.0;\n\tint worst_index = -1;\n\tvoid *data;\n\tint n;\n\n\tvobject_refresh_timeout = 0;\n\n\tif( !refresh_timer )\n\t\trefresh_timer = g_timer_new();\n\n\tg_timer_reset( refresh_timer );\n\n\tprintf( \"vobject_idle_refresh: starting ...\\n\" );\n\n\tfor( n = 0; (data = queue_head( vobject_dirty )); n++ ) {\n\t\tvObject *vobject = VOBJECT( data );\n\t\tdouble elapsed;\n\n\t\tvobject->dirty = FALSE;\n\t\tvobject_refresh( vobject );\n\t\telapsed = g_timer_elapsed( refresh_timer, NULL );\n\n\t\tif( elapsed - last_elapsed > worst_time ) {\n\t\t\tworst_time = elapsed - last_elapsed;\n\t\t\tworst_index = n;\n\t\t}\n\n\t\tlast_elapsed = elapsed;\n\t}\n\n\tprintf( \"vobject_idle_refresh: done after %gs (%d refreshes)\\n\",\n\t\tg_timer_elapsed( refresh_timer, NULL ), n );\n\n\tprintf( \"vobject_idle_refresh: worst %gs (refresh %d)\\n\", \n\t\tworst_time, worst_index );\n\n\treturn( FALSE );\n}\n#else /*DEBUG_TIME*/\n/* Refresh stuff off the dirty list. \n */\nstatic gboolean\nvobject_refresh_timeout_cb( gpointer user_data )\n{\n\tvoid *data;\n\n#ifdef DEBUG\n\tprintf( \"vobject_refresh_timeout_cb:\\n\" ); \n#endif /*DEBUG*/\n\n\tvobject_refresh_timeout = 0;\n\n\twhile( (data = queue_head( vobject_dirty ) ) ) {\n\t\tvObject *vobject = VOBJECT( data );\n\n#ifdef DEBUG\n\t\tprintf( \"vobject_refresh_timeout_cb: starting \\\"%s\\\" (%p)\\n\", \n\t\t\tG_OBJECT_TYPE_NAME( vobject ), vobject );\n#endif /*DEBUG*/\n\n\t\t/* We must clear dirty before we _refresh() so that if the\n\t\t * _refresh() indirectly triggers another update, we will\n\t\t * _refresh() again.\n\t\t */\n\t\tvobject->dirty = FALSE;\n\t\tvobject_refresh( vobject );\n\t}\n\n\treturn( FALSE );\n}\n#endif /*DEBUG_TIME*/\n\n/* Mark something for refresh. Seldom call this directly ... just change the \n * iobject and all vobjects will have a refresh queued.\n */\nvoid *\nvobject_refresh_queue( vObject *vobject )\n{\n\tif( !vobject->dirty ) {\n#ifdef DEBUG\n\t\tprintf( \"vobject_refresh_queue: %s (%p)\", \n\t\t\tG_OBJECT_TYPE_NAME( vobject ), vobject );\n\t\tif( vobject->iobject )\n\t\t\tprintf( \", iobject %s \\\"%s\\\"\", \n\t\t\t\tG_OBJECT_TYPE_NAME( vobject->iobject ), \n\t\t\t\tNN( vobject->iobject->name ) );\n\t\tprintf( \"\\n\" );\n#endif /*DEBUG*/\n\n\t\tvobject->dirty = TRUE;\n\t\tqueue_add( vobject_dirty, vobject );\n\n\t\tIM_FREEF( g_source_remove, vobject_refresh_timeout );\n\t\tvobject_refresh_timeout = g_timeout_add( 20, \n\t\t\t(GSourceFunc) vobject_refresh_timeout_cb, NULL );\n\t}\n\n\treturn( NULL );\n}\n\n/* Called for iobject changed signal ... queue a refresh. \n */\nstatic void\nvobject_iobject_changed( iObject *iobject, vObject *vobject )\n{\n#ifdef DEBUG\n\tprintf( \"vobject_iobject_changed: %s %s \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( vobject ), \n\t\tG_OBJECT_TYPE_NAME( iobject ), \n\t\tNN( iobject->name ) );\n#endif /*DEBUG*/\n\n\tvobject_refresh_queue( vobject );\n}\n\n/* Called for iobject destroy signal ... kill the vobject too.\n */\nstatic void\nvobject_iobject_destroy( iObject *iobject, vObject *vobject )\n{\n#ifdef DEBUG\n\tprintf( \"vobject_iobject_destroy: iobject %s \\\"%s\\\"\\n\", \n\t\tG_OBJECT_TYPE_NAME( iobject ), NN( iobject->name ) );\n#endif /*DEBUG*/\n\n\tgtk_widget_destroy( GTK_WIDGET( vobject ) );\n}\n\n/* Link to iobject. \n */\nvoid \nvobject_link( vObject *vobject, iObject *iobject )\n{\n\tvObjectClass *vobject_class = VOBJECT_GET_CLASS( vobject );\n\n\tg_assert( !vobject->iobject );\n\n\tif( vobject_class->link ) \n\t\tvobject_class->link( vobject, iobject );\n\n\t/* Queue a refresh ... we always need at least one.\n\t */\n\tvobject_refresh_queue( vobject );\n}\n\nstatic void\nvobject_destroy( GtkObject *object )\n{\n\tvObject *vobject;\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_VOBJECT( object ) );\n\n\tvobject = VOBJECT( object );\n\n#ifdef DEBUG\n\tprintf( \"vobject_destroy: \\\"%s\\\"\\n\", G_OBJECT_TYPE_NAME( object ) );\n#endif /*DEBUG*/\n\n\tif( vobject->iobject ) {\n\t\tFREESID( vobject->changed_sid, vobject->iobject );\n\t\tFREESID( vobject->destroy_sid, vobject->iobject );\n\t\tvobject->iobject = NULL;\n\t}\n\tvobject_refresh_dequeue( vobject );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void \nvobject_finalize( GObject *gobject )\n{\n#ifdef DEBUG\n\tprintf( \"vobject_finalize: \\\"%s\\\"\\n\", G_OBJECT_TYPE_NAME( gobject ) );\n#endif /*DEBUG*/\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\nvobject_real_refresh( vObject *vobject )\n{\n#ifdef DEBUG\n\tprintf( \"vobject_real_refresh: %p %s\\n\", \n\t\tvobject, G_OBJECT_TYPE_NAME( vobject ) );\n#endif /*DEBUG*/\n}\n\nstatic void\nvobject_real_link( vObject *vobject, iObject *iobject )\n{\n\tvobject->iobject = iobject;\n\n\tvobject->changed_sid = g_signal_connect( iobject, \"changed\", \n\t\tG_CALLBACK( vobject_iobject_changed ), vobject );\n\tvobject->destroy_sid = g_signal_connect( iobject, \"destroy\", \n\t\tG_CALLBACK( vobject_iobject_destroy ), vobject );\n}\n\nstatic void\nvobject_class_init( vObjectClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tGtkObjectClass *object_class = (GtkObjectClass*) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = vobject_finalize;\n\n\tobject_class->destroy = vobject_destroy;\n\n\t/* Create signals.\n\t */\n\n\t/* Init default methods.\n\t */\n\tclass->refresh = vobject_real_refresh;\n\tclass->link = vobject_real_link;\n\n\t/* Static init.\n\t */\n\tvobject_dirty = queue_new();\n}\n\nstatic void\nvobject_init( vObject *vobject )\n{\n\t/* Init our instance fields.\n\t */\n\tvobject->iobject = NULL;\n\tvobject->changed_sid = 0;\n\tvobject->destroy_sid = 0;\n\n\tvobject->dirty = FALSE;\n\n\t/* All new vobjects will need refreshing.\n\t */\n\tvobject_refresh_queue( vobject );\n}\n\nGtkType\nvobject_get_type( void )\n{\n\tstatic GtkType vobject_type = 0;\n\n\tif( !vobject_type ) {\n\t\tstatic const GtkTypeInfo vobject_info = {\n\t\t\t\"vObject\",\n\t\t\tsizeof( vObject ),\n\t\t\tsizeof( vObjectClass ),\n\t\t\t(GtkClassInitFunc) vobject_class_init,\n\t\t\t(GtkObjectInitFunc) vobject_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\tvobject_type = gtk_type_unique( GTK_TYPE_VBOX, &vobject_info );\n\t}\n\n\treturn( vobject_type );\n}\n\n/* Trigger the refresh method for a vobject immediately ... we usually queue\n * and wait for idle, but this can be better for interactive stuff.\n */\nvoid *\nvobject_refresh( vObject *vobject )\n{\n\tvObjectClass *vobject_class = VOBJECT_GET_CLASS( vobject );\n\n\tif( vobject_class->refresh ) \n\t\tvobject_class->refresh( vobject );\n\n\treturn( NULL );\n}\n"
  },
  {
    "path": "src/vobject.h",
    "content": "/* abstract base class for a view ... watch an iobject and call _refresh in \n * idle if it changes.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_VOBJECT (vobject_get_type())\n#define VOBJECT( obj ) (GTK_CHECK_CAST( (obj), TYPE_VOBJECT, vObject ))\n#define VOBJECT_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), TYPE_VOBJECT, vObjectClass ))\n#define IS_VOBJECT( obj ) (GTK_CHECK_TYPE( (obj), TYPE_VOBJECT ))\n#define IS_VOBJECT_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_VOBJECT ))\n#define VOBJECT_GET_CLASS( obj ) \\\n\t(GTK_CHECK_GET_CLASS( (obj), TYPE_VOBJECT, vObjectClass ))\n\nstruct _vObject {\n\tGtkVBox vbox;\n\n\t/* My instance vars.\n\t */\n\tiObject *iobject;\t\t/* iObject we are watching */\n\tguint changed_sid;\t\t/* Signals we use to watch model */\n\tguint destroy_sid;\n\n\tgboolean dirty;\t\t\t/* In need of refreshment */\n};\n\ntypedef struct _vObjectClass {\n\tGtkVBoxClass parent_class;\n\n\t/* State change\n\n\t\trefresh\t\trefresh widgets (don't look at heap value,\n\t\t\t\tlook at model)\n\n\t\tlink\t\tthis vobject has been linked to an iobject\n\n\t\t\t\twe also have View::link() -- vObject::link is\n\t\t\t\ta lower-level link which is handy for views \n\t\t\t\twhich are not Views, eg. toolkitbrowser\n\n\t */\n\tvoid (*refresh)( vObject * );\n\tvoid (*link)( vObject *, iObject * );\n} vObjectClass;\n\nvoid *vobject_refresh_queue( vObject *vobject );\n\nGtkType vobject_get_type( void );\nvoid vobject_base_init( void );\n\nvoid vobject_link( vObject *vobject, iObject *iobject );\n\nvoid *vobject_refresh( vObject *vobject );\n"
  },
  {
    "path": "src/watch.c",
    "content": "/* Watch stuff in the prefs workspace.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your watch) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic iContainerClass *watchgroup_parent_class = NULL;\n\n/* Our signals. \n */\nenum {\n\tSIG_WATCH_CHANGED,\t/* \"changed\" on one of our watches */\n\tSIG_LAST\n};\n\nstatic guint watchgroup_signals[SIG_LAST] = { 0 };\n\nstatic void \nwatchgroup_changed( Watchgroup *watchgroup, Watch *watch )\n{\n\tg_signal_emit( G_OBJECT( watchgroup ), \n\t\twatchgroup_signals[SIG_WATCH_CHANGED], 0, watch );\n}\n\nstatic void\nwatchgroup_class_init( WatchgroupClass *class )\n{\n\twatchgroup_parent_class = g_type_class_peek_parent( class );\n\n\twatchgroup_signals[SIG_WATCH_CHANGED] = g_signal_new( \"watch_changed\",\n\t\tG_OBJECT_CLASS_TYPE( class ),\n\t\tG_SIGNAL_RUN_FIRST,\n\t\tG_STRUCT_OFFSET( WatchgroupClass, watch_changed ),\n\t\tNULL, NULL,\n\t\tg_cclosure_marshal_VOID__OBJECT,\n\t\tG_TYPE_NONE, 1,\n\t\tTYPE_WATCH );\n}\n\nstatic void\nwatchgroup_init( Watchgroup *watchgroup )\n{\n#ifdef DEBUG\n\tprintf( \"watchgroup_init\\n\" );\n#endif /*DEBUG*/\n\n\twatchgroup->auto_save_timeout = 0;\n}\n\nGType\nwatchgroup_get_type( void )\n{\n\tstatic GType watchgroup_type = 0;\n\n\tif( !watchgroup_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( WatchgroupClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) watchgroup_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Watchgroup ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) watchgroup_init,\n\t\t};\n\n\t\twatchgroup_type = g_type_register_static( TYPE_ICONTAINER, \n\t\t\t\"Watchgroup\", &info, 0 );\n\t}\n\n\treturn( watchgroup_type );\n}\n\nWatchgroup *\nwatchgroup_new( Workspaceroot *workspaceroot, const char *name )\n{\n\tWatchgroup *watchgroup = WATCHGROUP( \n\t\tg_object_new( TYPE_WATCHGROUP, NULL ) );\n\n\t/* Assume it's a static string.\n\t */\n\twatchgroup->name = name;\n\n\twatchgroup->workspaceroot = workspaceroot;\n\ticontainer_set_hash( ICONTAINER( watchgroup ) );\n\n\treturn( watchgroup );\n}\n\n/* Get the ws we are storing prefs in, and check it looks OK.\n */\nstatic Workspace *\nwatchgroup_get_workspace( Watchgroup *watchgroup )\n{\n\tCompile *compile;\n\tSymbol *sym;\n\n\tif( !watchgroup->workspaceroot->sym )\n\t\treturn( NULL );\n\n\tcompile = watchgroup->workspaceroot->sym->expr->compile;\n\n\tif( !(sym = compile_lookup( compile, watchgroup->name )) ||\n\t\t!sym->expr->compile ||\n\t\tsym->type != SYM_WORKSPACE ||\n\t\t!sym->ws )\n\t\treturn( NULL );\n\n\treturn( sym->ws );\n}\n\nstatic void\nwatchgroup_save( Watchgroup *watchgroup )\n{\n\tWorkspace *ws;\n\n\tif( (ws = watchgroup_get_workspace( watchgroup )) ) {\n\t\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\t\tFilemodel *filemodel = FILEMODEL( wsg );\n\n\t\tif( filemodel->modified ) {\n\t\t\tsymbol_recalculate_all();\n\n\t\t\t/* Ignore error returns ... hmm! Tricky: we can come\n\t\t\t * here during shutdown.\n\t\t\t */\n\t\t\t(void) filemodel_top_save( filemodel, \n\t\t\t\tfilemodel->filename );\n\n\t\t\tfilemodel_set_modified( filemodel, FALSE );\n\t\t}\n\t}\n}\n\nstatic gboolean\nwatchgroup_dirty_timeout_cb( Watchgroup *watchgroup )\n{\n\twatchgroup->auto_save_timeout = 0;\n\n\twatchgroup_save( watchgroup );\n\n\treturn( FALSE );\n}\n\nvoid\nwatchgroup_dirty( Watchgroup *watchgroup )\n{\n\tWorkspace *ws;\n\n\t/* Find the preferences workspace.\n\t */\n\tif( (ws = watchgroup_get_workspace( watchgroup )) ) { \n\t\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\n\t\t/* Mark ws dirty, start save timer.\n\t\t */\n\t\tfilemodel_set_modified( FILEMODEL( wsg ), TRUE );\n\n\t\tIM_FREEF( g_source_remove, watchgroup->auto_save_timeout );\n\t\twatchgroup->auto_save_timeout = g_timeout_add( 1000, \n\t\t\t(GSourceFunc) watchgroup_dirty_timeout_cb, watchgroup );\n\t}\n}\n\nvoid\nwatchgroup_flush( Watchgroup *watchgroup )\n{\n\t/* Do we have a pending save?\n\t */\n\tif( watchgroup->auto_save_timeout ) {\n\t\twatchgroup_save( watchgroup );\n\n\t\tIM_FREEF( g_source_remove, watchgroup->auto_save_timeout );\n\t}\n}\n\nstatic iContainerClass *watch_parent_class = NULL;\nstatic GSList *watch_all = NULL;\n\nstatic void\nwatch_finalize( GObject *gobject )\n{\n\tWatch *watch;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_WATCH( gobject ) );\n\n\twatch = WATCH( gobject );\n\n#ifdef DEBUG\n\tprintf( \"watch_finalize: %s\\n\", NN( IOBJECT( watch )->name ) );\n#endif /*DEBUG*/\n\n\twatch_all = g_slist_remove( watch_all, watch );\n\n\tG_OBJECT_CLASS( watch_parent_class )->finalize( gobject );\n}\n\nstatic void\nwatch_dispose( GObject *gobject )\n{\n\tWatch *watch;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_WATCH( gobject ) );\n\n\twatch = WATCH( gobject );\n\n#ifdef DEBUG\n\tprintf( \"watch_dispose: %s\\n\", NN( IOBJECT( watch )->name ) );\n#endif /*DEBUG*/\n\n\t/* My instance destroy stuff.\n\t */\n\tFREESID( watch->destroy_sid, watch->row );\n\tFREESID( watch->changed_sid, watch->row );\n\twatch->row = NULL;\n\n\tG_OBJECT_CLASS( watch_parent_class )->dispose( gobject );\n}\n\nstatic void\nwatch_changed( iObject *iobject )\n{\n\tWatch *watch = WATCH( iobject );\n\tWatchgroup *watchgroup = WATCHGROUP( ICONTAINER( watch )->parent );\n\n\t/* Emit on our group too. Can get here before our parent is linked on,\n\t * careful.\n\t */\n\tif( watchgroup )\n\t\twatchgroup_changed( WATCHGROUP( ICONTAINER( watch )->parent ), \n\t\t\twatch );\n\n\tIOBJECT_CLASS( watch_parent_class )->changed( iobject );\n}\n\nstatic void\nwatch_class_init( WatchClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tWatchClass *watch_class = (WatchClass *) class;\n\n\twatch_parent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = watch_finalize;\n\tgobject_class->dispose = watch_dispose;\n\n\tiobject_class->changed = watch_changed;\n\n\twatch_class->update = NULL;\n\twatch_class->get_value = NULL;\n}\n\nstatic void\nwatch_init( Watch *watch )\n{\n\twatch->row = NULL;\n\twatch->ok = FALSE;\n\twatch->destroy_sid = 0;\n\twatch->changed_sid = 0;\n\n\twatch_all = g_slist_prepend( watch_all, watch );\n}\n\nGType\nwatch_get_type( void )\n{\n\tstatic GType watch_type = 0;\n\n\tif( !watch_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( WatchClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) watch_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Watch ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) watch_init,\n\t\t};\n\n\t\twatch_type = g_type_register_static( TYPE_ICONTAINER, \n\t\t\t\"Watch\", &info, 0 );\n\t}\n\n\treturn( watch_type );\n}\n\nstatic void\nwatch_link( Watch *watch, Watchgroup *watchgroup, const char *name )\n{\n\tiobject_set( IOBJECT( watch ), name, NULL );\n\ticontainer_child_add( ICONTAINER( watchgroup ), \n\t\tICONTAINER( watch ), -1 );\n}\n\nstatic void\nwatch_destroy_cb( Row *row, Watch *watch )\n{\n#ifdef DEBUG\n\tprintf( \"watch_destroy_cb\\n\" );\n#endif /*DEBUG*/\n\n\twatch->row = NULL;\n\twatch->ok = FALSE;\n\twatch->destroy_sid = 0;\n\twatch->changed_sid = 0;\n}\n\n/* The row we are watching has changed.\n */\nstatic void\nwatch_changed_cb( Row *row, Watch *watch )\n{\n#ifdef DEBUG\n\tprintf( \"watch_changed_cb: %s\\n\", NN( IOBJECT( watch )->name ) );\n#endif /*DEBUG*/\n\n\tif( row->expr )\n\t\twatch->ok = WATCH_GET_CLASS( watch )->update( watch );\n\n\tiobject_changed( IOBJECT( watch ) );\n}\n\n/* Make sure we're linked to the thing we watch.\n */\nstatic void\nwatch_attach( Watch *watch )\n{\n\tWatchgroup *watchgroup = WATCHGROUP( ICONTAINER( watch )->parent );\n\tconst char *name = IOBJECT( watch )->name;\n\tWorkspace *ws;\n\tSymbol *sym;\n\n\tif( watch->row )\n\t\treturn;\n\n\tif( (ws = watchgroup_get_workspace( watchgroup )) &&\n\t\tws->sym->expr &&\n\t\tws->sym->expr->compile &&\n\t\t(sym = compile_lookup( ws->sym->expr->compile, name )) &&\n\t\tsym->expr->row ) {\n\t\twatch->row = sym->expr->row;\n\t\twatch->destroy_sid = \n\t\t\tg_signal_connect( G_OBJECT( watch->row ), \"destroy\",\n\t\t\t\tG_CALLBACK( watch_destroy_cb ), watch );\n\t\twatch->changed_sid = \n\t\t\tg_signal_connect( G_OBJECT( watch->row ), \"changed\",\n\t\t\t\tG_CALLBACK( watch_changed_cb ), watch );\n\t}\n}\n\nWatch *\nwatch_find( Watchgroup *watchgroup, const char *name )\n{\n\treturn( (Watch *)\n\t\t(icontainer_child_lookup( ICONTAINER( watchgroup ), name )) );\n}\n\nstatic gboolean\nwatch_get( Watch *watch, void **out )\n{\n#ifdef DEBUG\n\tprintf( \"watch_get: %s\\n\", NN( IOBJECT( watch )->name ) );\n#endif /*DEBUG*/\n\n\twatch_attach( watch );\n\n\tif( !watch->row )\n\t\treturn( FALSE );\n\n\tif( !watch->ok )\n\t\twatch->ok = WATCH_GET_CLASS( watch )->update( watch );\n\n\tif( !watch->ok )\n\t\treturn( FALSE );\n\n\t*out = WATCH_GET_CLASS( watch )->get_value( watch );\n\n\treturn( TRUE );\n}\n\nstatic void *\nwatch_relink( Watch *watch )\n{\n\tif( !watch->row ) {\n\t\twatch_attach( watch );\n\t\tif( watch->row ) \n\t\t\tiobject_changed( IOBJECT( watch ) );\n\t}\n\n\treturn( NULL );\n}\n\nvoid\nwatch_relink_all( void )\n{\n\tslist_map( watch_all, (SListMapFn) watch_relink, NULL );\n}\n\nvoid\nwatch_vset( Watch *watch, const char *fmt, va_list args )\n{\n\tWatchgroup *watchgroup = WATCHGROUP( ICONTAINER( watch )->parent );\n\n\tWorkspace *ws;\n\n\t/* In case we try to set after prefs has gone.\n\t */\n\tif( !(ws = watchgroup_get_workspace( watchgroup )) ||\n\t\tws->in_dispose )\n\t\treturn;\n\n\tif( watch->row && \n\t\twatch->row->child_rhs && \n\t\twatch->row->child_rhs->itext ) {\n\t\tiText *itext = ITEXT( watch->row->child_rhs->itext );\n\t\tchar buf[256];\n\n\t\t(void) im_vsnprintf( buf, 256, fmt, args );\n\n\t\tif( itext_set_formula( itext, buf ) ) {\n#ifdef DEBUG\n\t\t\tprintf( \"watch_vset: %s = %s\\n\", \n\t\t\t\tIOBJECT( watch )->name, buf );\n#endif /*DEBUG*/\n\n\t\t\titext_set_edited( itext, TRUE );\n\t\t\tif( watch->row->sym )\n\t\t\t\texpr_dirty( watch->row->sym->expr, \n\t\t\t\t\tlink_serial_new() );\n\t\t\twatchgroup_dirty( \n\t\t\t\tWATCHGROUP( ICONTAINER( watch )->parent ) );\n\t\t}\n\t}\n}\n\nvoid\nwatch_set( Watch *watch, const char *fmt, ... )\n{\n\tva_list args;\n\n\tva_start( args, fmt );\n\twatch_vset( watch, fmt, args );\n\tva_end( args );\n}\n\nstatic WatchClass *watch_double_parent_class = NULL;\n\nstatic gboolean\nwatch_double_update( Watch *watch )\n{\n\tWatchDouble *watch_double = WATCH_DOUBLE( watch );\n\tPElement *root = &watch->row->expr->root;\n\n#ifdef DEBUG\n\tprintf( \"watch_double_update\\n\" );\n#endif /*DEBUG*/\n\n\tif( PEISNOVAL( root ) )\n\t\treturn( FALSE );\n\tif( !PEISREAL( root ) ) {\n\t\theap_error_typecheck( root, IOBJECT( watch )->name, \"real\" );\n\t\treturn( FALSE );\n\t}\n\n\twatch_double->value = PEGETREAL( root );\n\n\treturn( TRUE );\n}\n\nstatic void *\nwatch_double_get_value( Watch *watch )\n{\n\tWatchDouble *watch_double = WATCH_DOUBLE( watch );\n\n\treturn( (void *) &watch_double->value );\n}\n\nstatic void\nwatch_double_class_init( WatchDoubleClass *class )\n{\n\tWatchClass *watch_class = (WatchClass *) class;\n\n\twatch_double_parent_class = g_type_class_peek_parent( class );\n\n\twatch_class->update = watch_double_update;\n\twatch_class->get_value = watch_double_get_value;\n}\n\nstatic void\nwatch_double_init( WatchDouble *watch_double )\n{\n#ifdef DEBUG\n\tprintf( \"watch_double_init\\n\" );\n#endif /*DEBUG*/\n\n\twatch_double->value = -1.0;\n}\n\nGType\nwatch_double_get_type( void )\n{\n\tstatic GType watch_double_type = 0;\n\n\tif( !watch_double_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( WatchDoubleClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) watch_double_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( WatchDouble ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) watch_double_init,\n\t\t};\n\n\t\twatch_double_type = g_type_register_static( TYPE_WATCH, \n\t\t\t\"WatchDouble\", &info, 0 );\n\t}\n\n\treturn( watch_double_type );\n}\n\nstatic Watch *\nwatch_double_new( Watchgroup *watchgroup, const char *name )\n{\n\tWatchDouble *watch_double = WATCH_DOUBLE( \n\t\tg_object_new( TYPE_WATCH_DOUBLE, NULL ) );\n\n\twatch_link( WATCH( watch_double ), watchgroup, name );\n\n\treturn( WATCH( watch_double ) );\n}\n\ndouble \nwatch_double_get( Watchgroup *watchgroup, const char *name, double fallback )\n{\n\tWatch *watch;\n\tvoid *value;\n\n\tif( !watchgroup )\n\t\treturn( fallback );\n\n\tif( !(watch = watch_find( watchgroup, name )) )\n\t\twatch = watch_double_new( watchgroup, name );\n\n\tg_assert( IS_WATCH_DOUBLE( watch ) );\n\n\tif( !watch_get( watch, &value ) ) \n\t\treturn( fallback );\n\n\treturn( *((double *) value) );\n}\n\nstatic WatchClass *watch_int_parent_class = NULL;\n\nstatic gboolean\nwatch_int_update( Watch *watch )\n{\n\tWatchInt *watch_int = WATCH_INT( watch );\n\tExpr *expr = watch->row->expr;\n\tPElement *root;\n\n#ifdef DEBUG\n\tprintf( \"watch_int_update: %s\\n\", NN( IOBJECT( watch )->name ) );\n#endif /*DEBUG*/\n\n\t/* Can get called during shutdown :-( main_watchgroup_changed_cb() can\n\t * call us before destroying the row, but after killing the expr.\n\t */\n\tif( !expr )\n\t\treturn( FALSE );\n\troot = &expr->root;\n\tif( PEISNOVAL( root ) )\n\t\treturn( FALSE );\n\tif( !PEISREAL( root ) ) {\n\t\theap_error_typecheck( root, IOBJECT( watch )->name, \"real\" );\n\t\treturn( FALSE );\n\t}\n\n\twatch_int->value = IM_RINT( PEGETREAL( root ) );\n\n\treturn( TRUE );\n}\n\nstatic void *\nwatch_int_get_value( Watch *watch )\n{\n\tWatchInt *watch_int = WATCH_INT( watch );\n\n\treturn( (void *) &watch_int->value );\n}\n\nstatic void\nwatch_int_class_init( WatchIntClass *class )\n{\n\tWatchClass *watch_class = (WatchClass *) class;\n\n\twatch_int_parent_class = g_type_class_peek_parent( class );\n\n\twatch_class->update = watch_int_update;\n\twatch_class->get_value = watch_int_get_value;\n}\n\nstatic void\nwatch_int_init( WatchInt *watch_int )\n{\n#ifdef DEBUG\n\tprintf( \"watch_int_init\\n\" );\n#endif /*DEBUG*/\n\n\twatch_int->value = -1;\n}\n\nGType\nwatch_int_get_type( void )\n{\n\tstatic GType watch_int_type = 0;\n\n\tif( !watch_int_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( WatchIntClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) watch_int_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( WatchInt ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) watch_int_init,\n\t\t};\n\n\t\twatch_int_type = g_type_register_static( TYPE_WATCH, \n\t\t\t\"WatchInt\", &info, 0 );\n\t}\n\n\treturn( watch_int_type );\n}\n\nstatic Watch *\nwatch_int_new( Watchgroup *watchgroup, const char *name )\n{\n\tWatchInt *watch_int = WATCH_INT( g_object_new( TYPE_WATCH_INT, NULL ) );\n\n\twatch_link( WATCH( watch_int ), watchgroup, name );\n\n\treturn( WATCH( watch_int ) );\n}\n\nint\nwatch_int_get( Watchgroup *watchgroup, const char *name, int fallback )\n{\n\tWatch *watch;\n\tvoid *value;\n\n\tif( !watchgroup || \n\t\t!name )\n\t\treturn( fallback );\n\n\tif( !(watch = watch_find( watchgroup, name )) )\n\t\twatch = watch_int_new( watchgroup, name );\n\n\tg_assert( IS_WATCH_INT( watch ) );\n\n\tif( !watch_get( watch, &value ) ) \n\t\treturn( fallback );\n\n\treturn( *((int *) value) );\n}\n\nstatic WatchClass *watch_path_parent_class = NULL;\n\nstatic void\nwatch_path_finalize( GObject *gobject )\n{\n\tWatchPath *watch_path;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_WATCH_PATH( gobject ) );\n\n#ifdef DEBUG\n\tprintf( \"watch_path_finalize\\n\" );\n#endif /*DEBUG*/\n\n\twatch_path = WATCH_PATH( gobject );\n\n\t/* My instance destroy stuff.\n\t */\n\tIM_FREEF( slist_free_all, watch_path->value );\n\n\tG_OBJECT_CLASS( watch_path_parent_class )->finalize( gobject );\n}\n\nstatic gboolean\nwatch_path_update( Watch *watch )\n{\n\tWatchPath *watch_path = WATCH_PATH( watch );\n\tPElement *root = &watch->row->expr->root;\n\tGSList *value;\n\n#ifdef DEBUG\n\tprintf( \"watch_path_update\\n\" );\n#endif /*DEBUG*/\n\n\tif( !heap_get_lstring( root, &value ) )\n\t\treturn( FALSE );\n\n\tIM_FREEF( slist_free_all, watch_path->value );\n\twatch_path->value = value;\n\n\treturn( TRUE );\n}\n\nstatic void *\nwatch_path_get_value( Watch *watch )\n{\n\tWatchPath *watch_path = WATCH_PATH( watch );\n\n\treturn( (void *) &watch_path->value );\n}\n\nstatic void\nwatch_path_class_init( WatchPathClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tWatchClass *watch_class = (WatchClass *) class;\n\n\twatch_path_parent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = watch_path_finalize;\n\n\twatch_class->update = watch_path_update;\n\twatch_class->get_value = watch_path_get_value;\n}\n\nstatic void\nwatch_path_init( WatchPath *watch_path )\n{\n#ifdef DEBUG\n\tprintf( \"watch_path_init\\n\" );\n#endif /*DEBUG*/\n\n\twatch_path->value = NULL;\n}\n\nGType\nwatch_path_get_type( void )\n{\n\tstatic GType watch_path_type = 0;\n\n\tif( !watch_path_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( WatchPathClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) watch_path_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( WatchPath ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) watch_path_init,\n\t\t};\n\n\t\twatch_path_type = g_type_register_static( TYPE_WATCH, \n\t\t\t\"WatchPath\", &info, 0 );\n\t}\n\n\treturn( watch_path_type );\n}\n\nstatic Watch *\nwatch_path_new( Watchgroup *watchgroup, const char *name )\n{\n\tWatchPath *watch_path = WATCH_PATH( \n\t\tg_object_new( TYPE_WATCH_PATH, NULL ) );\n\n\twatch_link( WATCH( watch_path ), watchgroup, name );\n\n\treturn( WATCH( watch_path ) );\n}\n\nGSList *\nwatch_path_get( Watchgroup *watchgroup, const char *name, GSList *fallback )\n{\n\tWatch *watch;\n\tvoid *value;\n\n\tif( !watchgroup )\n\t\treturn( fallback );\n\n\tif( !(watch = watch_find( watchgroup, name )) )\n\t\twatch = watch_path_new( watchgroup, name );\n\n\tg_assert( IS_WATCH_PATH( watch ) );\n\n\tif( !watch_get( watch, &value ) ) \n\t\treturn( fallback );\n\t\n\treturn( *((GSList **) value) );\n}\n\nstatic WatchClass *watch_bool_parent_class = NULL;\n\nstatic gboolean\nwatch_bool_update( Watch *watch )\n{\n\tWatchBool *watch_bool = WATCH_BOOL( watch );\n\tPElement *root = &watch->row->expr->root;\n\n#ifdef DEBUG\n\tprintf( \"watch_bool_update: %s\\n\", NN( IOBJECT( watch )->name ) );\n#endif /*DEBUG*/\n\n\tif( PEISNOVAL( root ) )\n\t\treturn( FALSE );\n\tif( !PEISBOOL( root ) ) {\n\t\theap_error_typecheck( root, IOBJECT( watch )->name, \"bool\" );\n\t\treturn( FALSE );\n\t}\n\n\twatch_bool->value = PEGETBOOL( root );\n\n\treturn( TRUE );\n}\n\nstatic void *\nwatch_bool_get_value( Watch *watch )\n{\n\tWatchBool *watch_bool = WATCH_BOOL( watch );\n\n\treturn( (void *) &watch_bool->value );\n}\n\nstatic void\nwatch_bool_class_init( WatchBoolClass *class )\n{\n\tWatchClass *watch_class = (WatchClass *) class;\n\n\twatch_bool_parent_class = g_type_class_peek_parent( class );\n\n\twatch_class->update = watch_bool_update;\n\twatch_class->get_value = watch_bool_get_value;\n}\n\nstatic void\nwatch_bool_init( WatchBool *watch_bool )\n{\n#ifdef DEBUG\n\tprintf( \"watch_bool_init\\n\" );\n#endif /*DEBUG*/\n\n\twatch_bool->value = FALSE;\n}\n\nGType\nwatch_bool_get_type( void )\n{\n\tstatic GType watch_bool_type = 0;\n\n\tif( !watch_bool_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( WatchBoolClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) watch_bool_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( WatchBool ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) watch_bool_init,\n\t\t};\n\n\t\twatch_bool_type = g_type_register_static( TYPE_WATCH, \n\t\t\t\"WatchBool\", &info, 0 );\n\t}\n\n\treturn( watch_bool_type );\n}\n\nstatic Watch *\nwatch_bool_new( Watchgroup *watchgroup, const char *name )\n{\n\tWatchBool *watch_bool = WATCH_BOOL( \n\t\tg_object_new( TYPE_WATCH_BOOL, NULL ) );\n\n\twatch_link( WATCH( watch_bool ), watchgroup, name );\n\n\treturn( WATCH( watch_bool ) );\n}\n\ngboolean \nwatch_bool_get( Watchgroup *watchgroup, const char *name, gboolean fallback )\n{\n\tWatch *watch;\n\tvoid *value;\n\n\tif( !watchgroup )\n\t\treturn( fallback );\n\n\tif( !(watch = watch_find( watchgroup, name )) )\n\t\twatch = watch_bool_new( watchgroup, name );\n\n\tg_assert( IS_WATCH_BOOL( watch ) );\n\n\tif( !watch_get( watch, &value ) ) \n\t\treturn( fallback );\n\n\treturn( *((gboolean *) value) );\n}\n\nstatic WatchClass *watch_string_parent_class = NULL;\n\nstatic void\nwatch_string_finalize( GObject *gobject )\n{\n\tWatchString *watch_string;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_WATCH_STRING( gobject ) );\n\n#ifdef DEBUG\n\tprintf( \"watch_string_finalize\\n\" );\n#endif /*DEBUG*/\n\n\twatch_string = WATCH_STRING( gobject );\n\n\t/* My instance destroy stuff.\n\t */\n\tIM_FREE( watch_string->value );\n\n\tG_OBJECT_CLASS( watch_string_parent_class )->finalize( gobject );\n}\n\nstatic gboolean\nwatch_string_update( Watch *watch )\n{\n\tWatchString *watch_string = WATCH_STRING( watch );\n\tPElement *root = &watch->row->expr->root;\n\tchar value[1024];\n\n#ifdef DEBUG\n\tprintf( \"watch_string_update\\n\" );\n#endif /*DEBUG*/\n\n\tif( !heap_get_string( root, value, 1024 ) )\n\t\treturn( FALSE );\n\n\tIM_SETSTR( watch_string->value, value );\n\n\treturn( TRUE );\n}\n\nstatic void *\nwatch_string_get_value( Watch *watch )\n{\n\tWatchString *watch_string = WATCH_STRING( watch );\n\n\treturn( (void *) &watch_string->value );\n}\n\nstatic void\nwatch_string_class_init( WatchStringClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tWatchClass *watch_class = (WatchClass *) class;\n\n\twatch_string_parent_class = g_type_class_peek_parent( class );\n\n\tgobject_class->finalize = watch_string_finalize;\n\n\twatch_class->update = watch_string_update;\n\twatch_class->get_value = watch_string_get_value;\n}\n\nstatic void\nwatch_string_init( WatchString *watch_string )\n{\n#ifdef DEBUG\n\tprintf( \"watch_string_init\\n\" );\n#endif /*DEBUG*/\n\n\twatch_string->value = NULL;\n}\n\nGType\nwatch_string_get_type( void )\n{\n\tstatic GType watch_string_type = 0;\n\n\tif( !watch_string_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( WatchStringClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) watch_string_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( WatchString ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) watch_string_init,\n\t\t};\n\n\t\twatch_string_type = g_type_register_static( TYPE_WATCH, \n\t\t\t\"WatchString\", &info, 0 );\n\t}\n\n\treturn( watch_string_type );\n}\n\nstatic Watch *\nwatch_string_new( Watchgroup *watchgroup, const char *name )\n{\n\tWatchString *watch_string = WATCH_STRING( \n\t\tg_object_new( TYPE_WATCH_STRING, NULL ) );\n\n\twatch_link( WATCH( watch_string ), watchgroup, name );\n\n\treturn( WATCH( watch_string ) );\n}\n\nconst char * \nwatch_string_get( Watchgroup *watchgroup, \n\tconst char *name, const char *fallback )\n{\n\tWatch *watch;\n\tvoid *value;\n\n\tif( !watchgroup )\n\t\treturn( fallback );\n\n\tif( !(watch = watch_find( watchgroup, name )) )\n\t\twatch = watch_string_new( watchgroup, name );\n\n\tg_assert( IS_WATCH_STRING( watch ) );\n\n\tif( !watch_get( watch, &value ) ) \n\t\treturn( fallback );\n\n\treturn( *((const char **) value) );\n}\n\n"
  },
  {
    "path": "src/watch.h",
    "content": "/* Watch stuff in the prefs workspace.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your watch) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* Group watches with this.\n */\n\n#define TYPE_WATCHGROUP (watchgroup_get_type())\n#define WATCHGROUP( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCHGROUP, Watchgroup ))\n#define WATCHGROUP_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCHGROUP, WatchgroupClass))\n#define IS_WATCHGROUP( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCHGROUP ))\n#define IS_WATCHGROUP_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCHGROUP ))\n#define WATCHGROUP_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCHGROUP, WatchgroupClass ))\n\ntypedef struct _Watchgroup {\n\tiContainer parent_object;\n\n\t/* Workspaces we work within. Assume we are destroyed before this.\n\t */\n\tWorkspaceroot *workspaceroot;\n\n\t/* Name of workspace our watchers check for their syms.\n\t */\n\tconst char *name;\n\n\t/* Autosave timeout ... save our workspace automatically when this\n\t * ticks away.\n\t */\n\tguint auto_save_timeout;\n} Watchgroup;\n\ntypedef struct _WatchgroupClass {\n\tiContainerClass parent_class;\n\n\t/* One of the watches in this group has changed. \n\t * People interested in several watches can connect to\n\t * this, rather than having to try listening for many \"changed\" signals\n\t * on the watches.\n\t */\n\tvoid (*watch_changed)( Watchgroup *, Watch * );\n} WatchgroupClass;\n\nGType watchgroup_get_type( void );\nWatchgroup *watchgroup_new( Workspaceroot *workspaceroot, const char *name );\nvoid watchgroup_flush( Watchgroup *watchgroup );\n\n/* Abstract base class for something that watches a row.\n */\n\n#define TYPE_WATCH (watch_get_type())\n#define WATCH( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCH, Watch ))\n#define WATCH_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCH, WatchClass))\n#define IS_WATCH( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCH ))\n#define IS_WATCH_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCH ))\n#define WATCH_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCH, WatchClass ))\n\ntypedef void (*WatchCallbackFn)( void * );\n\nstruct _Watch {\n\tiContainer parent_class;\n\n\tRow *row;\t\t\t/* Row we watch */\n\tgboolean ok;\t\t\t/* Value read OK on last change */\n\n\tguint destroy_sid;\t\t/* Listen for events */\n\tguint changed_sid;\n};\n\ntypedef struct _WatchClass {\n\tiContainerClass parent_class;\n\n\t/* Update value from row.\n\t */\n\tgboolean (*update)( Watch * );\n\n\t/* Get a pointer to value.\n\t */\n\tvoid *(*get_value)( Watch * );\n} WatchClass;\n\nWatch *watch_find( Watchgroup *watchgroup, const char *name );\nGtkType watch_get_type( void );\nvoid watch_relink_all( void );\nvoid watch_vset( Watch *watch, const char *fmt, va_list args );\nvoid watch_set( Watch *watch, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\n\n/* A watch that watches something with an int value.\n */\n\ntypedef struct _WatchInt WatchInt;\n\n#define TYPE_WATCH_INT (watch_int_get_type())\n#define WATCH_INT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCH_INT, WatchInt ))\n#define WATCH_INT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCH_INT, WatchIntClass))\n#define IS_WATCH_INT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCH_INT ))\n#define IS_WATCH_INT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCH_INT ))\n#define WATCH_INT_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCH_INT, WatchIntClass ))\n\nstruct _WatchInt {\n\tWatch parent_class;\n\n\tint value;\n};\n\ntypedef struct _WatchIntClass {\n\tWatchClass parent_class;\n\n} WatchIntClass;\n\nGtkType watch_int_get_type( void );\nint watch_int_get( Watchgroup *, const char *name, int fallback );\n\n/* A watch that watches something with a double value.\n */\n\ntypedef struct _WatchDouble WatchDouble;\n\n#define TYPE_WATCH_DOUBLE (watch_double_get_type())\n#define WATCH_DOUBLE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCH_DOUBLE, WatchDouble ))\n#define WATCH_DOUBLE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCH_DOUBLE, WatchDoubleClass))\n#define IS_WATCH_DOUBLE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCH_DOUBLE ))\n#define IS_WATCH_DOUBLE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCH_DOUBLE ))\n#define WATCH_DOUBLE_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCH_DOUBLE, \\\n\t\tWatchDoubleClass ))\n\nstruct _WatchDouble {\n\tWatch parent_class;\n\n\tdouble value;\n};\n\ntypedef struct _WatchDoubleClass {\n\tWatchClass parent_class;\n\n} WatchDoubleClass;\n\nGtkType watch_double_get_type( void );\ndouble watch_double_get( Watchgroup *, const char *name, double fallback );\n\n/* A watch that watches a path.\n */\n\ntypedef struct _WatchPath WatchPath;\n\n#define TYPE_WATCH_PATH (watch_path_get_type())\n#define WATCH_PATH( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCH_PATH, WatchPath ))\n#define WATCH_PATH_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCH_PATH, WatchPathClass))\n#define IS_WATCH_PATH( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCH_PATH ))\n#define IS_WATCH_PATH_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCH_PATH ))\n#define WATCH_PATH_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCH_PATH, WatchPathClass ))\n\nstruct _WatchPath {\n\tWatch parent_class;\n\n\tGSList *value;\n};\n\ntypedef struct _WatchPathClass {\n\tWatchClass parent_class;\n\n} WatchPathClass;\n\nGtkType watch_path_get_type( void );\nGSList *watch_path_get( Watchgroup *, const char *name, GSList *fallback );\n\ntypedef struct _WatchBool WatchBool;\n\n#define TYPE_WATCH_BOOL (watch_bool_get_type())\n#define WATCH_BOOL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCH_BOOL, WatchBool ))\n#define WATCH_BOOL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCH_BOOL, WatchBoolClass))\n#define IS_WATCH_BOOL( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCH_BOOL ))\n#define IS_WATCH_BOOL_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCH_BOOL ))\n#define WATCH_BOOL_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCH_BOOL, WatchBoolClass ))\n\nstruct _WatchBool {\n\tWatch parent_class;\n\n\tgboolean value;\n};\n\ntypedef struct _WatchBoolClass {\n\tWatchClass parent_class;\n\n} WatchBoolClass;\n\nGtkType watch_bool_get_type( void );\ngboolean watch_bool_get( Watchgroup *, const char *name, gboolean fallback );\n\ntypedef struct _WatchString WatchString;\n\n#define TYPE_WATCH_STRING (watch_string_get_type())\n#define WATCH_STRING( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WATCH_STRING, WatchString ))\n#define WATCH_STRING_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WATCH_STRING, WatchStringClass))\n#define IS_WATCH_STRING( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WATCH_STRING ))\n#define IS_WATCH_STRING_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WATCH_STRING ))\n#define WATCH_STRING_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WATCH_STRING, \\\n\t\tWatchStringClass ))\n\nstruct _WatchString {\n\tWatch parent_class;\n\n\tchar *value;\n};\n\ntypedef struct _WatchStringClass {\n\tWatchClass parent_class;\n\n} WatchStringClass;\n\nGtkType watch_string_get_type( void );\nconst char *watch_string_get( Watchgroup *, \n\tconst char *name, const char *fallback );\n\n/* Prefs we follow from C.\n */\n\n/* Default show states.\n */\n#define DISPLAY_RULERS \\\n\t(watch_bool_get( main_watchgroup, \"DISPLAY_RULERS\", FALSE ))\n#define DISPLAY_STATUS \\\n\t(watch_bool_get( main_watchgroup, \"DISPLAY_STATUS\", FALSE ))\n#define DISPLAY_CONVERSION \\\n\t(watch_bool_get( main_watchgroup, \"DISPLAY_CONVERSION\", FALSE ))\n\n/* Display a crosshair on image windows ... turn-off-able, since some desktop\n * themes have almost invisible crosshairs.\n */\n#define DISPLAY_CROSSHAIR \\\n\t(watch_bool_get( main_watchgroup, \"DISPLAY_CROSSHAIR\", TRUE ))\n\n/* Update children during paint.\n */\n#define PAINTBOX_RECOMP \\\n\t(watch_bool_get( main_watchgroup, \"PAINTBOX_RECOMP\", TRUE ))\n\n/* Help browser.\n */\n#define BOX_BROWSER (watch_string_get( main_watchgroup, \"BROWSER\", \"mozilla\" ))\n#define BOX_BROWSER_REMOTE (watch_string_get( main_watchgroup, \\\n\t\"BROWSER_REMOTE\", \"-remote 'openURL(%s)'\" ))\n\n/* Thumbnail size.\n */\n#define DISPLAY_THUMBNAIL \\\n\t(watch_int_get( main_watchgroup, \"DISPLAY_THUMBNAIL\", 64 ))\n\n/* High-quality thumbnails.\n */\n#define DISPLAY_THUMBNAIL_HQ \\\n\t(watch_bool_get( main_watchgroup, \"DISPLAY_THUMBNAIL_HQ\", FALSE ))\n\n/* File stuff.\n */\n#define PIN_FILESEL \\\n\t(watch_bool_get( main_watchgroup, \"CALC_PIN_FILESEL\", FALSE ))\n#define IP_JPEG_Q \\\n\t(watch_int_get( main_watchgroup, \"JPEG_Q\", 75 ))\n#define IP_JPEG_ICC_PROFILE \\\n\t(watch_int_get( main_watchgroup, \"JPEG_ICC_PROFILE\", 0 ))\n#define IP_JPEG_ICC_PROFILE_FILE \\\n\t(watch_string_get( main_watchgroup, \"JPEG_ICC_PROFILE_FILE\", \\\n\t\t\"$VIPSHOME/share/nip2/data/sRGB.icm\" ))\n#define IP_PPM_MODE \\\n\t(watch_int_get( main_watchgroup, \"PPM_MODE\", 0 ))\n#define IP_CSV_SEPARATOR \\\n\t(watch_string_get( main_watchgroup, \"CSV_SEPARATOR\", \"\\t\" ))\n#define IP_PNG_COMPRESSION \\\n\t(watch_int_get( main_watchgroup, \"PNG_COMPRESSION\", 6 ))\n#define IP_PNG_INTERLACE \\\n\t(watch_int_get( main_watchgroup, \"PNG_INTERLACE\", 0 ))\n#define IP_TIFF_COMPRESSION \\\n\t(watch_int_get( main_watchgroup, \"TIFF_COMPRESSION\", 0 ))\n#define IP_TIFF_JPEG_Q \\\n\t(watch_int_get( main_watchgroup, \"TIFF_JPEG_Q\", 75 ))\n#define IP_TIFF_LAYOUT \\\n\t(watch_int_get( main_watchgroup, \"TIFF_LAYOUT\", 0 ))\n#define IP_TIFF_TILE_WIDTH \\\n\t(watch_int_get( main_watchgroup, \"TIFF_TILE_WIDTH\", 128 ))\n#define IP_TIFF_TILE_HEIGHT \\\n\t(watch_int_get( main_watchgroup, \"TIFF_TILE_HEIGHT\", 128 ))\n#define IP_TIFF_MULTI_RES \\\n\t(watch_int_get( main_watchgroup, \"TIFF_MULTI_RES\", 0 ))\n#define IP_TIFF_FORMAT \\\n\t(watch_int_get( main_watchgroup, \"TIFF_FORMAT\", 0 ))\n#define IP_TIFF_PREDICTOR \\\n\t(watch_int_get( main_watchgroup, \"TIFF_PREDICTOR\", 0 ))\n#define IP_TIFF_BIGTIFF \\\n\t(watch_bool_get( main_watchgroup, \"TIFF_BIGTIFF\", FALSE ))\n\n/* Autoreload. \n */\n#define CALC_RELOAD (watch_bool_get( main_watchgroup, \"CALC_RELOAD\", FALSE ))\n\n/* Max chars we print. \n */\n#define LINELENGTH \\\n\tIM_CLIP( 10, \\\n\t\twatch_int_get( main_watchgroup, \"CALC_LINELENGTH\", 80 ), \\\n\t\tMAX_LINELENGTH )\n\n/* CPUs we work over.\n */\n#define VIPS_CPUS \\\n\t(watch_int_get( main_watchgroup, \"VIPS_CPUS\", 1 ))\n\n/* Bar prefs.\n */\n#define MAINW_TOOLBAR \\\n\t(watch_bool_get( main_watchgroup, \"MAINW_TOOLBAR\", TRUE ))\n#define MAINW_TOOLBAR_STYLE \\\n\t(watch_int_get( main_watchgroup, \"MAINW_TOOLBAR_STYLE\", 0 ))\n#define MAINW_STATUSBAR \\\n\t(watch_bool_get( main_watchgroup, \"MAINW_STATUSBAR\", TRUE ))\n\n#define WORKSPACE_LPANE_OPEN \\\n\t(watch_bool_get( main_watchgroup, \"WORKSPACE_LPANE_OPEN\", FALSE ))\n#define WORKSPACE_LPANE_POSITION \\\n\t(watch_int_get( main_watchgroup, \"WORKSPACE_LPANE_POSITION\", 200 ))\n#define WORKSPACE_RPANE_OPEN \\\n\t(watch_bool_get( main_watchgroup, \"WORKSPACE_RPANE_OPEN\", FALSE ))\n#define WORKSPACE_RPANE_POSITION \\\n\t(watch_int_get( main_watchgroup, \"WORKSPACE_RPANE_POSITION\", 400 ))\n\n/* Heap size. Big enough to always load prefs, small enough that it doesn't \n * trash the computer.\n */\n#define MAX_HEAPSIZE \\\n\tIM_CLIP( 100000, \\\n\t\twatch_int_get( main_watchgroup, \"CALC_MAX_HEAP\", 200000 ), \\\n\t\t10000000 )\n\n/* Region dragging.\n */\n#ifdef NO_UPDATE\n#define CALC_RECOMP_REGION \\\n\t(watch_bool_get( main_watchgroup, \"CALC_RECOMP_REGION\", FALSE ))\n#else\n#define CALC_RECOMP_REGION \\\n\t(watch_bool_get( main_watchgroup, \"CALC_RECOMP_REGION\", TRUE ))\n#endif\n\n/* Slider dragging.\n */\n#define CALC_RECOMP_SLIDER \\\n\t(watch_bool_get( main_watchgroup, \"CALC_RECOMP_SLIDER\", FALSE ))\n\n/* Popup new objects.\n */\n#define POPUP_NEW_ROWS \\\n\t(watch_bool_get( main_watchgroup, \"POPUP_NEW_ROWS\", FALSE ))\n\n/* Draw LEDs rather than recolouring tally buttons.\n */\n#define CALC_DISPLAY_LED \\\n\t(watch_bool_get( main_watchgroup, \"CALC_DISPLAY_LED\", FALSE ))\n\n/* Number of vips calls to memoise.\n */\n#define CALL_HISTORY_MAX \\\n\t(watch_int_get( main_watchgroup, \"VIPS_HISTORY_MAX\", 200 ))\n\n/* Auto save wses.\n */\n#define AUTO_WS_SAVE \\\n\t(watch_bool_get( main_watchgroup, \"CALC_AUTO_WS_SAVE\", TRUE ))\n\n/* Image window geometry.\n */\n#define IMAGE_WINDOW_WIDTH \\\n\t(watch_int_get( main_watchgroup, \"IMAGE_WINDOW_WIDTH\", 600 ))\n#define IMAGE_WINDOW_HEIGHT \\\n\t(watch_int_get( main_watchgroup, \"IMAGE_WINDOW_HEIGHT\", 650 ))\n\n/* Default font.\n */\n#define PAINTBOX_FONT \\\n\t(watch_string_get( main_watchgroup, \"PAINTBOX_FONT\", \"Sans 12\" ))\n\n/* Max undo steps ... -1 == unlimited.\n */\n#define PAINTBOX_MAX_UNDO \\\n\t(watch_int_get( main_watchgroup, \"PAINTBOX_MAX_UNDO\", -1 ))\n\n/* Default image file type.\n */\n#define IMAGE_FILE_TYPE \\\n\t(watch_int_get( main_watchgroup, \"IMAGE_FILE_TYPE\", 0 ))\n\n/* Prefs we watch.\n */\n#define PATH_SEARCH (watch_path_get( main_watchgroup, \"CALC_PATH_SEARCH\", \\\n\tpath_search_default ))\n#define PATH_START (watch_path_get( main_watchgroup, \"CALC_PATH_START\", \\\n\tpath_start_default ))\n#define PATH_TMP (watch_string_get( main_watchgroup, \"CALC_PATH_TMP\", \\\n\tpath_tmp_default ))\n\n/* How we print stuff.\n */\n#define TRACE_FUNCTIONS \\\n\t(watch_bool_get( main_watchgroup, \"CALC_TRACE_FUNCTIONS\", FALSE ))\n#define PRINT_CARTESIAN \\\n\t(watch_bool_get( main_watchgroup, \"CALC_PRINT_CARTIESIAN\", FALSE ))\n\n/* Program window.\n */\n#define PROGRAM_PANE_POSITION \\\n\t(watch_double_get( main_watchgroup, \"PROGRAM_PANE_POSITION\", 200 ))\n\n"
  },
  {
    "path": "src/workspace.c",
    "content": "/* Manage workspace objects.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG_VERBOSE\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ModelClass *parent_class = NULL;\n\nstatic GSList *workspace_all = NULL;\n\nstatic GSList *workspace_needs_layout = NULL;\n\nvoid\nworkspace_set_needs_layout( Workspace *ws, gboolean needs_layout )\n{\n#ifdef DEBUG_VERBOSE\n\tprintf( \"workspace_set_needs_layout: %p %s %d\\n\", \n\t\tws, NN( IOBJECT( ws )->name ), needs_layout );\n#endif /*DEBUG_VERBOSE*/\n\n\tif( !ws->needs_layout && \n\t\tneeds_layout &&\n\t\t!ws->in_dispose ) { \n\t\tg_assert( !g_slist_find( workspace_needs_layout, ws ) ); \n\n\t\tws->needs_layout = TRUE;\n\t\tworkspace_needs_layout = g_slist_prepend( \n\t\t\tworkspace_needs_layout, ws ); \n\t}\n\n\tif( ws->needs_layout && !needs_layout ) { \n\t\tg_assert( g_slist_find( workspace_needs_layout, ws ) ); \n\n\t\tws->needs_layout = FALSE;\n\t\tworkspace_needs_layout = g_slist_remove( \n\t\t\tworkspace_needs_layout, ws ); \n\t}\n}\n\nGSList *\nworkspace_get_needs_layout()\n{\n\treturn( workspace_needs_layout );\n}\n\nWorkspacegroup *\nworkspace_get_workspacegroup( Workspace *ws )\n{\n\tiContainer *parent; \n\n\tif( (parent = ICONTAINER( ws )->parent) )\n\t\treturn( WORKSPACEGROUP( parent ) );\n\n\treturn( NULL );\n}\n\nWorkspaceroot *\nworkspace_get_workspaceroot( Workspace *ws )\n{\n\treturn( workspace_get_workspacegroup( ws )->wsr );\n}\n\nvoid\nworkspace_set_modified( Workspace *ws, gboolean modified )\n{\n\tWorkspacegroup *wsg;\n\n\tif( (wsg = workspace_get_workspacegroup( ws )) )\n\t\tfilemodel_set_modified( FILEMODEL( wsg ), modified );\n}\n\nstatic void *\nworkspace_map_sub( Workspacegroup *wsg, workspace_map_fn fn, void *a, void *b )\n{\n\tg_assert( IS_WORKSPACEGROUP( wsg ) ); \n\n\treturn( icontainer_map( ICONTAINER( wsg ),\n\t\t(icontainer_map_fn) fn, a, b ) );\n}\n\n/* Over all workspaces.\n */\nvoid *\nworkspace_map( workspace_map_fn fn, void *a, void *b )\n{\n\treturn( icontainer_map3( ICONTAINER( main_workspaceroot ), \n\t\t(icontainer_map3_fn) workspace_map_sub,\n\t\tfn, a, b ) );\n}\n\n/* Map across the columns in a workspace.\n */\nvoid *\nworkspace_map_column( Workspace *ws, column_map_fn fn, void *a )\n{\n\treturn( icontainer_map( ICONTAINER( ws ), \n\t\t(icontainer_map_fn) fn, a, NULL ) );\n}\n\n/* Map across a Workspace, applying to the symbols of the top-level rows.\n */\nvoid *\nworkspace_map_symbol( Workspace *ws, symbol_map_fn fn, void *a )\n{\n\treturn( icontainer_map( ICONTAINER( ws ), \n\t\t(icontainer_map_fn) column_map_symbol, (void *) fn, a ) );\n}\n\nstatic void *\nworkspace_is_empty_sub( Symbol *sym )\n{\n\treturn( sym );\n}\n\n/* Does a workspace contain no rows?\n */\ngboolean\nworkspace_is_empty( Workspace *ws )\n{\n\treturn( workspace_map_symbol( ws,\n\t\t(symbol_map_fn) workspace_is_empty_sub, NULL ) == NULL );\n}\n\n/* Map a function over all selected rows in a workspace.\n */\nvoid *\nworkspace_selected_map( Workspace *ws, row_map_fn fn, void *a, void *b )\n{\n\treturn( slist_map2( ws->selected, (SListMap2Fn) fn, a, b ) );\n}\n\nstatic void *\nworkspace_selected_map_sym_sub( Row *row, symbol_map_fn fn, void *a )\n{\n\treturn( fn( row->sym, a, NULL, NULL ) );\n}\n\n/* Map a function over all selected symbols in a workspace.\n */\nvoid *\nworkspace_selected_map_sym( Workspace *ws, \n\tsymbol_map_fn fn, void *a, void *b )\n{\n\treturn( workspace_selected_map( ws,\n\t\t(row_map_fn) workspace_selected_map_sym_sub, (void *) fn, a ) );\n}\n\n/* Are there any selected rows?\n */\ngboolean\nworkspace_selected_any( Workspace *ws )\n{\n\treturn( ws->selected != NULL );\n}\n\n/* Number of selected rows.\n */\nint\nworkspace_selected_num( Workspace *ws )\n{\n\treturn( g_slist_length( ws->selected ) );\n}\n\nstatic void *\nworkspace_selected_sym_sub( Row *row, Symbol *sym )\n{\n\tif( row->sym == sym )\n\t\treturn( row );\n\n\treturn( NULL );\n}\n\n/* Is sym selected?\n */\ngboolean\nworkspace_selected_sym( Workspace *ws, Symbol *sym )\n{\n\treturn( workspace_selected_map( ws,\n\t\t(row_map_fn) workspace_selected_sym_sub, sym, NULL ) != NULL  );\n}\n\n/* Is just one row selected? If yes, return it.\n */\nRow *\nworkspace_selected_one( Workspace *ws )\n{\n\tint len = g_slist_length( ws->selected );\n\n\tif( len == 1 )\n\t\treturn( (Row *)(ws->selected->data) );\n\telse if( len == 0 ) {\n\t\terror_top( _( \"No objects selected.\" ) );\n\t\terror_sub( _( \"Select exactly one object and try again.\" ) );\n\t\treturn( NULL );\n\t}\n\telse {\n\t\terror_top( _( \"More than one object selected.\" ) );\n\t\terror_sub( _( \"Select exactly one object and try again.\" ) );\n\t\treturn( NULL );\n\t}\n}\n\nstatic void *\nworkspace_deselect_all_sub( Column *col )\n{\n\tcol->last_select = NULL;\n\n\treturn( NULL );\n}\n\n/* Deselect all rows.\n */\nvoid\nworkspace_deselect_all( Workspace *ws )\n{\n\t(void) workspace_selected_map( ws, \n\t\t(row_map_fn) row_deselect, NULL, NULL );\n\t(void) workspace_map_column( ws, \n\t\t(column_map_fn) workspace_deselect_all_sub, NULL );\n}\n\n/* Track this while we build a names list.\n */\ntypedef struct {\n\tVipsBuf *buf;\n\tconst char *separator;\n\tgboolean first;\n} NamesInfo;\n\n/* Add a name to a string for a symbol.\n */\nstatic void *\nworkspace_selected_names_sub( Row *row, NamesInfo *names )\n{\n\tif( !names->first )\n\t\tvips_buf_appends( names->buf, names->separator );\n\n\t/* Hack: if this is a matrix with selected cells, use an extract to\n\t * get those cells out. We should really have a row method for this I\n\t * guess :-(\n\t */\n\tif( row->child_rhs && row->child_rhs->graphic &&\n\t\tIS_MATRIX( row->child_rhs->graphic ) &&\n\t\tMATRIX( row->child_rhs->graphic )->selected ) {\n\t\tMatrix *matrix = MATRIX( row->child_rhs->graphic );\n\n\t\tvips_buf_appends( names->buf, \"(\" );\n\t\trow_qualified_name( row, names->buf );\n\t\tvips_buf_appendf( names->buf, \".extract %d %d %d %d)\",\n\t\t\tmatrix->range.left, \n\t\t\tmatrix->range.top, \n\t\t\tmatrix->range.width, \n\t\t\tmatrix->range.height );\n\t}\n\telse \n\t\trow_qualified_name( row, names->buf );\n\n\tnames->first = FALSE;\n\n\treturn( NULL );\n}\n\n/* Add a list of selected symbol names to a string. \n */\nvoid\nworkspace_selected_names( Workspace *ws, VipsBuf *buf, const char *separator )\n{\n\tNamesInfo names;\n\n        names.buf = buf;\n        names.separator = separator;\n        names.first = TRUE;\n\n\t(void) workspace_selected_map( ws,\n\t\t(row_map_fn) workspace_selected_names_sub, &names, NULL );\n}\n\nvoid\nworkspace_column_names( Column *col, VipsBuf *buf, const char *separator )\n{\n\tNamesInfo names;\n\n        names.buf = buf;\n        names.separator = separator;\n        names.first = TRUE;\n\n\t(void) column_map( col,\n\t\t(row_map_fn) workspace_selected_names_sub, &names, NULL );\n}\n\n/* Select all objects in all columns.\n */\nvoid\nworkspace_select_all( Workspace *ws )\n{\n\t(void) icontainer_map( ICONTAINER( ws ), \n\t\t(icontainer_map_fn) column_select_symbols, NULL, NULL );\n}\n\n/* Is there just one column, and is it empty? \n */\nColumn *\nworkspace_is_one_empty( Workspace *ws )\n{\n\tGSList *children = ICONTAINER( ws )->children;\n\tColumn *col;\n\n\tif( g_slist_length( children ) != 1 ) \n\t\treturn( NULL );\n\n\tcol = COLUMN( children->data );\n\tif( !column_is_empty( col ) )\n\t\treturn( NULL );\n\n\treturn( col );\n}\n\n/* Search for a column by name.\n */\nColumn *\nworkspace_column_find( Workspace *ws, const char *name )\n{\n\tModel *model;\n\n\tif( !(model = icontainer_map( ICONTAINER( ws ),\n\t\t(icontainer_map_fn) iobject_test_name, (void *) name, NULL )) ) \n\t\treturn( NULL );\n\n\treturn( COLUMN( model ) );\n}\n\n/* Return the column for a name ... an existing column, or a new one.\n */\nColumn *\nworkspace_column_get( Workspace *ws, const char *name )\n{\n\tColumn *col;\n\n\t/* Exists?\n\t */\n\tif( (col = workspace_column_find( ws, name )) ) \n\t\treturn( col );\n\n\t/* No - build new column and return a pointer to that.\n\t */\n\treturn( column_new( ws, name ) );\n}\n\n/* Make up a new column name. Check for not already in workspace.\n */\nvoid\nworkspace_column_name_new( Workspace *ws, char *name )\n{\n\tdo {\n\t\tnumber_to_string( ws->next++, name );\n\t} while( workspace_column_find( ws, name ) );\n}\n\nColumn *\nworkspace_get_column( Workspace *ws )\n{\n\tif( ICONTAINER( ws )->current )\n\t\treturn( COLUMN( ICONTAINER( ws )->current ) );\n\n\treturn( NULL );\n}\n\n/* Select a column. Can select NULL for no current col in this ws.\n */\nvoid\nworkspace_column_select( Workspace *ws, Column *col )\n{\n\ticontainer_current( ICONTAINER( ws ), ICONTAINER( col ) ); \n}\n\n/* Make sure we have a column selected ... pick one of the existing columns; if \n * there are none, make a column.\n */\nColumn *\nworkspace_column_pick( Workspace *ws )\n{\n\tColumn *col;\n\n\tif( (col = workspace_get_column( ws )) )\n\t\treturn( col );\n\tif( (col = COLUMN( icontainer_get_nth_child( \n\t\tICONTAINER( ws ), 0 ) )) ) {\n\t\tworkspace_column_select( ws, col ); \n\t\treturn( col );\n\t}\n\n\t/* Make an empty column ... always at the top left.\n\t */\n\tcol = column_new( ws, \"A\" );\n\tcol->x = WORKSPACEVIEW_MARGIN_LEFT;\n\tcol->y = WORKSPACEVIEW_MARGIN_TOP;\n\tworkspace_column_select( ws, col );\n\n\treturn( col );\n}\n\n/* Make and select a column. Used for \"new column\" UI actions. \n */\nColumn *\nworkspace_column_new( Workspace *ws )\n{\n\tchar new_name[MAX_STRSIZE];\n\tColumn *old_col;\n\tColumn *col;\n\n\tworkspace_column_name_new( ws, new_name );\n\tif( !(col = column_new( ws, new_name )) ) \n\t\treturn( NULL );\n\n\t/* Position just to right of currently selected column.\n\t */\n\tif( (old_col = workspace_get_column( ws )) ) {\n\t\tcol->x = old_col->x + 50;\n\t\tcol->y = old_col->y;\n\t}\n\n\tworkspace_column_select( ws, col );\n\tcolumn_scrollto( col, MODEL_SCROLL_TOP );\n\n\treturn( col );\n}\n\n/* Make a new symbol, part of the current column.\n */\nstatic Symbol *\nworkspace_add_symbol( Workspace *ws )\n{\n\tColumn *col = workspace_column_pick( ws );\n\tSymbol *sym;\n\tchar *name;\n\n\tname = column_name_new( col );\n\tsym = symbol_new( ws->sym->expr->compile, name );\n\tIM_FREE( name );\n\n\treturn( sym );\n}\n\n/* Make up a new definition.\n */\nSymbol *\nworkspace_add_def( Workspace *ws, const char *str )\n{\n\tColumn *col = workspace_column_pick( ws );\n\tSymbol *sym;\n\tchar *name;\n\n#ifdef DEBUG\n\tprintf( \"workspace_add_def: %s\\n\", str );\n#endif /*DEBUG*/\n\n        if( !str || strspn( str, WHITESPACE ) == strlen( str ) )\n\t\treturn( NULL );\n\n\t/* Try parsing as a \"fred = 12\" style def. \n\t */\n\tattach_input_string( str );\n\tif( (name = parse_test_define()) ) {\n\t\tsym = symbol_new( ws->sym->expr->compile, name );\n\t\tIM_FREE( name );\n\t\tattach_input_string( str + \n\t\t\tIM_CLIP( 0, input_state.charpos - 1, strlen( str ) ) );\n\t}\n\telse {\n\t\t/* That didn't work. Make a sym from the col name.\n\t\t */\n\t\tsym = workspace_add_symbol( ws );\n\t\tattach_input_string( str );\n\t}\n\n\tif( !symbol_user_init( sym ) || \n\t\t!parse_rhs( sym->expr, PARSE_RHS ) ) {\n\t\t/* Another parse error.\n\t\t */\n\t\texpr_error_get( sym->expr );\n\n\t\t/* Block changes to error_string ... symbol_destroy() \n\t\t * can set this for compound objects.\n\t\t */\n\t\terror_block();\n\t\tIDESTROY( sym );\n\t\terror_unblock();\n\n\t\treturn( NULL );\n\t}\n\n\t/* If we're redefining a sym, it might have a row already.\n\t */\n\tif( !sym->expr->row )\n\t\t(void) row_new( col->scol, sym, &sym->expr->root );\n\tsymbol_made( sym );\n\tworkspace_set_modified( ws, TRUE );\n\n\treturn( sym );\n}\n\n/* Make up a new definition, recalc and scroll to make it visible. \n */\nSymbol *\nworkspace_add_def_recalc( Workspace *ws, const char *str )\n{\n\tColumn *col = workspace_column_pick( ws );\n\n\tSymbol *sym;\n\n#ifdef DEBUG\n\tprintf( \"workspace_add_def_recalc: %s\\n\", str );\n#endif /*DEBUG*/\n\n\tif( !(sym = workspace_add_def( ws, str )) )\n\t\treturn( NULL );\n\n\tif( !symbol_recalculate_check( sym ) ) {\n\t\t/* Eval error.\n\t\t */\n\t\texpr_error_get( sym->expr );\n\t\terror_block();\n\t\tIDESTROY( sym );\n\t\terror_unblock();\n\n\t\treturn( NULL );\n\t}\n\n\t/* Jump to column containing object.\n\t */\n\tcolumn_scrollto( col, MODEL_SCROLL_BOTTOM );\n\n\treturn( sym );\n}\n\ngboolean\nworkspace_load_file_buf( VipsBuf *buf, const char *filename )\n{\n\tif( callv_string_filenamef( \n\t\t(callv_string_fn) vips_format_for_file,\n\t\t\"%s\", filename ) ) \n\t\tvips_buf_appends( buf, \"Image_file\" );\n\telse\n\t\tvips_buf_appends( buf, \"Matrix_file\" );\n\n\tvips_buf_appends( buf, \" \\\"\" );\n\tvips_buf_appendsc( buf, TRUE, filename );\n\tvips_buf_appends( buf, \"\\\"\" );\n\n\treturn( TRUE );\n}\n\n/* Load a matrix or image. Don't recalc: you need to recalc later to test for\n * success/fail. See eg. workspace_add_def_recalc()\n */\nSymbol *\nworkspace_load_file( Workspace *ws, const char *filename )\n{\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\tSymbol *sym;\n\n\tif( !workspace_load_file_buf( &buf, filename ) )\n\t\treturn( NULL );\n\tif( !(sym = workspace_add_def( ws, vips_buf_all( &buf ) )) ) \n\t\treturn( NULL );\n\tmainw_recent_add( &mainw_recent_image, filename );\n\n\treturn( sym );\n}\n\nstatic void\nworkspace_dispose( GObject *gobject )\n{\n\tWorkspace *ws;\n\n#ifdef DEBUG\n\tprintf( \"workspace_dispose: %p %s\\n\", \n\t\tgobject, NN( IOBJECT( gobject )->name ) );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_WORKSPACE( gobject ) );\n\n\tws = WORKSPACE( gobject );\n\n\tworkspace_set_needs_layout( ws, FALSE );\n\tws->in_dispose = TRUE;\n\n\tUNREF( ws->kitg );\n\tUNREF( ws->local_kitg );\n\tIDESTROY( ws->sym );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\nworkspace_finalize( GObject *gobject )\n{\n\tWorkspace *ws;\n\n#ifdef DEBUG\n\tprintf( \"workspace_finalize: %p %s\\n\", \n\t\tgobject, NN( IOBJECT( gobject )->name ) );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_WORKSPACE( gobject ) );\n\n\tws = WORKSPACE( gobject );\n\n\tIM_FREE( ws->status );\n\tIM_FREE( ws->local_defs );\n\n\tworkspace_all = g_slist_remove( workspace_all, ws );\n\n\tG_OBJECT_CLASS( parent_class )->finalize( gobject );\n}\n\nstatic void\nworkspace_changed( iObject *iobject )\n{\n\tWorkspace *ws;\n\tWorkspacegroup *wsg;\n\n#ifdef DEBUG_VERBOSE\n\tprintf( \"workspace_changed: %s\\n\", NN( iobject->name ) );\n#endif /*DEBUG_VERBOSE*/\n\n\tg_return_if_fail( iobject != NULL );\n\tg_return_if_fail( IS_WORKSPACE( iobject ) );\n\n\tws = WORKSPACE( iobject );\n\twsg = workspace_get_workspacegroup( ws );\n\n\t/* Signal changed on our workspacegroup, if we're the current object.\n\t */\n\tif( wsg &&\n\t\tICONTAINER( wsg )->current == ICONTAINER( iobject ) )\n\t\tiobject_changed( IOBJECT( wsg ) );\n\n\tIOBJECT_CLASS( parent_class )->changed( iobject );\n}\n\nstatic void\nworkspace_child_add( iContainer *parent, iContainer *child, int pos )\n{\n\tWorkspace *ws = WORKSPACE( parent );\n\tColumn *col = COLUMN( child );\n\n\tICONTAINER_CLASS( parent_class )->child_add( parent, child, pos );\n\n\tif( col->selected )\n\t\tworkspace_column_select( ws, col );\n}\n\nstatic void\nworkspace_child_remove( iContainer *parent, iContainer *child )\n{\n\tWorkspace *ws = WORKSPACE( parent );\n\n\tworkspace_set_modified( ws, TRUE );\n\n\tICONTAINER_CLASS( parent_class )->child_remove( parent, child );\n}\n\nstatic void\nworkspace_current( iContainer *parent, iContainer *child )\n{\n\tWorkspace *ws = WORKSPACE( parent );\n\tColumn *col = COLUMN( child );\n\tColumn *current = workspace_get_column( ws );\n\n\tif( current )\n\t\tcurrent->selected = FALSE;\n\tif( col )\n\t\tcol->selected = TRUE;\n\n\tICONTAINER_CLASS( parent_class )->current( parent, child );\n}\n\nstatic void\nworkspace_link( Workspace *ws, Workspacegroup *wsg, const char *name )\n{\n\tWorkspaceroot *wsr = wsg->wsr;\n\n\tSymbol *sym;\n\n#ifdef DEBUG\n\tprintf( \"workspace_link: naming ws %p as %s\\n\", ws, name );\n#endif /*DEBUG*/\n\n\tsym = symbol_new_defining( wsr->sym->expr->compile, name );\n\n\tws->sym = sym;\n\tsym->type = SYM_WORKSPACE;\n\tsym->ws = ws;\n\tsym->expr = expr_new( sym );\n\t(void) compile_new( sym->expr );\n\tsymbol_made( sym );\n\tiobject_set( IOBJECT( ws ), name, NULL );\n\n\tws->local_kitg = toolkitgroup_new( ws->sym );\n\tg_object_ref( G_OBJECT( ws->local_kitg ) );\n\tiobject_sink( IOBJECT( ws->local_kitg ) );\n}\n\nstatic const char *\nworkspacemode_to_char( WorkspaceMode mode )\n{\n\tswitch( mode ) {\n\tcase WORKSPACE_MODE_REGULAR:\n\t\treturn( \"WORKSPACE_MODE_REGULAR\" );\n\n\tcase WORKSPACE_MODE_FORMULA:\n\t\treturn( \"WORKSPACE_MODE_FORMULA\" );\n\n\tcase WORKSPACE_MODE_NOEDIT:\n\t\treturn( \"WORKSPACE_MODE_NOEDIT\" );\n\n\tdefault:\n\t\treturn( NULL );\n\t}\n}\n\nstatic WorkspaceMode\nchar_to_workspacemode( const char *mode )\n{\n\tif( strcasecmp( mode, \"WORKSPACE_MODE_REGULAR\" ) == 0 )\n\t\treturn( WORKSPACE_MODE_REGULAR );\n\telse if( strcasecmp( mode, \"WORKSPACE_MODE_FORMULA\" ) == 0 )\n\t\treturn( WORKSPACE_MODE_FORMULA );\n\telse if( strcasecmp( mode, \"WORKSPACE_MODE_NOEDIT\" ) == 0 )\n\t\treturn( WORKSPACE_MODE_NOEDIT );\n\telse\n\t\treturn( (WorkspaceMode) -1 );\n}\n\nstatic View *\nworkspace_view_new( Model *model, View *parent )\n{\n\treturn( workspaceview_new() );\n}\n\nstatic gboolean\nworkspace_load( Model *model, \n\tModelLoadState *state, Model *parent, xmlNode *xnode )\n{\n\tWorkspace *ws = WORKSPACE( model );\n\tchar buf[FILENAME_MAX];\n\tchar *txt;\n\n\tg_assert( IS_WORKSPACEGROUP( parent ) );\n\n\t/* \"view\" is optional, for backwards compatibility.\n\t */\n\tif( get_sprop( xnode, \"view\", buf, FILENAME_MAX ) ) {\n\t\tWorkspaceMode mode = char_to_workspacemode( buf );\n\n\t\tif( (int) mode >= 0 )\n\t\t\t/* Could call workspace_set_mode(), but this is only a\n\t\t\t * load, so so what.\n\t\t\t */\n\t\t\tws->mode = mode;\n\t}\n\n\t/* Also optional.\n\t */\n\t(void) get_dprop( xnode, \"scale\", &ws->scale );\n\t(void) get_dprop( xnode, \"offset\", &ws->offset );\n\n\t(void) get_bprop( xnode, \"locked\", &ws->locked );\n\n\t(void) get_bprop( xnode, \"lpane_open\", &ws->lpane_open );\n\t(void) get_iprop( xnode, \"lpane_position\", &ws->lpane_position );\n\t(void) get_bprop( xnode, \"rpane_open\", &ws->rpane_open );\n\t(void) get_iprop( xnode, \"rpane_position\", &ws->rpane_position );\n\n\tif( get_sprop( xnode, \"name\", buf, FILENAME_MAX ) ) {\n\t\tIM_SETSTR( IOBJECT( ws )->name, buf );\n\t}\n\tif( get_sprop( xnode, \"caption\", buf, FILENAME_MAX ) ) {\n\t\tIM_SETSTR( IOBJECT( ws )->caption, buf );\n\t}\n\n\t/* Don't use get_sprop() and avoid a limit on def size.\n\t */\n\tif( (txt = (char *) xmlGetProp( xnode, (xmlChar *) \"local_defs\" )) ) {\n\t\t(void) workspace_local_set( ws, txt );\n\t\tIM_FREEF( xmlFree, txt );\n\t}\n\n\t(void) get_iprop( xnode, \"major\", &ws->major );\n\t(void) get_iprop( xnode, \"minor\", &ws->minor );\n\n\tif( !MODEL_CLASS( parent_class )->load( model, state, parent, xnode ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic xmlNode *\nworkspace_save( Model *model, xmlNode *xnode )\n{\n\tWorkspace *ws = WORKSPACE( model );\n\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\txmlNode *xthis;\n\n\tif( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )\n\t\treturn( NULL );\n\n\tif( !set_sprop( xthis, \"view\", workspacemode_to_char( ws->mode ) ) ||\n\t\t!set_dprop( xthis, \"scale\", ws->scale ) ||\n\t\t!set_dprop( xthis, \"offset\", ws->offset ) ||\n\t\t!set_sprop( xthis, \"locked\", bool_to_char( ws->locked ) ) ||\n\t\t!set_iprop( xthis, \"lpane_position\", ws->lpane_position ) ||\n\t\t!set_sprop( xthis, \"lpane_open\", \n\t\t\tbool_to_char( ws->lpane_open ) ) ||\n\t\t!set_iprop( xthis, \"rpane_position\", ws->rpane_position ) ||\n\t\t!set_sprop( xthis, \"rpane_open\", \n\t\t\tbool_to_char( ws->rpane_open ) ) ||\n\t\t!set_sprop( xthis, \"local_defs\", ws->local_defs ) ||\n\t\t!set_sprop( xthis, \"name\", IOBJECT( ws )->name ) ||\n\t\t!set_sprop( xthis, \"caption\", IOBJECT( ws )->caption ) ) \n\t\treturn( NULL );\n\n\t/* We have to save our workspacegroup's filename here for compt with\n\t * older nip2.\n\t */\n\tif( !set_sprop( xthis, \"filename\", FILEMODEL( wsg )->filename ) )\n\t\treturn( NULL );\n\n\tif( !set_iprop( xthis, \"major\", ws->major ) ||\n\t\t!set_iprop( xthis, \"minor\", ws->minor ) )\n\t\treturn( NULL );\n\n\treturn( xthis );\n}\n\nstatic void\nworkspace_empty( Model *model )\n{\n\tWorkspace *ws = WORKSPACE( model );\n\n\t/* Make sure this gets reset.\n\t */\n\tws->area.left = 0;\n\tws->area.top = 0;\n\tws->area.width = 0;\n\tws->area.height = 0;\n\n\tMODEL_CLASS( parent_class )->empty( model );\n}\n\nstatic void *\nworkspace_load_toolkit( const char *filename, Toolkitgroup *toolkitgroup )\n{\n\tif( !toolkit_new_from_file( toolkitgroup, filename ) ) \n\t\tiwindow_alert( NULL, GTK_MESSAGE_ERROR );\n\n\treturn( NULL );\n}\n\n/* The compat modes this version of nip2 has. Search the compat dir and make a\n * list of these things.\n */\n#define MAX_COMPAT (100)\nstatic int compat_major[MAX_COMPAT];\nstatic int compat_minor[MAX_COMPAT];\nstatic int n_compat = 0;\n\nstatic void *\nworkspace_build_compat_fn( const char *filename )\n{\n\tchar *basename;\n\tint major;\n\tint minor;\n\n\tbasename = g_path_get_basename( filename );\n\n\tif( sscanf( basename, \"%d.%d\", &major, &minor ) != 2 ) {\n\t\tg_free( basename );\n\t\treturn( NULL );\n\t}\n\tg_free( basename );\n\n\tcompat_major[n_compat] = major;\n\tcompat_minor[n_compat] = minor;\n\tn_compat += 1;\n\n#ifdef DEBUG\n\tprintf( \"workspace_build_compat_fn: found major = %d, minor = %d\\n\", \n\t\tmajor, minor ); \n#endif /*DEBUG*/\n\n\treturn( NULL );\n}\n\n/* Build the list of ws compatibility defs we have.\n */\nstatic void\nworkspace_build_compat( void )\n{\n\tif( n_compat > 0 )\n\t\treturn;\n\n\tpath_map_dir( \"$VIPSHOME/share/\" PACKAGE \"/compat\", \"*.*\", \n\t\t(path_map_fn) workspace_build_compat_fn, NULL );\n}\n\n/* Given a major/minor (eg. read from a ws header), return non-zero if we have \n * a set of compat defs.\n */\nint\nworkspace_have_compat( int major, int minor, int *best_major, int *best_minor )\n{\n\tint i;\n\tint best;\n\n#ifdef DEBUG\n\tprintf( \"workspace_have_compat: searching for %d.%d\\n\", major, minor );\n#endif /*DEBUG*/\n\n\t/* Sets of ws compatibility defs cover themselves and any earlier\n\t * releases, as far back as the next set of compat defs. We need to\n\t * search for the smallest compat version that's greater than the\n\t * version number in the file.\n\t */\n\tworkspace_build_compat();\n\tbest = -1;\n\tfor( i = 0; i < n_compat; i++ ) \n\t\tif( major <= compat_major[i] && minor <= compat_minor[i] ) \n\t\t\t/* Found a possible compat set, is it better than the\n\t\t\t * best we've seen so far?\n\t\t\t */\n\t\t\tif( best == -1 ||\n\t\t\t\tcompat_major[i] < compat_major[best] ||\n\t\t\t\tcompat_minor[i] < compat_minor[best] )\n\t\t\t\tbest = i;\n\tif( best == -1 )\n\t\treturn( 0 );\n\n#ifdef DEBUG\n\tprintf( \"\\tfound %d.%d\\n\", compat_major[best], compat_minor[best] );\n#endif /*DEBUG*/\n\n\tif( best_major )\n\t\t*best_major = compat_major[best];\n\tif( best_minor )\n\t\t*best_minor = compat_minor[best];\n\n\treturn( 1 );\n}\n\nvoid\nworkspace_get_version( Workspace *ws, int *major, int *minor )\n{\n\t*major = ws->major;\n\t*minor = ws->minor;\n}\n\ngboolean\nworkspace_load_compat( Workspace *ws, int major, int minor )\n{\n\tchar pathname[FILENAME_MAX];\n\tGSList *path;\n\tint best_major;\n\tint best_minor;\n\n\tif( workspace_have_compat( major, minor, &best_major, &best_minor ) ) {\n\t\t/* Make a private toolkitgroup local to this workspace to \n\t\t * hold the compatibility defs we are planning to load.\n\t\t */\n\t\tUNREF( ws->kitg );\n\t\tws->kitg = toolkitgroup_new( ws->sym );\n\t\tg_object_ref( G_OBJECT( ws->kitg ) );\n\t\tiobject_sink( IOBJECT( ws->kitg ) );\n\n\t\tim_snprintf( pathname, FILENAME_MAX, \n\t\t\t\"$VIPSHOME/share/\" PACKAGE \"/compat/%d.%d\", \n\t\t\tbest_major, best_minor );\n\t\tpath = path_parse( pathname );\n\t\tif( path_map( path, \"*.def\", \n\t\t\t(path_map_fn) workspace_load_toolkit, ws->kitg ) ) {\n\t\t\tpath_free2( path );\n\t\t\treturn( FALSE );\n\t\t}\n\t\tpath_free2( path );\n\n#ifdef DEBUG\n\t\tprintf( \"workspace_load_compat: loaded %d.%d\\n\", \n\t\t\tbest_major, best_minor );\n#endif /*DEBUG*/\n\n\t\tws->compat_major = best_major;\n\t\tws->compat_minor = best_minor;\n\t}\n\telse {\n#ifdef DEBUG\n\t\tprintf( \"workspace_load_compat: no compat necessary\\n\" ); \n#endif /*DEBUG*/\n\n\t\t/* No compat defs necessary for this ws. \n\t\t */\n\t\tws->compat_major = 0;\n\t\tws->compat_minor = 0;\n\t}\n\n\treturn( TRUE );\n}\n\nstatic void\nworkspace_class_init( WorkspaceClass *class )\n{\n\tGObjectClass *gobject_class = G_OBJECT_CLASS( class );\n\tiObjectClass *iobject_class = IOBJECT_CLASS( class );\n\tiContainerClass *icontainer_class = (iContainerClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->dispose = workspace_dispose;\n\tgobject_class->finalize = workspace_finalize;\n\n\tiobject_class->changed = workspace_changed;\n\tiobject_class->user_name = _( \"Tab\" );\n\n\ticontainer_class->child_add = workspace_child_add;\n\ticontainer_class->child_remove = workspace_child_remove;\n\ticontainer_class->current = workspace_current;\n\n\tmodel_class->view_new = workspace_view_new;\n\tmodel_class->load = workspace_load;\n\tmodel_class->save = workspace_save;\n\tmodel_class->empty = workspace_empty;\n\n\t/* Static init.\n\t */\n\tmodel_register_loadable( MODEL_CLASS( class ) );\n}\n\nstatic void\nworkspace_init( Workspace *ws )\n{\n\tws->sym = NULL;\n\n\t/* We default to using the main toolkitgroup for our definitions.\n\t * Unref and load private defs if we need compatibility.\n\t */\n\tws->kitg = main_toolkitgroup;\n\tg_object_ref( G_OBJECT( ws->kitg ) );\n\n\tws->next = 0;\n\tws->selected = NULL;\n\tws->errors = NULL;\n        ws->mode = WORKSPACE_MODE_REGULAR;\n\n\tws->major = MAJOR_VERSION;\n\tws->minor = MINOR_VERSION;\n\n\tws->compat_major = 0;\n\tws->compat_minor = 0;\n\n\tws->area.left = 0;\n\tws->area.top = 0;\n\tws->area.width = 0;\n\tws->area.height = 0;\n\tws->vp = ws->area;\n\n\tws->lpane_open = WORKSPACE_LPANE_OPEN;\n\tws->lpane_position = WORKSPACE_LPANE_POSITION;\n\tws->rpane_open = WORKSPACE_RPANE_OPEN;\n\tws->rpane_position = WORKSPACE_RPANE_POSITION;\n\n\tws->status = NULL;\n\n\tws->scale = 1.0;\n\tws->offset = 0.0;\n\n\tws->local_defs = im_strdupn( _( \n\t\t\"// private definitions for this tab\\n\" ) );\n\tws->local_kitg = NULL;\n\tws->local_kit = NULL;\n\n\tworkspace_all = g_slist_prepend( workspace_all, ws );\n}\n\nGType\nworkspace_get_type( void )\n{\n\tstatic GType workspace_type = 0;\n\n\tif( !workspace_type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( WorkspaceClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) workspace_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Workspace ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) workspace_init,\n\t\t};\n\n\t\tworkspace_type = g_type_register_static( TYPE_MODEL, \n\t\t\t\"Workspace\", &info, 0 );\n\t}\n\n\treturn( workspace_type );\n}\n\nWorkspace *\nworkspace_new( Workspacegroup *wsg, const char *name )\n{\n\tWorkspaceroot *wsr = wsg->wsr;\n\n\tWorkspace *ws;\n\n#ifdef DEBUG\n\tprintf( \"workspace_new: %s\\n\", name );\n#endif /*DEBUG*/\n\n\tif( compile_lookup( wsr->sym->expr->compile, name ) ) {\n\t\terror_top( _( \"Name clash.\" ) );\n\t\terror_sub( _( \"Can't create workspace \\\"%s\\\". \"\n\t\t\t\"A symbol with that name already exists.\" ), name );\n\t\treturn( NULL );\n\t}\n\n\tws = WORKSPACE( g_object_new( TYPE_WORKSPACE, NULL ) );\n\tworkspace_link( ws, wsg, name );\n\ticontainer_child_add( ICONTAINER( wsg ), ICONTAINER( ws ), -1 );\n\n\treturn( ws );\n}\n\n/* Make the blank workspace we present the user with (in the absence of\n * anything else).\n */\nWorkspace *\nworkspace_new_blank( Workspacegroup *wsg )\n{\n\tchar name[256];\n\tWorkspace *ws;\n\n\tworkspaceroot_name_new( wsg->wsr, name );\n\tif( !(ws = workspace_new( wsg, name )) )\n\t\treturn( NULL );\n\n\t/* Make an empty column.\n\t */\n\t(void) workspace_column_pick( ws );\n\n\ticontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) );\n\n\tiobject_set( IOBJECT( ws ), NULL, _( \"Default empty tab\" ) );\n\n\treturn( ws );\n}\n\n/* Get the bottom row from the current column.\n */\nstatic Row *\nworkspace_get_bottom( Workspace *ws )\n{\n\treturn( column_get_bottom( workspace_column_pick( ws ) ) );\n}\n\ngboolean\nworkspace_add_action( Workspace *ws, \n\tconst char *name, const char *action, int nparam )\n{\n\tColumn *col = workspace_column_pick( ws );\n\tchar txt[1024];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t/* Are there any selected symbols?\n\t */\n\tvips_buf_appends( &buf, action );\n\tif( nparam > 0 && workspace_selected_any( ws ) ) {\n\t\tif( nparam != workspace_selected_num( ws ) ) {\n\t\t\terror_top( _( \"Wrong number of arguments.\" ) );\n\t\t\terror_sub( _( \"%s needs %d arguments, \"\n\t\t\t\t\"there are %d selected.\" ), \n\t\t\t\tname, nparam,\n\t\t\t\tworkspace_selected_num( ws ) );\n\t\t\treturn( FALSE );\n\t\t}\n\n\t\tvips_buf_appends( &buf, \" \" );\n\t\tworkspace_selected_names( ws, &buf, \" \" );\n\t\tif( vips_buf_is_full( &buf ) ) {\n\t\t\terror_top( _( \"Overflow error.\" ) );\n\t\t\terror_sub( _( \"Too many names selected.\" ) );\n\t\t\treturn( FALSE );\n\t\t}\n\n\t\tif( !workspace_add_def_recalc( ws, vips_buf_all( &buf ) ) ) \n\t\t\treturn( FALSE );\n\t\tworkspace_deselect_all( ws );\n\t}\n\telse {\n\t\t/* Try to use the previous n items in this column as the\n\t\t * arguments. \n\t\t */\n\t\tif( !column_add_n_names( col, name, &buf, nparam ) || \n\t\t\t!workspace_add_def_recalc( ws, vips_buf_all( &buf ) ) ) \n\t\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nint\nworkspace_number( void )\n{\n\treturn( g_slist_length( workspace_all ) );\n}\n\nstatic void *\nworkspace_row_dirty( Row *row, int serial )\n{\n\treturn( expr_dirty( row->expr, serial ) );\n}\n\n/* Recalculate selected items.\n */\ngboolean\nworkspace_selected_recalc( Workspace *ws )\n{\n\tif( workspace_selected_map( ws,\n\t\t(row_map_fn) workspace_row_dirty, \n\t\t GINT_TO_POINTER( link_serial_new() ), NULL ) ) \n\t\treturn( FALSE );\n\n\t/* Recalc even if autorecomp is off.\n\t */\n\tsymbol_recalculate_all_force( TRUE );\n\n\tworkspace_deselect_all( ws );\n\n\treturn( TRUE );\n}\n\nstatic void *\nworkspace_selected_remove2( Row *row )\n{\n\tif( row != row->top_row )\n\t\treturn( row );\n\n\treturn( NULL );\n}\n\nstatic void *\nworkspace_selected_remove3( Row *row, int *nsel )\n{\n\tif( row->selected )\n\t\t*nsel += 1;\n\n\treturn( NULL );\n}\n\nstatic void *\nworkspace_selected_remove4( Column *col, GSList **cs )\n{\n\tint nsel = 0;\n\n\t(void) column_map( col, \n\t\t(row_map_fn) workspace_selected_remove3, &nsel, NULL );\n\tif( nsel > 0 )\n\t\t*cs = g_slist_prepend( *cs, col );\n\n\treturn( NULL );\n}\n\nstatic void *\nworkspace_selected_remove5( Column *col )\n{\n\tSubcolumn *scol = col->scol;\n\tint nmembers = g_slist_length( ICONTAINER( scol )->children );\n\n\tif( nmembers > 0 ) \n\t\ticontainer_pos_renumber( ICONTAINER( scol ) );\n\telse\n\t\tIDESTROY( col );\n\n\treturn( NULL );\n}\n\n/* Remove selected items.\n *\n * 0. check all objects to be destroyed are top level rows\n * 1. look for and note all columns containing items we are going to delete\n * 2. loop over selected items, and delete them one-by-one.\n * 3. loop over the columns we noted in 1 and delete empty ones\n * 4. renumber affected columns\n */\nstatic gboolean\nworkspace_selected_remove( Workspace *ws )\n{\n\tRow *row;\n\tGSList *cs = NULL;\n\n\tif( (row = (Row *) workspace_selected_map( ws,\n\t\t(row_map_fn) workspace_selected_remove2, NULL, NULL )) ) {\n\t\terror_top( _( \"You can only remove top level rows.\" ) );\n\t\terror_sub( _( \"Not all selected objects are top level \"\n\t\t\t\"rows.\" ) );\n\t\treturn( FALSE );\n\t}\n\n\t(void) workspace_map_column( ws, \n\t\t(column_map_fn) workspace_selected_remove4, &cs );\n\t(void) workspace_selected_map_sym( ws,\n\t\t(symbol_map_fn) iobject_destroy, NULL, NULL );\n\t(void) slist_map( cs, \n\t\t(SListMapFn) workspace_selected_remove5, NULL );\n\n\tIM_FREEF( g_slist_free, cs );\n\tsymbol_recalculate_all();\n\tworkspace_set_modified( ws, TRUE );\n\n\treturn( TRUE );\n}\n\n/* Callback for workspace_selected_remove_yesno. Remove selected items.\n */\nstatic void\nworkspace_selected_remove_yesno_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tWorkspace *ws = WORKSPACE( client );\n\n\tif( workspace_selected_remove( ws ) )\n\t\tnfn( sys, IWINDOW_YES );\n\telse\n\t\tnfn( sys, IWINDOW_ERROR );\n}\n\n/* Ask before removing selected.\n */\nvoid\nworkspace_selected_remove_yesno( Workspace *ws, GtkWidget *parent )\n{\n\tchar txt[30];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n        if( !workspace_selected_any( ws ) ) \n\t\treturn;\n\n\tworkspace_selected_names( ws, &buf, \", \" );\n\n\tbox_yesno( parent, \n\t\tworkspace_selected_remove_yesno_cb, iwindow_true_cb, ws, \n\t\tiwindow_notify_null, NULL,\n\t\tGTK_STOCK_DELETE, \n\t\t_( \"Delete selected objects?\" ),\n\t\t_( \"Are you sure you want to delete %s?\" ), vips_buf_all( &buf ) );\n}\n\n/* Sub fn of below ... add a new index expression.\n */\nstatic gboolean\nworkspace_ungroup_add_index( Row *row, const char *fmt, int i )\n{\n\tstatic char txt[200];\n\tstatic VipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tvips_buf_rewind( &buf );\n\trow_qualified_name( row, &buf );\n\tvips_buf_appendf( &buf, fmt, i );\n\tif( !workspace_add_def_recalc( row->ws, vips_buf_all( &buf ) ) )\n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\nstatic void *\nworkspace_ungroup_row( Row *row )\n{\n\tPElement *root = &row->expr->root;\n\tgboolean result;\n\tPElement value;\n\tint length;\n\tint i;\n\n\tif( !heap_is_instanceof( CLASS_GROUP, root, &result ) )\n\t\treturn( row );\n\tif( result ) {\n\t\tif( !class_get_member( root, MEMBER_VALUE, NULL, &value ) || \n\t\t\t(length = heap_list_length_max( &value, 100 )) < 0 ) \n\t\t\treturn( row );\n\n\t\tfor( i = 0; i < length; i++ )\n\t\t\tif( !workspace_ungroup_add_index( row, \n\t\t\t\t\".value?%d\", i ) )\n\t\t\t\treturn( row );\n\t}\n\telse {\n\t\tif( !heap_is_list( root, &result ) )\n\t\t\treturn( row );\n\t\tif( result ) {\n\t\t\tif( (length = heap_list_length_max( root, 100 )) < 0 ) \n\t\t\t\treturn( row );\n\n\t\t\tfor( i = 0; i < length; i++ )\n\t\t\t\tif( !workspace_ungroup_add_index( row, \n\t\t\t\t\t\"?%d\", i ) )\n\t\t\t\t\treturn( row );\n\t\t}\n\t\telse {\n\t\t\tchar txt[100];\n\t\t\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\t\t\trow_qualified_name( row, &buf );\n\t\t\terror_top( _( \"Unable to ungroup.\" ) );\n\t\t\terror_sub( _( \"Row \\\"%s\\\" is not a Group or a list.\" ), \n\t\t\t\tvips_buf_all( &buf ) );  \n\n\t\t\treturn( row );\n\t\t}\n\t}\n\n\treturn( NULL );\n}\n\n/* Ungroup the selected object(s), or the bottom object.\n */\ngboolean\nworkspace_selected_ungroup( Workspace *ws )\n{\n\tif( !workspace_selected_any( ws ) ) {\n\t\tRow *row;\n\n\t\tif( (row = workspace_get_bottom( ws )) ) {\n\t\t\tif( workspace_ungroup_row( row ) ) \n\t\t\t\treturn( FALSE );\n\n\t\t\tsymbol_recalculate_all();\n\t\t}\n\t}\n\telse {\n\t\t/* Ungroup selected symbols.\n\t\t */\n\t\tif( workspace_selected_map( ws,\n\t\t\t(row_map_fn) workspace_ungroup_row, NULL, NULL ) ) {\n\t\t\tsymbol_recalculate_all();\n\t\t\treturn( FALSE );\n\t\t}\n\t\tsymbol_recalculate_all();\n\t\tworkspace_deselect_all( ws );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Group the selected object(s).\n */\ngboolean\nworkspace_selected_group( Workspace *ws )\n{\n\tchar txt[MAX_STRSIZE];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tif( !workspace_selected_any( ws ) ) {\n\t\tRow *row;\n\n\t\tif( (row = workspace_get_bottom( ws )) )\n\t\t\trow_select( row );\n\t}\n\n\tvips_buf_appends( &buf, \"Group [\" );\n\tworkspace_selected_names( ws, &buf, \",\" );\n\tvips_buf_appends( &buf, \"]\" );\n\tif( !workspace_add_def_recalc( ws, vips_buf_all( &buf ) ) ) \n\t\treturn( FALSE );\n\tworkspace_deselect_all( ws );\n\n\treturn( TRUE );\n}\n\nstatic Row *\nworkspace_test_error( Row *row, Workspace *ws, int *found )\n{\n\tg_assert( row->err );\n\n\t/* Found next?\n\t */\n\tif( *found )\n\t\treturn( row );\n\n\tif( row == ws->last_error ) {\n\t\t/* Found the last one ... return the next one.\n\t\t */\n\t\t*found = 1;\n\t\treturn( NULL );\n\t}\n\n\treturn( NULL );\n}\n\n/* FALSE for no errors.\n */\ngboolean\nworkspace_next_error( Workspace *ws )\n{\n\tchar txt[MAX_LINELENGTH];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tint found;\n\n\tif( !ws->errors ) \n\t\treturn( FALSE ); \n\n\t/* Search for the one after the last one.\n\t */\n\tfound = 0;\n\tws->last_error = (Row *) slist_map2( ws->errors, \n\t\t(SListMap2Fn) workspace_test_error, ws, &found );\n\n\t/* NULL? We've hit end of table, start again.\n\t */\n\tif( !ws->last_error ) {\n\t\tfound = 1;\n\t\tws->last_error = (Row *) slist_map2( ws->errors, \n\t\t\t(SListMap2Fn) workspace_test_error, ws, &found );\n\t}\n\n\t/* *must* have one now.\n\t */\n\tg_assert( ws->last_error && ws->last_error->err );\n\n\tmodel_scrollto( MODEL( ws->last_error ), MODEL_SCROLL_TOP );\n\n\trow_qualified_name( ws->last_error->expr->row, &buf );\n\tvips_buf_appends( &buf, \": \" );\n\tvips_buf_appends( &buf, ws->last_error->expr->error_top );\n\tworkspace_set_status( ws, \"%s\", vips_buf_firstline( &buf ) );\n\n\treturn( TRUE ); \n}\n\nvoid\nworkspace_set_status( Workspace *ws, const char *fmt, ... )\n{\n\tva_list ap;\n\tchar buf[256];\n\n\tva_start( ap, fmt );\n\t(void) im_vsnprintf( buf, 256, fmt, ap );\n\tva_end( ap );\n\n\tIM_SETSTR( ws->status, buf );\n\tiobject_changed( IOBJECT( ws ) );\n}\n\nvoid\nworkspace_set_mode( Workspace *ws, WorkspaceMode mode )\n{\n\tif( ws->mode != mode ) {\n\t\tws->mode = mode;\n\n\t\t/* Rebuild all the views. Yuk! It would be better to get the\n\t\t * views that change with workspace mode to watch the\n\t\t * enclosing workspace and update on that. But we'd have\n\t\t * connections from almost every object in the ws. We don't\n\t\t * change mode very often, so just loop over them all.\n\t\t */\n\t\ticontainer_map_all( ICONTAINER( ws ),\n\t\t\t(icontainer_map_fn) iobject_changed, NULL );\n\t}\n}\n\n/* New ws private defs.\n */\ngboolean\nworkspace_local_set( Workspace *ws, const char *txt )\n{\n\t/* New kit for defs ... will destroy any old defs, since we can't have\n\t * two kits with the same name. Don't register it, we don't want it \n\t * to be autosaved on quit.\n\t */\n\tws->local_kit = toolkit_new( ws->local_kitg, \"Workspace Locals\" );\n\tfilemodel_unregister( FILEMODEL( ws->local_kit ) );\n\tIM_SETSTR( ws->local_defs, txt );\n\tiobject_changed( IOBJECT( ws ) );\n\n\tworkspace_set_modified( ws, TRUE );\n\tattach_input_string( txt );\n\tif( !parse_toplevel( ws->local_kit, 0 ) ) \n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\ngboolean\nworkspace_local_set_from_file( Workspace *ws, const char *fname )\n{\n\tiOpenFile *of;\n\tchar *txt;\n\n\tif( !(of = ifile_open_read( \"%s\", fname )) ) \n\t\treturn( FALSE );\n\tif( !(txt = ifile_read( of )) ) {\n\t\tifile_close( of );\n\t\treturn( FALSE );\n\t}\n\tif( !workspace_local_set( ws, txt ) ) {\n\t\tg_free( txt );\n\t\tifile_close( of );\n\t\treturn( FALSE );\n\t}\n\n\tfilemodel_set_filename( FILEMODEL( ws->local_kit ), fname );\n\n\tg_free( txt );\n\tifile_close( of );\n\n\treturn( TRUE );\n}\n\nstatic gint\nworkspace_jump_name_compare( iContainer *a, iContainer *b )\n{\n\tint la = strlen( IOBJECT( a )->name );\n\tint lb = strlen( IOBJECT( b )->name );\n\n\t/* Smaller names first.\n\t */\n\tif( la == lb )\n\t\treturn( strcmp( IOBJECT( a )->name, IOBJECT( b )->name ) );\n\telse\n\t\treturn( la - lb );\n}\n\nstatic void\nworkspace_jump_column_cb( GtkWidget *item, Column *column )\n{\n\tcolumn_scrollto( column, MODEL_SCROLL_TOP );\n}\n\nstatic void *\nworkspace_jump_build( Column *column, GtkWidget *menu )\n{\n\tGtkWidget *item;\n\tchar txt[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n\tvips_buf_appendf( &buf, \"%s - %s\", \n\t\tIOBJECT( column )->name, IOBJECT( column )->caption );\n\titem = gtk_menu_item_new_with_label( vips_buf_all( &buf ) );\n\tg_signal_connect( item, \"activate\",\n\t\tG_CALLBACK( workspace_jump_column_cb ), column );\n\tgtk_menu_append( GTK_MENU( menu ), item );\n\tgtk_widget_show( item );\n\n\treturn( NULL );\n}\n\n/* Update a menu with the set of current columns.\n */\nvoid\nworkspace_jump_update( Workspace *ws, GtkWidget *menu )\n{\n\tGSList *columns;\n\n\tgtk_container_foreach( GTK_CONTAINER( menu ),\n\t\t(GtkCallback) gtk_widget_destroy, NULL );\n\n\tcolumns = icontainer_get_children( ICONTAINER( ws ) );\n\n        columns = g_slist_sort( columns, \n\t\t(GCompareFunc) workspace_jump_name_compare );\n\tslist_map( columns, (SListMapFn) workspace_jump_build, menu );\n\n\tg_slist_free( columns );\n}\n\n/* Merge file into this workspace. \n */\ngboolean\nworkspace_merge_file( Workspace *ws, const char *filename )\n{\n\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\n\ticontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) );\n\n\treturn( workspacegroup_merge_columns( wsg, filename ) );\n}\n\n/* Duplicate selected rows in this workspace.\n */\ngboolean \nworkspace_selected_duplicate( Workspace *ws )\n{\n\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\n\tchar filename[FILENAME_MAX];\n\n\tif( !workspace_selected_any( ws ) ) {\n\t\tRow *row;\n\n\t\tif( (row = workspace_get_bottom( ws )) )\n\t\t\trow_select( row );\n\t}\n\n\tif( !temp_name( filename, \"ws\" ) )\n\t\treturn( FALSE );\n\tif( !workspace_selected_save( ws, filename ) ) \n\t\treturn( FALSE );\n\n        progress_begin();\n\n\tif( !workspacegroup_merge_rows( wsg, filename ) ) {\n\t\tprogress_end();\n\t\tunlinkf( \"%s\", filename );\n\n\t\treturn( FALSE );\n\t}\n\tunlinkf( \"%s\", filename );\n\n\tsymbol_recalculate_all();\n\tworkspace_deselect_all( ws );\n\tcolumn_scrollto( workspace_get_column( ws ), MODEL_SCROLL_BOTTOM );\n\n\tprogress_end();\n\n\treturn( TRUE );\n}\n\n/* Bounding box of columns to be saved. Though we only really set top/left.\n */\nstatic void *\nworkspace_selected_save_box( Column *col, Rect *box )\n{\n\tif( model_save_test( MODEL( col ) ) ) {\n\t\tif( im_rect_isempty( box ) ) {\n\t\t\tbox->left = col->x;\n\t\t\tbox->top = col->y;\n\t\t\tbox->width = 100;\n\t\t\tbox->height = 100;\n\t\t}\n\t\telse {\n\t\t\tbox->left = IM_MIN( box->left, col->x );\n\t\t\tbox->top = IM_MIN( box->top, col->y );\n\t\t}\n\t}\n\n\treturn( NULL );\n}\n\n/* Save just the selected objects.\n */\ngboolean\nworkspace_selected_save( Workspace *ws, const char *filename )\n{\n\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\n\tRect box = { 0 };\n\n\ticontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) );\n\n\tworkspace_map_column( ws, \n\t\t(column_map_fn) workspace_selected_save_box, \n\t\t&box );\n\n\tfilemodel_set_offset( FILEMODEL( wsg ), box.left, box.top );\n\n\tif( !workspacegroup_save_selected( wsg, filename ) ) \n\t\treturn( FALSE );\n\n\treturn( TRUE );\n}\n\ngboolean\nworkspace_rename( Workspace *ws, const char *name, const char *caption )\n{\n\tif( !symbol_rename( ws->sym, name ) )\n\t\treturn( FALSE );\n\tiobject_set( IOBJECT( ws ), IOBJECT( ws->sym )->name, caption );\n\tworkspace_set_modified( ws, TRUE );\n\n\tsymbol_recalculate_all();\n\n\treturn( TRUE );\n}\n\nvoid\nworkspace_set_locked( Workspace *ws, gboolean locked )\n{\n\tif( ws->locked != locked ) { \n\t\tws->locked = locked;\n\t\tiobject_changed( IOBJECT( ws ) ); \n\t\tworkspace_set_modified( ws, TRUE );\n\t}\n}\n\ngboolean\nworkspace_duplicate( Workspace *ws )\n{\n\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\n\tchar filename[FILENAME_MAX];\n\n\tif( !temp_name( filename, \"ws\" ) )\n\t\treturn( FALSE );\n\ticontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) );\n\tif( !workspacegroup_save_current( wsg, filename ) ) \n\t\treturn( FALSE );\n\n        progress_begin();\n\n\tif( !workspacegroup_merge_workspaces( wsg, filename ) ) {\n\t\tprogress_end();\n\t\tunlinkf( \"%s\", filename );\n\n\t\treturn( FALSE );\n\t}\n\tunlinkf( \"%s\", filename );\n\n\tsymbol_recalculate_all();\n\n\tprogress_end();\n\n\treturn( TRUE );\n}\n"
  },
  {
    "path": "src/workspace.h",
    "content": "/* Declarations for workspace.c.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_WORKSPACE (workspace_get_type())\n#define WORKSPACE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WORKSPACE, Workspace ))\n#define WORKSPACE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WORKSPACE, WorkspaceClass))\n#define IS_WORKSPACE( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WORKSPACE ))\n#define IS_WORKSPACE_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WORKSPACE ))\n#define WORKSPACE_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WORKSPACE, WorkspaceClass ))\n\n/* Three sorts of workspace file load.\n */\ntypedef enum {\n\tWORKSPACE_MODE_REGULAR, /* Vanilla! */\n\tWORKSPACE_MODE_FORMULA, /* Show formula, not values */\n\tWORKSPACE_MODE_NOEDIT\t/* Shut down all edits */\n} WorkspaceMode;\n\n/* A workspace.\n */\nstruct _Workspace {\n\tModel parent_object;\n\n\t/* Our rows are part of this symbol.\n\t */\n\tSymbol *sym;\n\n\t/* We are using this set of toolkits.\n\t */\n\tToolkitgroup *kitg;\n\n\t/* State.\n\t */\n\tint next;\t\t/* Index for next column name */\n\tGSList *selected;\t/* Rows selected in this workspace */\n\tGSList *errors;\t\t/* Rows with errors */\n        WorkspaceMode mode;\t/* Display mode */\n\tgboolean locked;\t/* WS has been locked */\n\n\t/* The nip2 version that made this workspace.\n\t */\n\tint major;\n\tint minor;\n\n\t/* We may load some compat definitions to support this workspace, if it\n\t * was written by an older version.\n\t *\n\t * The version number of the compat stuff we loaded. Zero for no compat\n\t * stuff loaded.\n\t */\n\tint compat_major;\n\tint compat_minor;\n\n\t/* The last row we scrolled to on next-error.\n\t */\n\tRow *last_error;\n\n\tRect area;\t\t/* Rect enclosing the set of columns */\n\tRect vp;\t\t/* Viewport hint ... set by views */\n\tgboolean lpane_open;\t/* Pane model */\n\tint lpane_position;\t\n\tgboolean rpane_open;\n\tint rpane_position;\n\n\tchar *status;\t\t/* Status message */\n\n\t/* Visualisation defaults for this ws.\n\t */\n\tdouble scale;\n\tdouble offset;\n\n\t/* Workspace-local defs, displayed in the left pane. All in a private\n\t * kitg and kit.\n\t */\n\tchar *local_defs;\n\tToolkitgroup *local_kitg;\n\tToolkit *local_kit;\n\n\t/* Some view inside this ws has changed and this ws needs a relayout.\n\t * Use in_dispose to stop relayout during ws shutdown.\n\t */\n\tgboolean needs_layout;\n\tgboolean in_dispose;\n};\n\ntypedef struct _WorkspaceClass {\n\tModelClass parent_class;\n\n\t/* Methods.\n\t */\n} WorkspaceClass;\n\nvoid workspace_set_needs_layout( Workspace *ws, gboolean needs_layout );\nGSList *workspace_get_needs_layout();\n\nWorkspacegroup *workspace_get_workspacegroup( Workspace *ws );\nWorkspaceroot *workspace_get_workspaceroot( Workspace *ws );\nvoid workspace_set_modified( Workspace *ws, gboolean modified );\n\nvoid *workspace_map( workspace_map_fn fn, void *a, void *b );\nvoid *workspace_map_column( Workspace *ws, column_map_fn fn, void *a );\nvoid *workspace_map_symbol( Workspace *ws, symbol_map_fn fn, void *a );\nvoid *workspace_map_view( Workspace *ws, view_map_fn fn, void *a );\n\ngboolean workspace_is_empty( Workspace *ws );\n\nvoid *workspace_selected_map( Workspace *ws, row_map_fn fn, void *a, void *b );\nvoid *workspace_selected_map_sym( Workspace *ws, \n\tsymbol_map_fn fn, void *a, void *b );\ngboolean workspace_selected_any( Workspace *ws );\nint workspace_selected_num( Workspace *ws );\ngboolean workspace_selected_sym( Workspace *ws, Symbol *sym );\nRow *workspace_selected_one( Workspace *ws );\nvoid workspace_deselect_all( Workspace *ws );\nvoid workspace_selected_names( Workspace *ws, \n\tVipsBuf *buf, const char *separator );\nvoid workspace_column_names( Column *col, \n\tVipsBuf *buf, const char *separator );\nvoid workspace_select_all( Workspace *ws );\nColumn *workspace_is_one_empty( Workspace *ws );\n\nColumn *workspace_column_find( Workspace *ws, const char *name );\nColumn *workspace_column_get( Workspace *ws, const char *name );\nvoid workspace_column_name_new( Workspace *ws, char *name );\nColumn *workspace_column_pick( Workspace *ws );\nvoid workspace_column_select( Workspace *ws, Column *col );\nColumn *workspace_column_new( Workspace *ws );\n\nSymbol *workspace_add_def( Workspace *ws, const char *str );\nSymbol *workspace_add_def_recalc( Workspace *ws, const char *str );\ngboolean workspace_load_file_buf( VipsBuf *buf, const char *filename );\nSymbol *workspace_load_file( Workspace *ws, const char *filename );\n\nvoid workspace_get_version( Workspace *ws, int *major, int *minor );\nint workspace_have_compat( int major, int minor, \n\tint *best_major, int *best_minor );\ngboolean workspace_load_compat( Workspace *ws, int major, int minor );\n\nGType workspace_get_type( void );\nWorkspace *workspace_new( Workspacegroup *wsg, const char *name );\nWorkspace *workspace_new_blank( Workspacegroup *wsg );\n\ngboolean workspace_add_action( Workspace *ws, \n\tconst char *name, const char *action, int nparam );\n\nint workspace_number( void );\n\ngboolean workspace_selected_recalc( Workspace *ws );\nvoid workspace_selected_remove_yesno( Workspace *ws, GtkWidget *parent );\ngboolean workspace_selected_ungroup( Workspace *ws );\ngboolean workspace_selected_group( Workspace *ws );\n\ngboolean workspace_next_error( Workspace *ws );\n\nvoid workspace_set_status( Workspace *ws, const char *fmt, ... )\n\t__attribute__((format(printf, 2, 3)));\n\nvoid workspace_set_mode( Workspace *ws, WorkspaceMode mode );\n\ngboolean workspace_local_set( Workspace *ws, const char *txt );\ngboolean workspace_local_set_from_file( Workspace *ws, const char *fname );\n\nvoid workspace_jump_update( Workspace *ws, GtkWidget *menu );\n\ngboolean workspace_merge_file( Workspace *ws, const char *filename );\ngboolean workspace_selected_duplicate( Workspace *ws );\ngboolean workspace_selected_save( Workspace *ws, const char *filename );\n\ngboolean workspace_rename( Workspace *ws, \n\tconst char *name, const char *caption );\nvoid workspace_set_locked( Workspace *ws, gboolean locked );\ngboolean workspace_duplicate( Workspace *ws );\n"
  },
  {
    "path": "src/workspacedefs.c",
    "content": "/* Workspace-local defs.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk \n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\nstatic void\nworkspacedefs_text_changed( GtkTextBuffer *buffer, \n\tWorkspacedefs *workspacedefs )\n{\n#ifdef DEBUG\n\tprintf( \"workspacedefs_text_changed\\n\" );\n#endif /*DEBUG*/\n\n\tif( !workspacedefs->changed ) {\n\t\tworkspacedefs->changed = TRUE;\n\n#ifdef DEBUG\n\t\tprintf( \"\\t(changed = TRUE)\\n\" );\n#endif /*DEBUG*/\n\n\t\t/* The workspace hasn't changed, but this will queue a refresh\n\t\t * on us.\n\t\t */\n\t\tiobject_changed( IOBJECT( workspacedefs->ws ) );\n\t}\n}\n\nstatic void\nworkspacedefs_refresh( vObject *vobject )\n{\n\tWorkspacedefs *workspacedefs = WORKSPACEDEFS( vobject );\n\tWorkspace *ws = workspacedefs->ws;\n\tchar txt[256];\n\tVipsBuf buf = VIPS_BUF_STATIC( txt );\n\n#ifdef DEBUG\n\tprintf( \"workspacedefs_refresh:\\n\" );\n#endif /*DEBUG*/\n\n\tif( !workspacedefs->changed ) {\n\t\tguint text_hash = g_str_hash( ws->local_defs );\n\n\t\tif( text_hash != workspacedefs->text_hash ) {\n\t\t\tg_signal_handlers_block_by_func( \n\t\t\t\tgtk_text_view_get_buffer( \n\t\t\t\t\tGTK_TEXT_VIEW( workspacedefs->text ) ),\n\t\t\t\tworkspacedefs_text_changed, workspacedefs );\n\t\t\ttext_view_set_text( \n\t\t\t\tGTK_TEXT_VIEW( workspacedefs->text ), \n\t\t\t\tws->local_defs, TRUE );\n\t\t\tg_signal_handlers_unblock_by_func( \n\t\t\t\tgtk_text_view_get_buffer( \n\t\t\t\t\tGTK_TEXT_VIEW( workspacedefs->text ) ),\n\t\t\t\tworkspacedefs_text_changed, workspacedefs );\n\n\t\t\tworkspacedefs->text_hash = text_hash;\n\t\t}\n\t}\n\n\tif( ws->local_kit ) {\n\t\tint n = icontainer_get_n_children( ICONTAINER( \n\t\t\tws->local_kit ) );\n\n\t\tvips_buf_appendf( &buf, ngettext( \"%d definition\", \n\t\t\t\"%d definitions\", n ), n );\n\t}\n\tif( workspacedefs->errors ) {\n\t\tif( !vips_buf_is_empty( &buf ) )\n\t\t\tvips_buf_appendf( &buf, \", \" ); \n\t\tvips_buf_appendf( &buf, _( \"errors\" ) ); \n\t}\n\tif( workspacedefs->changed ) {\n\t\tif( !vips_buf_is_empty( &buf ) )\n\t\t\tvips_buf_appendf( &buf, \", \" ); \n\t\tvips_buf_appendf( &buf, _( \"modified\" ) ); \n\t}\n\tset_glabel( workspacedefs->status, \"%s\", vips_buf_all( &buf ) );\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\nstatic void\nworkspacedefs_link( vObject *vobject, iObject *iobject )\n{\n\tWorkspacedefs *workspacedefs = WORKSPACEDEFS( vobject );\n\tWorkspace *ws = WORKSPACE( iobject );\n\n\tg_assert( !workspacedefs->ws );\n\n\tworkspacedefs->ws = ws;\n\n\tVOBJECT_CLASS( parent_class )->link( vobject, iobject );\n}\n\nstatic void\nworkspacedefs_class_init( WorkspacedefsClass *class )\n{\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tvobject_class->refresh = workspacedefs_refresh;\n\tvobject_class->link = workspacedefs_link;\n}\n\nstatic gboolean\nworkspacedefs_set_text_from_file( Workspacedefs *workspacedefs, \n\tconst char *fname )\n{\n\tWorkspace *ws = workspacedefs->ws;\n\n\tworkspacedefs->changed = FALSE;\n\tworkspacedefs->errors = FALSE;\n\tif( !workspace_local_set_from_file( ws, fname ) ) {\n\t\ttext_view_select_text( GTK_TEXT_VIEW( workspacedefs->text ), \n\t\t\tinput_state.charpos - yyleng, input_state.charpos );\n\t\tworkspacedefs->errors = TRUE;\n\n\t\treturn( FALSE );\n\t}\n\n\tsymbol_recalculate_all();\n\n\treturn( TRUE );\n}\n\n/* Callback from load browser.\n */\nstatic void\nworkspacedefs_load_file_cb( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( iwnd );\n\tWorkspacedefs *workspacedefs = WORKSPACEDEFS( client );\n\tchar *fname;\n\n\tif( !(fname = filesel_get_filename( filesel )) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tif( !workspacedefs_set_text_from_file( workspacedefs, fname ) ) {\n\t\tg_free( fname );\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tg_free( fname );\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void\nworkspacedefs_replace_cb( GtkWidget *wid, Workspacedefs *workspacedefs )\n{\n\tGtkWidget *filesel;\n\n\tfilesel = filesel_new();\n\tiwindow_set_title( IWINDOW( filesel ), \n\t\t_( \"Replace Definition From File\" ) );\n\tfilesel_set_flags( FILESEL( filesel ), FALSE, FALSE );\n\tfilesel_set_filetype( FILESEL( filesel ), filesel_type_definition, 0 ); \n\tiwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( wid ) );\n\tfilesel_set_done( FILESEL( filesel ), \n\t\tworkspacedefs_load_file_cb, workspacedefs );\n\tiwindow_build( IWINDOW( filesel ) );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\nstatic void\nworkspacedefs_save_as_cb( GtkWidget *wid, Workspacedefs *workspacedefs )\n{\n\tWorkspace *ws = workspacedefs->ws;\n\n\tif( ws->local_kit )\n\t\tfilemodel_inter_saveas( IWINDOW( wid ), \n\t\t\tFILEMODEL( ws->local_kit ) );\n}\n\nstatic gboolean\nworkspacedefs_set_text( Workspacedefs *workspacedefs, const char *txt )\n{\n\tWorkspace *ws = workspacedefs->ws;\n\n\tworkspacedefs->changed = FALSE;\n\tworkspacedefs->errors = FALSE;\n\tworkspacedefs->text_hash = g_str_hash( txt );\n\tif( !workspace_local_set( ws, txt ) ) {\n\t\ttext_view_select_text( GTK_TEXT_VIEW( workspacedefs->text ), \n\t\t\tinput_state.charpos - yyleng, input_state.charpos );\n\t\tworkspacedefs->errors = TRUE;\n\n\t\treturn( FALSE );\n\t}\n\n\tsymbol_recalculate_all();\n\n\treturn( TRUE );\n}\n\n/* \"Process\" in defs area.\n */\nstatic void\nworkspacedefs_process_cb( GtkWidget *wid, Workspacedefs *workspacedefs )\n{\n\tchar *txt;\n\n#ifdef DEBUG\n\tprintf( \"workspacedefs_process_cb:\\n\" );\n\tprintf( \"\\tchanged = FALSE\\n\" );\n#endif /*DEBUG*/\n\n\ttxt = text_view_get_text( GTK_TEXT_VIEW( workspacedefs->text ) );\n\tif( !workspacedefs_set_text( workspacedefs, txt ) )\n\t\tiwindow_alert( wid, GTK_MESSAGE_ERROR );\n\tg_free( txt );\n}\n\nstatic void\nworkspacedefs_init( Workspacedefs *workspacedefs )\n{\n\tGtkWidget *pane;\n\tPopupbutton *popupbutton;\n\tGtkWidget *swin;\n\tGtkWidget *hbox;\n\tGtkWidget *but;\n\n#ifdef DEBUG\n\tprintf( \"workspacedefs_init:\\n\" );\n#endif /*DEBUG*/\n\n\tworkspacedefs->changed = FALSE;\n\tworkspacedefs->errors = FALSE;\n\tworkspacedefs->text_hash = 0;\n\n\tpane = menu_build( _( \"Workspace definitions\" ) );\n\tmenu_add_but( pane, _( \"Replace From _File\" ),\n\t\tGTK_SIGNAL_FUNC( workspacedefs_replace_cb ), workspacedefs );\n\tmenu_add_but( pane, GTK_STOCK_SAVE_AS,\n\t\tGTK_SIGNAL_FUNC( workspacedefs_save_as_cb ), workspacedefs );\n\n\thbox = gtk_hbox_new( FALSE, 7 );\n\tgtk_box_pack_start( GTK_BOX( workspacedefs ), hbox, FALSE, FALSE, 0 );\n\tgtk_widget_show( hbox );\n\n\tpopupbutton = popupbutton_new();\n\tpopupbutton_set_menu( popupbutton, pane );\n        gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET( popupbutton ), \n\t\tFALSE, FALSE, 0 );\n\tgtk_widget_show( GTK_WIDGET( popupbutton ) );\n\n\tbut = gtk_button_new_with_label( _( \"Process\" ) );\n        g_signal_connect( G_OBJECT( but ), \"clicked\",\n                G_CALLBACK( workspacedefs_process_cb ), workspacedefs );\n\tgtk_box_pack_start( GTK_BOX( hbox ), but, FALSE, FALSE, 0 );\n\tgtk_widget_show( but );\n\tworkspacedefs->status = gtk_label_new( NULL );\n\tgtk_misc_set_alignment( GTK_MISC( workspacedefs->status ), 0, 0.5 );\n\tgtk_box_pack_start( GTK_BOX( hbox ), \n\t\tworkspacedefs->status, TRUE, TRUE, 0 );\n\tgtk_widget_show( workspacedefs->status );\n\n\tswin = gtk_scrolled_window_new( NULL, NULL );\n\tgtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( swin ),\n\t\tGTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );\n\tgtk_box_pack_end( GTK_BOX( workspacedefs ), swin, TRUE, TRUE, 0 );\n\tgtk_widget_show( swin );\n\tworkspacedefs->text = program_text_new();\n        g_signal_connect( gtk_text_view_get_buffer( \n\t\tGTK_TEXT_VIEW( workspacedefs->text ) ), \"changed\",\n                G_CALLBACK( workspacedefs_text_changed ), workspacedefs );\n\tgtk_container_add( GTK_CONTAINER( swin ), workspacedefs->text );\n\tgtk_widget_show( workspacedefs->text );\n}\n\nGtkType\nworkspacedefs_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Workspacedefs\",\n\t\t\tsizeof( Workspacedefs ),\n\t\t\tsizeof( WorkspacedefsClass ),\n\t\t\t(GtkClassInitFunc) workspacedefs_class_init,\n\t\t\t(GtkObjectInitFunc) workspacedefs_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_VOBJECT, &info );\n\t}\n\n\treturn( type );\n}\n\nWorkspacedefs *\nworkspacedefs_new( void )\n{\n\tWorkspacedefs *workspacedefs = gtk_type_new( TYPE_WORKSPACEDEFS );\n\n\treturn( workspacedefs );\n}\n\n"
  },
  {
    "path": "src/workspacedefs.h",
    "content": "/* Workspace-local defs\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_WORKSPACEDEFS (workspacedefs_get_type())\n#define WORKSPACEDEFS( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_WORKSPACEDEFS, Workspacedefs ))\n#define WORKSPACEDEFS_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_WORKSPACEDEFS, WorkspacedefsClass ))\n#define IS_WORKSPACEDEFS( obj ) \\\n\t(GTK_CHECK_TYPE( (obj), TYPE_WORKSPACEDEFS ))\n#define IS_WORKSPACEDEFS_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_WORKSPACEDEFS ))\n\nstruct _Workspacedefs {\n\tvObject parent_object;\n\n\tWorkspace *ws;\t\t\t/* Workspace we explore */\n\n\tGtkWidget *text;\t\n\tgboolean changed;\t\t/* Text has been edited */\n\tgboolean errors;\t\t/* Error on last process */\n\tguint text_hash;\t\t/* Hash of the last text we set */\n\tGtkWidget *status;\t\n};\n\ntypedef struct _WorkspacedefsClass {\n\tvObjectClass parent_class;\n\n} WorkspacedefsClass;\n\nGtkType workspacedefs_get_type( void );\nWorkspacedefs *workspacedefs_new( void );\n"
  },
  {
    "path": "src/workspacegroup.c",
    "content": "/* A set of workspaces loaded and saved from a ws file.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic FilemodelClass *parent_class = NULL;\n\nvoid\nworkspacegroup_set_load_type( Workspacegroup *wsg, \n\tWorkspacegroupLoadType load_type )\n{\n\twsg->load_type = load_type;\n}\n\nvoid\nworkspacegroup_set_save_type( Workspacegroup *wsg, \n\tWorkspacegroupSaveType save_type )\n{\n\twsg->save_type = save_type;\n}\n\nWorkspace *\nworkspacegroup_get_workspace( Workspacegroup *wsg )\n{\n\tif( ICONTAINER( wsg )->current )\n\t\treturn( WORKSPACE( ICONTAINER( wsg )->current ) ); \n\tif( ICONTAINER( wsg )->children )\n\t\treturn( WORKSPACE( ICONTAINER( wsg )->children->data ) ); \n\n\treturn( NULL ); \n}\n\nstatic Workspace *\nworkspacegroup_workspace_pick( Workspacegroup *wsg )\n{\n\tWorkspace *ws;\n\n\tif( (ws = workspacegroup_get_workspace( wsg )) )\n\t\treturn( ws );\n\n\tif( ICONTAINER( wsg )->children ) {\n\t\tws = WORKSPACE( ICONTAINER( wsg )->children->data );\n\t\ticontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) );\n\n\t\treturn( ws );\n\t}\n\n\tws = workspace_new_blank( wsg );\n\n\t(void) workspace_column_pick( ws ); \n\n\treturn( ws );\n}\n\nWorkspace *\nworkspacegroup_map( Workspacegroup *wsg, workspace_map_fn fn, void *a, void *b )\n{\n\treturn( (Workspace *) icontainer_map( ICONTAINER( wsg ), \n\t\t(icontainer_map_fn) fn, a, b ) );\n}\n\nstatic void *\nworkspacegroup_is_empty_sub( Workspace *ws, gboolean *empty )\n{\n\tif( !workspace_is_empty( ws ) ) {\n\t\t*empty = FALSE;\n\t\treturn( ws );\n\t}\n\n\treturn( NULL );\n}\n\ngboolean \nworkspacegroup_is_empty( Workspacegroup *wsg )\n{\n\tgboolean empty;\n\n\tempty = TRUE;\n\t(void) workspacegroup_map( wsg, \n\t\t(workspace_map_fn) workspacegroup_is_empty_sub, &empty, NULL );\n\n\treturn( empty );\n}\n\nstatic void *\nworkspacegroup_get_n_objects_sub( Workspace *ws, int *n_objects )\n{\n\tCompile *compile = ws->sym->expr->compile;\n\n\t*n_objects += g_slist_length( ICONTAINER( compile )->children );\n\n\treturn( NULL );\n}\n\nint\nworkspacegroup_get_n_objects( Workspacegroup *wsg )\n{\n\tint n_objects;\n\n\tn_objects = 0;\n\tworkspacegroup_map( wsg, \n\t\t(workspace_map_fn) workspacegroup_get_n_objects_sub, \n\t\t\t&n_objects, NULL );\n\n\treturn( n_objects );\n}\n\nstatic void \nworkspacegroup_dispose( GObject *gobject )\n{\n\tWorkspacegroup *wsg;\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_WORKSPACEGROUP( gobject ) );\n\n\twsg = WORKSPACEGROUP( gobject );\n\n#ifdef DEBUG\n\tprintf( \"workspacegroup_dispose %s\\n\", IOBJECT( wsg )->name );\n#endif /*DEBUG*/\n\n\tIM_FREEF( g_source_remove, wsg->autosave_timeout );\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic View *\nworkspacegroup_view_new( Model *model, View *parent )\n{\n\treturn( workspacegroupview_new() );\n}\n\nstatic void *\nworkspacegroup_save_sub( iContainer *icontainer, void *a, void *b )\n{\n\tWorkspace *ws = WORKSPACE( icontainer );\n\txmlNode *xnode = (xmlNode *) a;\n\tWorkspacegroup *wsg = WORKSPACEGROUP( b );\n\n\t/* Only save all workspaces in save-all mode. \n\t */\n\tif( wsg->save_type != WORKSPACEGROUP_SAVE_ALL &&\n\t\tWORKSPACE( ICONTAINER( wsg )->current ) != ws )\n\t\treturn( NULL );\n\n\treturn( model_save( MODEL( ws ), xnode ) );\n}\n\nstatic xmlNode *\nworkspacegroup_save( Model *model, xmlNode *xnode )\n{\n\t/* We normally chain up like this:\n\t *\n\t * \txthis = MODEL_CLASS( parent_class )->save( model, xnode )\n\t *\n\t * but that will make a workspacegroup holding our workspaces. Instead \n\t * we want to save all our workspaces directly to xnode with nothing \n\t * about us in there.\n\t *\n\t * See model_real_save().\n\t */\n\n\tif( icontainer_map( ICONTAINER( model ), \n\t\tworkspacegroup_save_sub, xnode, model ) )\n\t\treturn( NULL );\n\n\treturn( xnode );\n}\n\n/* Loops over xml trees follow this pattern.\n */\n#define FOR_ALL_XML( ROOT, CHILD, CHILD_NAME ) { \\\n\txmlNode *CHILD; \\\n\t\\\n\tfor( CHILD = ROOT->children; CHILD; CHILD = CHILD->next ) { \\\n\t\tif( strcmp( (char *) CHILD->name, CHILD_NAME ) != 0 ) \\\n\t\t\tcontinue;\n\n#define FOR_ALL_XML_END } }\n\nstatic void\nworkspacegroup_rename_workspace_node( Workspacegroup *wsg, \n\tModelLoadState *state, xmlNode *xws )\n{\n\tWorkspaceroot *wsr = wsg->wsr;\n\n\tchar name[MAX_STRSIZE];\n\tchar new_name[MAX_STRSIZE];\n\n\tif( !get_sprop( xws, \"name\", name, MAX_STRSIZE ) )\n\t\treturn;\n\n\tstrcpy( new_name, name );\n\twhile( compile_lookup( wsr->sym->expr->compile, new_name ) ||\n\t\tmodel_loadstate_taken( state, new_name ) )\n\t\tincrement_name( new_name );\n\n\t(void) set_sprop( xws, \"name\", new_name );\n\t(void) model_loadstate_rename_new( state, name, new_name );\n}\n\n/* Does a scrap of XML need compat defs?\n */\nstatic gboolean\nworkspacegroup_xml_needs_compat( ModelLoadState *state, xmlNode *xws, \n\tint *best_major, int *best_minor )\n{\n\tint major;\n\tint minor;\n\n\t/* What version is the XML expecting? A combination of the version of\n\t * nip that saved the file, and any compat notes on the workspace XML\n\t */\n\tif( !get_iprop( xws, \"major\", &major ) ||\n\t\t!get_iprop( xws, \"minor\", &minor ) ) {\n\t\t/* Fall back to the version number in the xml header.\n\t\t */\n\t\tmajor = state->major;\n\t\tminor = state->minor;\n\t}\n\n\t/* Find the best set of compat we have.\n\t */\n\treturn( workspace_have_compat( major, minor, best_major, best_minor ) );\n}\n\n/* Load all workspaces into this wsg.\n */\nstatic gboolean\nworkspacegroup_load_new( Workspacegroup *wsg, \n\tModelLoadState *state, xmlNode *xroot )\n{\n\tWorkspace *first_ws;\n\n\t/* Rename ... new names for any workspaces which clash. \n\t */\n\tFOR_ALL_XML( xroot, xws, \"Workspace\" ) {\n\t\tworkspacegroup_rename_workspace_node( wsg, state, xws );\n\t} FOR_ALL_XML_END\n\n\t/* _front() the first ws we load. Needed for things like duplicate ws\n\t * and merge wses.\n\t */\n\tfirst_ws = NULL;\n\n\tFOR_ALL_XML( xroot, xws, \"Workspace\" ) {\n\t\tchar name[MAX_STRSIZE];\n\t\tWorkspace *ws;\n\t\tint major;\n\t\tint minor;\n\n\t\tcolumn_set_offset( WORKSPACEVIEW_MARGIN_LEFT, \n\t\t\tWORKSPACEVIEW_MARGIN_TOP );\n\n\t\tif( !get_sprop( xws, \"name\", name, FILENAME_MAX ) || \n\t\t\t!(ws = workspace_new( wsg, name )) )\n\t\t\treturn( FALSE );\n\n\t\tif( workspacegroup_xml_needs_compat( state, xws, \n\t\t\t&major, &minor ) &&\n\t\t\t!workspace_load_compat( ws, major, minor ) ) \n\t\t\treturn( FALSE );\n\n\t\tif( model_load( MODEL( ws ), state, MODEL( wsg ), xws ) )\n\t\t\treturn( FALSE );\n\n\t\tif( !first_ws )\n\t\t\tfirst_ws = ws;\n\t} FOR_ALL_XML_END\n\n\tif( first_ws ) \n\t\ticontainer_current( ICONTAINER( wsg ), ICONTAINER( first_ws ) );\n\n\treturn( TRUE );\n}\n\nstatic void\nworkspacegroup_rename_row_node( Workspace *ws, \n\tModelLoadState *state, const char *col_name, xmlNode *xrow )\n{\n\tchar old_name[MAX_STRSIZE];\n\tchar new_name[MAX_STRSIZE];\n\n\tif( !get_sprop( xrow, \"name\", old_name, MAX_STRSIZE ) )\n\t\treturn;\n\n\tim_snprintf( new_name, MAX_STRSIZE, \"%s1\", col_name );\n\twhile( compile_lookup( ws->sym->expr->compile, new_name ) ||\n\t\tmodel_loadstate_taken( state, new_name ) )\n\t\tincrement_name( new_name );\n\n\t(void) set_sprop( xrow, \"name\", new_name );\n\t(void) model_loadstate_rename_new( state, old_name, new_name );\n\n#ifdef DEBUG\n\tprintf( \"workspacegroup_rename_row_node: renaming \"\n\t\t\"'%s' to '%s'\\n\", old_name, new_name );\n#endif\n}\n\n/* Rename column if there's one of that name in workspace. \n */\nstatic void\nworkspacegroup_rename_column_node( Workspacegroup *wsg, \n\tWorkspace *ws, ModelLoadState *state, xmlNode *xcol )\n{\n\tchar name[MAX_STRSIZE];\n\tchar new_name[256];\n\n\tif( !get_sprop( xcol, \"name\", name, MAX_STRSIZE ) )\n\t\treturn;\n\n\tim_strncpy( new_name, name, 256 );\n\twhile( workspace_column_find( ws, new_name ) ||\n\t\tmodel_loadstate_column_taken( state, new_name ) ) \n\t\tworkspace_column_name_new( ws, new_name );\n\n\tif( strcmp( name, new_name ) != 0 ) { \n#ifdef DEBUG\n\t\tprintf( \"workspace_rename_column_node: renaming column \"\n\t\t\t\"%s to %s\\n\", name, new_name );\n#endif /*DEBUG*/\n\n\t\t(void) set_sprop( xcol, \"name\", new_name );\n\t\t(void) model_loadstate_column_rename_new( state, \n\t\t\tname, new_name ); \n\n\t\t/* And allocate new names for all rows in the subcolumn.\n\t\t */\n\t\tFOR_ALL_XML( xcol, xsub, \"Subcolumn\" ) {\n\t\t\tFOR_ALL_XML( xsub, xrow, \"Row\" ) {\n\t\t\t\tworkspacegroup_rename_row_node( ws, state, \n\t\t\t\t\tnew_name, xrow );\n\t\t\t} FOR_ALL_XML_END\n\t\t} FOR_ALL_XML_END\n\t}\n}\n\n/* Load at column level ... rename columns which clash with \n * columns in the current workspace. Also look out for clashes\n * with columns we will load.\n */\nstatic gboolean\nworkspacegroup_load_columns( Workspacegroup *wsg, \n\tModelLoadState *state, xmlNode *xroot )\n{\n\tWorkspace *ws = workspacegroup_workspace_pick( wsg );\n\n\tint xml_major;\n\tint xml_minor;\n\tgboolean found;\n\tint ws_major;\n\tint ws_minor;\n\n\t/* Look for any compat problems.\n\t */\n\tfound = FALSE;\n\tFOR_ALL_XML( xroot, xws, \"Workspace\" ) { \n\t\tif( workspacegroup_xml_needs_compat( state, xws, \n\t\t\t&xml_major, &xml_minor ) ) {\n\t\t\tfound = TRUE;\n\t\t\tbreak;\n\t\t}\n\t} FOR_ALL_XML_END\n\n\tworkspace_get_version( ws, &ws_major, &ws_minor );\n\tif( found &&\n\t\t(xml_major != ws_major ||\n\t\txml_minor != ws_minor) ) {\n\t\terror_top( _( \"Version mismatch.\" ) );\n\t\terror_sub( _( \"File \\\"%s\\\" needs version %d.%d. Merging \"\n\t\t\t\"into this tab may cause compatibility problems.\" ),\n\t\t\tstate->filename, xml_major, xml_minor );\n\t\tiwindow_alert( GTK_WIDGET( wsg->iwnd ), GTK_MESSAGE_INFO );\n\t}\n\n\t/* Search all the columns we will load for their names and add rename\n\t * rules.\n\t */\n\tFOR_ALL_XML( xroot, xws, \"Workspace\" ) { \n\t\tFOR_ALL_XML( xws, xcol, \"Column\" ) { \n\t\t\tworkspacegroup_rename_column_node( wsg, ws, \n\t\t\t\tstate, xcol );\n\t\t} FOR_ALL_XML_END\n\t} FOR_ALL_XML_END\n\n\t/* Load those columns.\n\t */\n\tFOR_ALL_XML( xroot, xws, \"Workspace\" ) { \n\t\tFOR_ALL_XML( xws, xcol, \"Column\" ) { \n\t\t\tif( !model_new_xml( state, MODEL( ws ), xcol ) )\n\t\t\t\treturn( FALSE );\n\t\t} FOR_ALL_XML_END\n\t} FOR_ALL_XML_END\n\n\treturn( TRUE ); \n}\n\n/* Load at row level ... merge into the current column.\n */\nstatic gboolean\nworkspacegroup_load_rows( Workspacegroup *wsg, \n\tModelLoadState *state, xmlNode *xroot )\n{\n\tWorkspace *ws = workspacegroup_workspace_pick( wsg );\n\tColumn *col = workspace_column_pick( ws );\n\n\tint xml_major;\n\tint xml_minor;\n\tgboolean found;\n\tint ws_major;\n\tint ws_minor;\n\n\t/* Look for any compat problems.\n\t */\n\tfound = FALSE;\n\tFOR_ALL_XML( xroot, xws, \"Workspace\" ) { \n\t\tif( workspacegroup_xml_needs_compat( state, xws, \n\t\t\t&xml_major, &xml_minor ) ) {\n\t\t\tfound = TRUE;\n\t\t\tbreak;\n\t\t}\n\t} FOR_ALL_XML_END\n\n\tworkspace_get_version( ws, &ws_major, &ws_minor );\n\tif( found &&\n\t\t(xml_major != ws_major ||\n\t\txml_minor != ws_minor) ) {\n\t\terror_top( _( \"Version mismatch.\" ) );\n\t\terror_sub( _( \"File \\\"%s\\\" needs version %d.%d. Merging \"\n\t\t\t\"into this tab may cause compatibility problems.\" ),\n\t\t\tstate->filename, xml_major, xml_minor );\n\t\tiwindow_alert( GTK_WIDGET( wsg->iwnd ), GTK_MESSAGE_INFO );\n\t}\n\n\tFOR_ALL_XML( xroot, xws, \"Workspace\" ) {\n\t\tFOR_ALL_XML( xws, xcol, \"Column\" ) {\n\t\t\tFOR_ALL_XML( xcol, xsub, \"Subcolumn\" ) {\n\t\t\t\tFOR_ALL_XML( xsub, xrow, \"Row\" ) {\n\t\t\t\t\tworkspacegroup_rename_row_node( ws, \n\t\t\t\t\t\tstate, IOBJECT( col )->name, \n\t\t\t\t\t\txrow );\n\t\t\t\t} FOR_ALL_XML_END\n\t\t\t} FOR_ALL_XML_END\n\t\t} FOR_ALL_XML_END\n\t} FOR_ALL_XML_END\n\n\tFOR_ALL_XML( xroot, xws, \"Workspace\" ) {\n\t\tFOR_ALL_XML( xws, xcol, \"Column\" ) {\n\t\t\tFOR_ALL_XML( xcol, xsub, \"Subcolumn\" ) {\n\t\t\t\tFOR_ALL_XML( xsub, xrow, \"Row\" ) {\n\t\t\t\t\tif( !model_new_xml( state,\n\t\t\t\t\t\tMODEL( col->scol ),\n\t\t\t\t\t\txrow ) )\n\t\t\t\t\t\treturn( FALSE );\n\t\t\t\t} FOR_ALL_XML_END\n\t\t\t} FOR_ALL_XML_END\n\t\t} FOR_ALL_XML_END\n\t} FOR_ALL_XML_END\n\n\treturn( TRUE ); \n}\n\nstatic gboolean\nworkspacegroup_top_load( Filemodel *filemodel,\n\tModelLoadState *state, Model *parent, xmlNode *xroot )\n{\n\tWorkspacegroup *wsg = WORKSPACEGROUP( filemodel );\n\n\txmlNode *xnode;\n\tchar name[FILENAME_MAX];\n\n#ifdef DEBUG\n\tprintf( \"workspacegroup_top_load: from %s\\n\", state->filename );\n#endif /*DEBUG*/\n\n\t/* The top node should be the first workspace. Get the filename this\n\t * workspace was saved as so we can work out how to rewrite embedded\n\t * filenames.\n\t *\n\t * The filename field can be missing. \n\t */\n\tif( (xnode = get_node( xroot, \"Workspace\" )) &&\n\t\tget_sprop( xnode, \"filename\", name, FILENAME_MAX ) ) {\n\t\tchar *new_dir;\n\n\t\t/* The old filename could be non-native, so we must rewrite \n\t\t * to native form first so g_path_get_dirname() can work.\n\t\t */\n\t\tpath_compact( name );\n\n\t\tstate->old_dir = g_path_get_dirname( name ); \n\n\t\tnew_dir = g_path_get_dirname( state->filename_user );\n\t\tpath_rewrite_add( state->old_dir, new_dir, FALSE );\n\t\tg_free( new_dir );\n\t}\n\n\tswitch( wsg->load_type ) {\n\tcase WORKSPACEGROUP_LOAD_NEW:\n\t\tif( !workspacegroup_load_new( wsg, state, xroot ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase WORKSPACEGROUP_LOAD_COLUMNS:\n\t\tif( !workspacegroup_load_columns( wsg, state, xroot ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tcase WORKSPACEGROUP_LOAD_ROWS:\n\t\tif( !workspacegroup_load_rows( wsg, state, xroot ) )\n\t\t\treturn( FALSE );\n\t\tbreak;\n\n\tdefault:\n\t\tg_assert( FALSE );\n\t}\n\n\treturn( FILEMODEL_CLASS( parent_class )->top_load( filemodel, \n\t\tstate, parent, xnode ) );\n}\n\nstatic gboolean\nworkspacegroup_top_save( Filemodel *filemodel, const char *filename )\n{\n\tgboolean result;\n\n#ifdef DEBUG\n\tprintf( \"workspacegroup_top_save: %s to %s\\n\",\n\t\tNN( IOBJECT( filemodel )->name ), filename );\n#endif /*DEBUG*/\n\n\tif( (result = FILEMODEL_CLASS( parent_class )->\n\t\ttop_save( filemodel, filename )) )\n\t\t/* This will add save-as files to recent too. Don't note\n\t\t * auto_load on recent, since it won't have been loaded by the\n\t\t * user.\n\t\t */\n\t\tif( !filemodel->auto_load )\n\t\t\tmainw_recent_add( &mainw_recent_workspace, filename );\n\n\treturn( result );\n}\n\n/* Backup the last WS_RETAIN workspaces.\n */\n#define WS_RETAIN (10)\n\n/* Array of names of workspace files we are keeping.\n */\nstatic char *retain_files[WS_RETAIN] = { NULL };\n\n/* On safe exit, remove all ws checkmarks.\n */\nvoid\nworkspacegroup_autosave_clean( void )\n{\n\tint i;\n\n\tfor( i = 0; i < WS_RETAIN; i++ ) {\n\t\tif( retain_files[i] ) {\n\t\t\tunlinkf( \"%s\", retain_files[i] );\n\t\t\tIM_FREE( retain_files[i] );\n\t\t}\n\t}\n}\n\n/* Save the workspace to one of our temp files.\n */\nstatic gboolean\nworkspacegroup_checkmark_timeout( Workspacegroup *wsg )\n{\n\t/* The next one we allocate.\n\t */\n\tstatic int retain_next = 0;\n\n\twsg->autosave_timeout = 0;\n\n\tif( !AUTO_WS_SAVE )\n\t\treturn( FALSE );\n\n\t/* Don't backup auto loaded workspace (eg. preferences). These are\n\t * system things and don't need it.\n\t */\n\tif( FILEMODEL( wsg )->auto_load )\n\t\treturn( FALSE );\n\n\t/* Do we have a name for this retain file?\n\t */\n\tif( !retain_files[retain_next] ) {\n\t\tchar filename[FILENAME_MAX];\n\n\t\t/* No name yet - make one up.\n\t\t */\n\t\tif( !temp_name( filename, \"ws\" ) )\n\t\t\treturn( FALSE );\n\t\tretain_files[retain_next] = im_strdup( NULL, filename );\n\t}\n \n\tif( !filemodel_top_save( FILEMODEL( wsg ), retain_files[retain_next] ) )\n\t\treturn( FALSE );\n\n\tretain_next = (retain_next + 1) % WS_RETAIN;\n\n\treturn( FALSE );\n}\n\n/* Save the workspace to one of our temp files. Don't save directly (pretty\n * slow), instead set a timeout and save when we're quiet for >1s.\n */\nstatic void\nworkspacegroup_checkmark( Workspacegroup *wsg )\n{\n\tif( !AUTO_WS_SAVE )\n\t\treturn;\n\tif( FILEMODEL( wsg )->auto_load )\n\t\treturn;\n\n\tIM_FREEF( g_source_remove, wsg->autosave_timeout );\n\twsg->autosave_timeout = g_timeout_add( 1000, \n\t\t(GSourceFunc) workspacegroup_checkmark_timeout, wsg );\n}\n\ntypedef struct {\n\t/* Best so far filename.\n\t */\n\tchar filename[FILENAME_MAX];\n\n\t/* Best-so-far file date.\n\t */\n\ttime_t time;\n} AutoRecover;\n\n/* This file any better than the previous best candidate? Subfn of below.\n */\nstatic void *\nworkspacegroup_test_file( const char *name, void *a, void *b, void *c )\n{\n\tAutoRecover *recover = (AutoRecover *) a;\n\n\tchar buf[FILENAME_MAX];\n\ttime_t time;\n\tint i;\n\n\tim_strncpy( buf, name, FILENAME_MAX );\n\tpath_expand( buf );\n\tfor( i = 0; i < WS_RETAIN; i++ )\n\t\tif( retain_files[i] && \n\t\t\tstrcmp( buf, retain_files[i] ) == 0 )\n\t\t\treturn( NULL );\n\tif( !(time = mtime( \"%s\", buf )) )\n\t\treturn( NULL );\n\tif( recover->time > 0 && time < recover->time )\n\t\treturn( NULL );\n\t\n\tstrcpy( recover->filename, buf );\n\trecover->time = time;\n\n\treturn( NULL );\n}\n\n/* Search for the most recent \"*.ws\" file \n * in the tmp area owned by us, with a size > 0, that's not in our\n * retain_files[] set.\n */\nchar *\nworkspacegroup_autosave_recover( void )\n{\n\tAutoRecover recover;\n\n\tstrcpy( recover.filename, \"\" ); \n\trecover.time = 0;  \n\t(void) path_map_dir( PATH_TMP, \"*.ws\", \n\t\t(path_map_fn) workspacegroup_test_file, &recover );\n\n\tif( !recover.time )\n\t\treturn( NULL );\n\n\treturn( g_strdup( recover.filename ) ); \n}\n\nstatic void \nworkspacegroup_set_modified( Filemodel *filemodel, gboolean modified )\n{\n\tWorkspacegroup *wsg = WORKSPACEGROUP( filemodel );\n\n\tworkspacegroup_checkmark( wsg );\n\n\tFILEMODEL_CLASS( parent_class )->set_modified( filemodel, modified );\n}\n\nstatic void\nworkspacegroup_class_init( WorkspacegroupClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiObjectClass *iobject_class = (iObjectClass *) class;\n\tModelClass *model_class = (ModelClass *) class;\n\tFilemodelClass *filemodel_class = (FilemodelClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->dispose = workspacegroup_dispose;\n\n\tiobject_class->user_name = _( \"Workspace\" );\n\n\t/* ->load() is done by workspace_top_load().\n\t */\n\tmodel_class->view_new = workspacegroup_view_new;\n\tmodel_class->save = workspacegroup_save;\n\n\tfilemodel_class->filetype = filesel_type_workspace;\n\tfilemodel_class->top_load = workspacegroup_top_load;\n\tfilemodel_class->top_save = workspacegroup_top_save;\n\tfilemodel_class->set_modified = workspacegroup_set_modified;\n}\n\nstatic void\nworkspacegroup_init( Workspacegroup *wsg )\n{\n}\n\nGType\nworkspacegroup_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( WorkspacegroupClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) workspacegroup_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Workspacegroup ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) workspacegroup_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_FILEMODEL, \n\t\t\t\"Workspacegroup\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\nworkspacegroup_link( Workspacegroup *wsg, Workspaceroot *wsr )\n{\n\ticontainer_child_add( ICONTAINER( wsr ), ICONTAINER( wsg ), -1 );\n\twsg->wsr = wsr;\n\tfilemodel_register( FILEMODEL( wsg ) );\n}\n\nWorkspacegroup *\nworkspacegroup_new( Workspaceroot *wsr )\n{\n\tWorkspacegroup *wsg;\n\n#ifdef DEBUG\n\tprintf( \"workspacegroup_new:\\n\" ); \n#endif /*DEBUG*/\n\n\twsg = WORKSPACEGROUP( g_object_new( TYPE_WORKSPACEGROUP, NULL ) );\n\t/* Changed later.\n\t */\n\tiobject_set( IOBJECT( wsg ), \"untitled\", _( \"Empty workspace\" ) );\n\tworkspacegroup_link( wsg, wsr );\n\tfilemodel_set_modified( FILEMODEL( wsg ), FALSE );\n\n\treturn( wsg );\n}\n\n/* Make the blank workspacegroup we present the user with (in the absence of\n * anything else).\n */\nWorkspacegroup *\nworkspacegroup_new_blank( Workspaceroot *wsr, const char *name )\n{\n\tWorkspacegroup *wsg;\n\n\tif( !(wsg = workspacegroup_new( wsr )) )\n\t\treturn( NULL );\n\tiobject_set( IOBJECT( wsg ), name, NULL );\n\t(void) workspacegroup_workspace_pick( wsg ); \n\tfilemodel_set_modified( FILEMODEL( wsg ), FALSE );\n\n\treturn( wsg );\n}\n\nWorkspacegroup *\nworkspacegroup_new_filename( Workspaceroot *wsr, const char *filename )\n{\n\tWorkspacegroup *wsg;\n\tchar name[FILENAME_MAX];\n\n\tif( !(wsg = workspacegroup_new( wsr )) )\n\t\treturn( NULL ); \n\tname_from_filename( filename, name );\n\tiobject_set( IOBJECT( wsg ), name, _( \"Default empty workspace\" ) );\n\tfilemodel_set_filename( FILEMODEL( wsg ), filename );\n\tfilemodel_set_modified( FILEMODEL( wsg ), FALSE );\n\n\treturn( wsg );\n}\n\n/* Load a file as a workspacegroup.\n */\nWorkspacegroup *\nworkspacegroup_new_from_file( Workspaceroot *wsr, \n\tconst char *filename, const char *filename_user )\n{\n\tWorkspacegroup *wsg;\n\n\tif( !(wsg = workspacegroup_new( wsr )) )\n\t\treturn( NULL );\n\n\tworkspacegroup_set_load_type( wsg, WORKSPACEGROUP_LOAD_NEW );\n\tif( !filemodel_load_all( FILEMODEL( wsg ), \n\t\tMODEL( wsr ), filename, filename_user ) ) \n\t\treturn( NULL );\n\n\tfilemodel_set_filename( FILEMODEL( wsg ), filename_user );\n\tfilemodel_set_modified( FILEMODEL( wsg ), FALSE );\n\n\tif( filename_user ) {\n\t\tchar name[FILENAME_MAX];\n\n\t\tname_from_filename( filename_user, name );\n\t\tiobject_set( IOBJECT( wsg ), name, NULL );\n\t}\n\telse\n\t\tiobject_set( IOBJECT( wsg ), \"untitled\", NULL );\n\n\treturn( wsg );\n}\n\n/* New workspacegroup from a file.\n */\nWorkspacegroup *\nworkspacegroup_new_from_openfile( Workspaceroot *wsr, iOpenFile *of )\n{\n\tWorkspacegroup *wsg;\n\tchar name[FILENAME_MAX];\n\n#ifdef DEBUG\n\tprintf( \"workspacegroup_new_from_openfile: %s\\n\", of->fname );\n#endif /*DEBUG*/\n\n\tif( !(wsg = workspacegroup_new( wsr )) )\n\t\treturn( NULL );\n\n\tworkspacegroup_set_load_type( wsg, WORKSPACEGROUP_LOAD_NEW );\n\tif( !filemodel_load_all_openfile( FILEMODEL( wsg ), \n\t\tMODEL( wsr ), of ) ) {\n\t\tg_object_unref( G_OBJECT( wsg ) );\n\t\treturn( NULL );\n\t}\n\n\tfilemodel_set_filename( FILEMODEL( wsg ), of->fname );\n\tfilemodel_set_modified( FILEMODEL( wsg ), FALSE );\n\n\tname_from_filename( of->fname, name );\n\tiobject_set( IOBJECT( wsg ), name, NULL );\n\n\treturn( wsg );\n}\n\n/* Merge into workspacegroup as a set of new workspaces.\n */\ngboolean\nworkspacegroup_merge_workspaces( Workspacegroup *wsg, const char *filename )\n{\n\tworkspacegroup_set_load_type( wsg, WORKSPACEGROUP_LOAD_NEW );\n\tif( !filemodel_load_all( FILEMODEL( wsg ), MODEL( wsg->wsr ), \n\t\tfilename, NULL ) ) \n\t\treturn( FALSE );\n\n\tfilemodel_set_modified( FILEMODEL( wsg ), TRUE );\n\n\treturn( TRUE );\n}\n\n/* Merge into the current workspace as a set of columns. \n */\ngboolean\nworkspacegroup_merge_columns( Workspacegroup *wsg, const char *filename )\n{\n\tWorkspace *ws;\n\n\tif( (ws = workspacegroup_get_workspace( wsg )) ) \n\t\t/* We'll do a layout after load, so just load to a huge x and\n\t\t * we'll be OK.\n\t\t */\n\t\tcolumn_set_offset( \n\t\t\t2 * IM_RECT_RIGHT( &ws->area ) + \n\t\t\t\tWORKSPACEVIEW_MARGIN_LEFT,\n\t\t\tWORKSPACEVIEW_MARGIN_TOP );\n\n\tworkspacegroup_set_load_type( wsg, WORKSPACEGROUP_LOAD_COLUMNS );\n\tif( !filemodel_load_all( FILEMODEL( wsg ), MODEL( wsg->wsr ), \n\t\tfilename, NULL ) ) \n\t\treturn( FALSE );\n\n\tfilemodel_set_modified( FILEMODEL( wsg ), TRUE );\n\n\treturn( TRUE );\n}\n\n/* Merge into the current workspace as a set of rows.  \n */\ngboolean\nworkspacegroup_merge_rows( Workspacegroup *wsg, const char *filename )\n{\n\tworkspacegroup_set_load_type( wsg, WORKSPACEGROUP_LOAD_ROWS );\n\tif( !filemodel_load_all( FILEMODEL( wsg ), MODEL( wsg->wsr ), \n\t\tfilename, NULL ) ) \n\t\treturn( FALSE );\n\n\tfilemodel_set_modified( FILEMODEL( wsg ), TRUE );\n\n\treturn( TRUE );\n}\n\n/* Save just the selected objects in the current workspace. \n */\ngboolean\nworkspacegroup_save_selected( Workspacegroup *wsg, const char *filename )\n{\n\tworkspacegroup_set_save_type( wsg, WORKSPACEGROUP_SAVE_SELECTED );\n\tif( !filemodel_top_save( FILEMODEL( wsg ), filename ) ) {\n\t\tunlinkf( \"%s\", filename );\n\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Save just the current workspace. \n */\ngboolean\nworkspacegroup_save_current( Workspacegroup *wsg, const char *filename )\n{\n\tworkspacegroup_set_save_type( wsg, WORKSPACEGROUP_SAVE_WORKSPACE );\n\tif( !filemodel_top_save( FILEMODEL( wsg ), filename ) ) {\n\t\tunlinkf( \"%s\", filename );\n\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\n/* Save an entire workspacegroup.\n */\ngboolean\nworkspacegroup_save_all( Workspacegroup *wsg, const char *filename )\n{\n\tworkspacegroup_set_save_type( wsg, WORKSPACEGROUP_SAVE_ALL );\n\tif( !filemodel_top_save( FILEMODEL( wsg ), filename ) ) {\n\t\tunlinkf( \"%s\", filename );\n\n\t\treturn( FALSE );\n\t}\n\n\treturn( TRUE );\n}\n\nWorkspacegroup *\nworkspacegroup_duplicate( Workspacegroup *wsg )\n{\n\tWorkspaceroot *wsr = wsg->wsr;\n\n\tWorkspacegroup *new_wsg;\n\tchar filename[FILENAME_MAX];\n\n\tif( !temp_name( filename, \"ws\" ) ||\n\t\t!workspacegroup_save_all( wsg, filename ) ) \n\t\treturn( NULL );\n\n\tif( !(new_wsg = workspacegroup_new_from_file( wsr, \n\t\tfilename, FILEMODEL( wsg )->filename )) ) {\n\t\tunlinkf( \"%s\", filename );\n\t\treturn( NULL );\n\t}\n\tunlinkf( \"%s\", filename );\n\n\treturn( new_wsg );\n}\n"
  },
  {
    "path": "src/workspacegroup.h",
    "content": "/* A set of workspaces loaded and saved from a ws file.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_WORKSPACEGROUP (workspacegroup_get_type())\n#define WORKSPACEGROUP( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), \\\n\t\tTYPE_WORKSPACEGROUP, Workspacegroup ))\n#define WORKSPACEGROUP_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_WORKSPACEGROUP, WorkspacegroupClass))\n#define IS_WORKSPACEGROUP( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WORKSPACEGROUP ))\n#define IS_WORKSPACEGROUP_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WORKSPACEGROUP ))\n#define WORKSPACEGROUP_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), \\\n\t\tTYPE_WORKSPACEGROUP, WorkspacegroupClass ))\n\n/* Three sorts of workspace file load.\n */\ntypedef enum {\n\tWORKSPACEGROUP_LOAD_NEW,\t/* Load as new workspace */\n\tWORKSPACEGROUP_LOAD_COLUMNS,\t/* Merge into current workspace */\n\tWORKSPACEGROUP_LOAD_ROWS\t/* Merge rows into current column */\n} WorkspacegroupLoadType;\n\n/* Save mode ... controls behaviour of column_save_test() and row_save_test()\n */\ntypedef enum {\n\tWORKSPACEGROUP_SAVE_ALL,\t/* Save everything */\n\tWORKSPACEGROUP_SAVE_WORKSPACE,\t/* Save current workspace */\n\tWORKSPACEGROUP_SAVE_SELECTED\t/* Only save selected rows */\n} WorkspacegroupSaveType;\n\n/* Workspacegroups: group workspaces with these. One workspacegroup per \n * file loaded.\n */\nstruct _Workspacegroup {\n\tFilemodel parent_class;\n\n\tWorkspaceroot *wsr;\n\n\t/* Control load/save for this wsg.\n\t */\n\tWorkspacegroupLoadType load_type;\n\tWorkspacegroupSaveType save_type;\n\n\tguint autosave_timeout;\n\n\t/* workspacegroup_load_columns() etc. use this to display warnings\n\t * during load.\n\t */\n\tiWindow *iwnd;\n\n};\n\ntypedef struct _WorkspacegroupClass {\n\tFilemodelClass parent_class;\n\n\t/* My methods.\n\t */\n} WorkspacegroupClass;\n\nWorkspace *workspacegroup_get_workspace( Workspacegroup *wsg );\nint workspacegroup_get_n_objects( Workspacegroup *wsg );\n\nvoid workspacegroup_set_load_type( Workspacegroup *wsg, \n\tWorkspacegroupLoadType load_type );\nvoid workspacegroup_set_save_type( Workspacegroup *wsg, \n\tWorkspacegroupSaveType save_type );\n\nWorkspace *workspacegroup_map( Workspacegroup *wsg, \n\tworkspace_map_fn fn, void *a, void *b );\n\nGType workspacegroup_get_type( void );\n\ngboolean workspacegroup_is_empty( Workspacegroup *wsg );\n\nWorkspacegroup *workspacegroup_new( Workspaceroot *wsr );\nWorkspacegroup *workspacegroup_new_blank( Workspaceroot *wsr, \n\tconst char *name );\nWorkspacegroup *workspacegroup_new_filename( Workspaceroot *wsr, \n\tconst char *filename );\nWorkspacegroup *workspacegroup_new_from_file( Workspaceroot *wsr, \n\tconst char *filename, const char *filename_user );\nWorkspacegroup *workspacegroup_new_from_openfile( Workspaceroot *wsr, \n\tiOpenFile *of );\n\ngboolean workspacegroup_merge_workspaces( Workspacegroup *wsg, \n\tconst char *filename );\ngboolean workspacegroup_merge_columns( Workspacegroup *wsg, \n\tconst char *filename );\ngboolean workspacegroup_merge_rows( Workspacegroup *wsg, \n\tconst char *filename );\n\ngboolean workspacegroup_save_selected( Workspacegroup *wsg, \n\tconst char *filename );\ngboolean workspacegroup_save_current( Workspacegroup *wsg, \n\tconst char *filename );\ngboolean workspacegroup_save_all( Workspacegroup *wsg, \n\tconst char *filename );\n\nWorkspacegroup *workspacegroup_duplicate( Workspacegroup *wsg );\n\nchar *workspacegroup_autosave_recover( void );\nvoid workspacegroup_autosave_clean( void );\n\n"
  },
  {
    "path": "src/workspacegroupview.c",
    "content": "/* main processing window\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#include \"ip.h\"\n\n/* \n#define DEBUG\n */\n\nstatic ViewClass *parent_class = NULL;\n\nstatic void\nworkspacegroupview_realize( GtkWidget *widget )\n{\n#ifdef DEBUG\n{\n\tWorkspacegroupview *wsgview = WORKSPACEGROUPVIEW( widget );\n\tWorkspace *ws = WORKSPACE( VOBJECT( wsgview )->iobject );\n\n\tprintf( \"workspacegroupview_realize: %s\\n\", IOBJECT( ws )->name );\n}\n#endif /*DEBUG*/\n\n\tGTK_WIDGET_CLASS( parent_class )->realize( widget );\n\n\t/* Mark us as a symbol drag-to widget. \n\t */\n\tset_symbol_drag_type( widget );\n}\n\nstatic void\nworkspacegroupview_rename_sub( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tWorkspace *ws = WORKSPACE( client );\n\tStringset *ss = STRINGSET( iwnd );\n\tStringsetChild *name = stringset_child_get( ss, _( \"Name\" ) );\n\tStringsetChild *caption = stringset_child_get( ss, _( \"Caption\" ) );\n\n\tchar name_text[1024];\n\tchar caption_text[1024];\n\n\tif( !get_geditable_name( name->entry, name_text, 1024 ) ||\n\t\t!get_geditable_string( caption->entry, caption_text, 1024 ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tif( !workspace_rename( ws, name_text, caption_text ) ) {\n\t\tnfn( sys, IWINDOW_ERROR );\n\t\treturn;\n\t}\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void                \nworkspacegroupview_rename_cb( GtkWidget *wid, GtkWidget *host, \n\tWorkspaceview *wview )\n{\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\tGtkWidget *ss = stringset_new();\n\n\tif( ws->locked )\n\t\treturn; \n\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Name\" ), IOBJECT( ws )->name, \n\t\t_( \"Set tab name here\" ) );\n\tstringset_child_new( STRINGSET( ss ), \n\t\t_( \"Caption\" ), IOBJECT( ws )->caption, \n\t\t_( \"Set tab caption here\" ) );\n\n\tiwindow_set_title( IWINDOW( ss ), \n\t\t_( \"Rename Tab \\\"%s\\\"\" ), IOBJECT( ws )->name );\n\tidialog_set_callbacks( IDIALOG( ss ), \n\t\tiwindow_true_cb, NULL, NULL, ws );\n\tidialog_add_ok( IDIALOG( ss ), \n\t\tworkspacegroupview_rename_sub, _( \"Rename Tab\" ) );\n\tiwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( wview ) );\n\tiwindow_build( IWINDOW( ss ) );\n\n\tgtk_widget_show( ss );\n}\n\nstatic void\nworkspacegroupview_rename_cb2( GtkWidget *wid, GdkEvent *event, \n\tWorkspaceview *wview )\n{\n\tworkspacegroupview_rename_cb( wid, NULL, wview );\n}\n\nstatic void\nworkspacegroupview_child_add( View *parent, View *child )\n{\n\tWorkspacegroupview *wsgview = WORKSPACEGROUPVIEW( parent );\n\tWorkspaceview *wview = WORKSPACEVIEW( child );\n\tWorkspace *ws = WORKSPACE( VOBJECT( child )->iobject );\n\n\tGtkWidget *ebox;\n\tGtkWidget *hbox;\n\tGtkWidget *label;\n\tGtkWidget *padlock;\n\tGtkWidget *alert;\n\n\tVIEW_CLASS( parent_class )->child_add( parent, child );\n\n        ebox = gtk_event_box_new();\n\tgtk_widget_add_events( GTK_WIDGET( ebox ), \n\t\tGDK_BUTTON_PRESS_MASK ); \n        hbox = gtk_hbox_new( FALSE, 0 );\n        gtk_container_add( GTK_CONTAINER( ebox ), hbox );\n        gtk_widget_show( GTK_WIDGET( hbox ) );\n\n\tpadlock = gtk_image_new(); \n        gtk_box_pack_start( GTK_BOX( hbox ), padlock, FALSE, FALSE, 0 );\n        gtk_widget_show( GTK_WIDGET( padlock ) );\n\tset_tooltip( padlock, \"%s\", _( \"unlock from Edit menu\" ) ); \n\n\talert = gtk_image_new(); \n        gtk_box_pack_start( GTK_BOX( hbox ), alert, FALSE, FALSE, 0 );\n        gtk_widget_show( GTK_WIDGET( alert ) );\n\tset_tooltip( alert, \"%s\", _( \"errors in tab\" ) ); \n\n\tlabel = gtk_label_new( NN( IOBJECT( ws->sym )->name ) );\n        gtk_box_pack_end( GTK_BOX( hbox ), label, FALSE, FALSE, 0 );\n        gtk_widget_show( GTK_WIDGET( label ) );\n\n\tworkspaceview_set_label( wview, label, padlock, alert );\n\n\tpopup_attach( ebox, wsgview->tab_menu, wview );\n\n        doubleclick_add( ebox, FALSE,\n                NULL, NULL, \n\t\tDOUBLECLICK_FUNC( workspacegroupview_rename_cb2 ), \n\t\t\twview );\n\n\tgtk_notebook_insert_page( GTK_NOTEBOOK( wsgview->notebook ),\n\t\tGTK_WIDGET( wview ), ebox, ICONTAINER( ws )->pos );\n\tgtk_notebook_set_tab_reorderable( GTK_NOTEBOOK( wsgview->notebook ),\n\t\tGTK_WIDGET( wview ), TRUE );\n\tgtk_notebook_set_tab_detachable( GTK_NOTEBOOK( wsgview->notebook ),\n\t\tGTK_WIDGET( wview ), TRUE );\n}\n\nstatic void\nworkspacegroupview_child_remove( View *parent, View *child )\n{\n\t/* Stuff.\n\tWorkspacegroupview *wsgview = WORKSPACEGROUPVIEW( parent );\n\tWorkspaceview *wview = WORKSPACEVIEW( child );\n\n\t */\n\n\tVIEW_CLASS( parent_class )->child_remove( parent, child );\n}\n\nstatic void\nworkspacegroupview_child_position( View *parent, View *child )\n{\n\tWorkspacegroupview *wsgview = WORKSPACEGROUPVIEW( parent );\n\tWorkspaceview *wview = WORKSPACEVIEW( child );\n\n\tgtk_notebook_reorder_child( GTK_NOTEBOOK( wsgview->notebook ),\n\t\tGTK_WIDGET( wview ), ICONTAINER( wview )->pos );\n\n\tVIEW_CLASS( parent_class )->child_position( parent, child );\n}\n\nstatic void\nworkspacegroupview_child_front( View *parent, View *child )\n{\n\tWorkspacegroupview *wsgview = WORKSPACEGROUPVIEW( parent );\n\tWorkspaceview *wview = WORKSPACEVIEW( child );\n\n\tint page;\n\tGtkWidget *current_front;\n\n\tpage = gtk_notebook_get_current_page( \n\t\tGTK_NOTEBOOK( wsgview->notebook ) );\n\tcurrent_front = gtk_notebook_get_nth_page( \n\t\tGTK_NOTEBOOK( wsgview->notebook ), page );\n\n\tif( current_front != GTK_WIDGET( wview ) ) { \n\t\tpage = gtk_notebook_page_num( \n\t\t\tGTK_NOTEBOOK( wsgview->notebook ), \n\t\t\tGTK_WIDGET( wview ) );\n\t\tgtk_notebook_set_current_page( \n\t\t\tGTK_NOTEBOOK( wsgview->notebook ),\n\t\t\tpage );\n\t}\n}\n\nstatic void\nworkspacegroupview_class_init( WorkspacegroupviewClass *class )\n{\n\tGtkWidgetClass *widget_class = (GtkWidgetClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\twidget_class->realize = workspacegroupview_realize;\n\n\tview_class->child_add = workspacegroupview_child_add;\n\tview_class->child_remove = workspacegroupview_child_remove;\n\tview_class->child_position = workspacegroupview_child_position;\n\tview_class->child_front = workspacegroupview_child_front;\n}\n\ntypedef struct _nip2GtkNotebookPage {\n\t  GtkWidget *child;\n\n\t  /* A lot of stuff follows in the real struct, which we ignore.\n\t   */\n} nip2GtkNotebookPage;\n\n/* gtk+-2.20 and earlier had a bug whereby switch_page would be given a\n * GtkNotebookPage rather than the actual page widget.\n */\nstatic Workspaceview *\nnotebookpage_get_workspaceview( GtkWidget *page )\n{\n#ifdef USE_NOTEBOOK_GROUP_NAME\n\treturn( WORKSPACEVIEW( page ) );\n#else /*!USE_NOTEBOOK_GROUP_NAME*/\n\t/* Buggy argh.\n\t */\n\treturn( WORKSPACEVIEW( ((nip2GtkNotebookPage *) page)->child ) );\n#endif\n}\n\n/* Called for switching the current page, and for page drags between\n * notebooks.\n */\nstatic void\nworkspacegroupview_switch_page_cb( GtkNotebook *notebook, \n\tGtkWidget *page, guint page_num, gpointer user_data )\n{\n\tWorkspaceview *wview = notebookpage_get_workspaceview( page );\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\tWorkspacegroup *old_wsg = WORKSPACEGROUP( ICONTAINER( ws )->parent );\n\tWorkspacegroupview *wsgview = WORKSPACEGROUPVIEW( user_data );\n\tWorkspacegroup *wsg = WORKSPACEGROUP( VOBJECT( wsgview )->iobject );\n\n\tif( ICONTAINER( ws )->parent != ICONTAINER( wsg ) ) {\n\t\ticontainer_reparent( ICONTAINER( wsg ), \n\t\t\tICONTAINER( ws ), -1 );\n\n\t\tfilemodel_set_modified( FILEMODEL( wsg ), TRUE );\n\t\tfilemodel_set_modified( FILEMODEL( old_wsg ), TRUE );\n\n\t\t/* If dragging the tab has emptied the old wsg, we can junk\n\t\t * the window.\n\t\t */\n\t\tmainw_cull();\n\t}\n\n\ticontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) );\n\n\tif( ws->compat_major ) { \n\t\terror_top( _( \"Compatibility mode.\" ) );\n\t\terror_sub( _( \"This workspace was created by version %d.%d. \"\n\t\t\t\"A set of compatibility menus have been loaded \"\n\t\t\t\"for this window.\" ),\n\t\t\tws->compat_major,\n\t\t\tws->compat_minor ); \n\t\tiwindow_alert( GTK_WIDGET( wview ), GTK_MESSAGE_INFO );\n\t}\n\n\t/* How bizarre, pages sometimes fail to set up correctly. Force a\n\t * resize to get everything to init. \n\t */\n\tif( wview &&\n\t\twview->fixed ) \n\t\tgtk_container_check_resize( GTK_CONTAINER( wview->fixed ) );\n}\n\nstatic void                \nworkspacegroupview_page_added_cb( GtkNotebook *notebook, \n\tGtkWidget *page, guint page_num, gpointer user_data )\n{\n\tWorkspacegroupview *wsgview = WORKSPACEGROUPVIEW( user_data );\n\tWorkspacegroup *wsg = WORKSPACEGROUP( VOBJECT( wsgview )->iobject );\n\tMainw *mainw = MAINW( iwindow_get_root( GTK_WIDGET( notebook ) ) );\n\n\tfilemodel_set_window_hint( FILEMODEL( wsg ), IWINDOW( mainw ) );\n}\n\nstatic GtkNotebook *                \nworkspacegroupview_create_window_cb( GtkNotebook *notebook, \n\tGtkWidget *page, int x, int y, gpointer user_data )\n{\n\tWorkspaceview *wview = WORKSPACEVIEW( page );\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\tWorkspacegroup *wsg = WORKSPACEGROUP( ICONTAINER( ws )->parent );\n\tWorkspaceroot *wsr = wsg->wsr; \n\n\tMainw *new_mainw;\n\tWorkspacegroup *new_wsg;\n\tchar name[256];\n\n\t/*\n\tprintf( \"workspacegroupview_create_window_cb: wsg = %s, ws = %s\\n\",\n\t\tNN( IOBJECT( wsg )->name ), NN( IOBJECT( ws )->name ) ); \n\tprintf( \"workspacegroupview_create_window_cb: x = %d, y = %d\\n\", x, y );\n\t */\n\n\tworkspaceroot_name_new( wsr, name );\n\tnew_wsg = workspacegroup_new( wsr );\n\n\t/*\n\tprintf( \"workspacegroupview_create_window_cb: new wsg = %s\\n\", name );\n\t */\n\n\tiobject_set( IOBJECT( new_wsg ), name, NULL );\n\tnew_mainw = mainw_new( new_wsg );\n\tgtk_window_move( GTK_WINDOW( new_mainw ), x, y );\n\tgtk_widget_show( GTK_WIDGET( new_mainw ) );\n\n\treturn( GTK_NOTEBOOK( new_mainw->wsgview->notebook ) ); \n}\n\nstatic void                \nworkspacegroupview_page_reordered_cb( GtkNotebook *notebook, \n\tGtkWidget *page, guint page_num, gpointer user_data )\n{\n\tWorkspaceview *wview = WORKSPACEVIEW( page );\n\tWorkspacegroupview *wsgview = \n\t\tWORKSPACEGROUPVIEW( VIEW( wview )->parent );\n\tWorkspacegroup *wsg = WORKSPACEGROUP( VOBJECT( wsgview )->iobject );\n\n\tint i;\n\tgboolean changed;\n\n\tchanged = FALSE;\n\n\tfor( i = 0; i < gtk_notebook_get_n_pages( notebook ); i++ ) {\n\t\tGtkWidget *page_n = gtk_notebook_get_nth_page( notebook, i );\n\t\tWorkspaceview *wview = WORKSPACEVIEW( page_n );\n\t\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\n\t\tif( ICONTAINER( ws )->pos != i ) {\n\t\t\tICONTAINER( ws )->pos = i;\n\t\t\tchanged = TRUE;\n\t\t}\n\t}\n\n\tif( changed ) {\n\t\ticontainer_pos_sort( ICONTAINER ( wsg ) ); \n\t\tfilemodel_set_modified( FILEMODEL( wsg ), TRUE );\n\t}\n}\n\nstatic void\nworkspacegroupview_tab_double_cb( GtkNotebook *notebook, GdkEvent *event, \n\tWorkspacegroupview *wsgview )\n{\n\tWorkspacegroup *wsg = WORKSPACEGROUP( VOBJECT( wsgview )->iobject );\n\n\tint i;\n\tGtkWidget *page;\n\tGtkWidget *tab;\n\n\t/* Doubleclick in a tab row background. This could be the gutter or\n\t * the edge of a label. Get the position of the right-most tab and\n\t * check our click x against that. \n\t */\n\ti = gtk_notebook_get_n_pages( notebook ); \n\tpage = gtk_notebook_get_nth_page( notebook, i - 1 ); \n\ttab = gtk_notebook_get_tab_label( notebook, page ); \n\n\tif( event->button.x > tab->allocation.x + tab->allocation.width &&\n\t\t!workspace_new_blank( wsg ) ) \n\t\tiwindow_alert( GTK_WIDGET( wsgview ), GTK_MESSAGE_ERROR );\n}\n\nstatic void\nworkspacegroupview_add_workspace_cb( GtkWidget *wid, \n\tWorkspacegroupview *wsgview )\n{\n\tWorkspacegroup *wsg = WORKSPACEGROUP( VOBJECT( wsgview )->iobject );\n\n\tif( !workspace_new_blank( wsg ) ) \n\t\tiwindow_alert( GTK_WIDGET( wsgview ), GTK_MESSAGE_ERROR );\n}\n\nstatic void                \nworkspacegroupview_add_workspace_cb2( GtkWidget *wid, GtkWidget *host, \n\tWorkspacegroupview *wsgview )\n{\n\tworkspacegroupview_add_workspace_cb( wid, wsgview ); \n}\n\nstatic void                \nworkspacegroupview_load_workspace_cb2( GtkWidget *wid, GtkWidget *host, \n\tWorkspacegroupview *wsgview )\n{\n\tMainw *mainw = MAINW( iwindow_get_root( GTK_WIDGET( wsgview ) ) );\n\n\tmainw_workspace_merge( mainw );\n}\n\nstatic void                \nworkspacegroupview_select_all_cb( GtkWidget *wid, GtkWidget *host, \n\tWorkspaceview *wview )\n{\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\n\tif( !ws->locked )\n\t\tworkspace_select_all( ws );\n}\n\nstatic void                \nworkspacegroupview_duplicate_cb( GtkWidget *wid, GtkWidget *host, \n\tWorkspaceview *wview )\n{\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\n\tif( !workspace_duplicate( ws ) ) {\n\t\tiwindow_alert( host, GTK_MESSAGE_ERROR );\n\t\treturn;\n\t}\n}\n\nstatic void\nworkspacegroupview_merge_sub( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( iwnd );\n\tWorkspace *ws = WORKSPACE( client );\n\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\n\tchar *filename;\n\tColumn *col;\n\n\tif( (filename = filesel_get_filename( filesel )) ) {\n\t\ticontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) );\n\n\t\tprogress_begin();\n\n\t\tcolumn_clear_last_new();\n\n\t\tif( !workspace_merge_file( ws, filename ) ) \n\t\t\tnfn( sys, IWINDOW_ERROR );\n\t\telse {\n\t\t\tsymbol_recalculate_all();\n\t\t\tnfn( sys, IWINDOW_YES );\n\t\t}\n\n\t\tif( (col = column_get_last_new()) )\n\t\t\tcolumn_scrollto( col, MODEL_SCROLL_TOP ); \n\n\t\tprogress_end();\n\n\t\tg_free( filename );\n\t}\n\telse\n\t\tnfn( sys, IWINDOW_ERROR );\n}\n\nstatic void                \nworkspacegroupview_merge_cb( GtkWidget *wid, GtkWidget *host, \n\tWorkspaceview *wview )\n{\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\tiWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( wview ) ) );\n\tGtkWidget *filesel = filesel_new();\n\n\tif( ws->locked )\n\t\treturn; \n\n\tiwindow_set_title( IWINDOW( filesel ), \n\t\t_( \"Merge Into Tab \\\"%s\\\"\" ), IOBJECT( ws )->name );\n\tfilesel_set_flags( FILESEL( filesel ), FALSE, FALSE );\n\tfilesel_set_filetype( FILESEL( filesel ), filesel_type_workspace, 0 ); \n\tiwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( iwnd ) );\n\tidialog_set_iobject( IDIALOG( filesel ), IOBJECT( ws ) );\n\tfilesel_set_done( FILESEL( filesel ), \n\t\tworkspacegroupview_merge_sub, ws );\n\tiwindow_build( IWINDOW( filesel ) );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\nstatic void\nworkspacegroupview_save_as_sub( iWindow *iwnd, \n\tvoid *client, iWindowNotifyFn nfn, void *sys )\n{\n\tFilesel *filesel = FILESEL( iwnd );\n\tWorkspace *ws = WORKSPACE( client );\n\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\n\tchar *filename;\n\n\tif( (filename = filesel_get_filename( filesel )) ) {\n\t\ticontainer_current( ICONTAINER( wsg ), ICONTAINER( ws ) );\n\t\tif( !workspacegroup_save_current( wsg, filename ) ) \n\t\t\tnfn( sys, IWINDOW_ERROR );\n\t\telse\n\t\t\tnfn( sys, IWINDOW_YES );\n\n\t\tg_free( filename );\n\t}\n\telse\n\t\tnfn( sys, IWINDOW_ERROR );\n}\n\nstatic void                \nworkspacegroupview_save_as_cb( GtkWidget *wid, GtkWidget *host, \n\tWorkspaceview *wview )\n{\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\tiWindow *iwnd = IWINDOW( view_get_toplevel( VIEW( wview ) ) );\n\tGtkWidget *filesel = filesel_new();\n\n\tiwindow_set_title( IWINDOW( filesel ), \n\t\t_( \"Save Tab \\\"%s\\\"\" ), IOBJECT( ws )->name );\n\tfilesel_set_flags( FILESEL( filesel ), FALSE, TRUE );\n\tfilesel_set_filetype( FILESEL( filesel ), filesel_type_workspace, 0 ); \n\tiwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( iwnd ) );\n\tidialog_set_iobject( IDIALOG( filesel ), IOBJECT( ws ) );\n\tfilesel_set_done( FILESEL( filesel ), \n\t\tworkspacegroupview_save_as_sub, ws );\n\tiwindow_build( IWINDOW( filesel ) );\n\n\tgtk_widget_show( GTK_WIDGET( filesel ) );\n}\n\n/* ws has been destroyed. \n */\nstatic void\nworkspacegroupview_delete_done_cb( iWindow *iwnd, void *client, \n\tiWindowNotifyFn nfn, void *sys )\n{\n\tmainw_cull();\n\n\tnfn( sys, IWINDOW_YES );\n}\n\nstatic void                \nworkspacegroupview_delete_cb( GtkWidget *wid, GtkWidget *host, \n\tWorkspaceview *wview )\n{\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\n\tif( !ws->locked )\n\t\tmodel_check_destroy( view_get_toplevel( VIEW( wview ) ), \n\t\t\tMODEL( ws ), workspacegroupview_delete_done_cb );\n}\n\nstatic void\nworkspacegroupview_init( Workspacegroupview *wsgview )\n{\n\twsgview->notebook = gtk_notebook_new();\n\tgtk_notebook_set_scrollable( GTK_NOTEBOOK( wsgview->notebook ), TRUE );\n#ifdef USE_NOTEBOOK_GROUP_NAME\n\tgtk_notebook_set_group_name( GTK_NOTEBOOK( wsgview->notebook ), \n\t\t\"wsgview\" );\n#endif /*USE_NOTEBOOK_GROUP_NAME*/\n\tgtk_notebook_set_tab_pos( GTK_NOTEBOOK( wsgview->notebook ), \n\t\tGTK_POS_TOP );\n\tg_signal_connect( wsgview->notebook, \"switch_page\", \n\t\tG_CALLBACK( workspacegroupview_switch_page_cb ), wsgview );\n\tg_signal_connect( wsgview->notebook, \"page_added\", \n\t\tG_CALLBACK( workspacegroupview_page_added_cb ), wsgview );\n\tg_signal_connect( wsgview->notebook, \"page_reordered\", \n\t\tG_CALLBACK( workspacegroupview_page_reordered_cb ), wsgview );\n\tg_signal_connect( wsgview->notebook, \"create_window\", \n\t\tG_CALLBACK( workspacegroupview_create_window_cb ), wsgview );\n\n        doubleclick_add( wsgview->notebook, FALSE,\n                NULL, NULL, \n\t\tDOUBLECLICK_FUNC( workspacegroupview_tab_double_cb ), \n\t\t\twsgview );\n\n\twsgview->gutter_menu = popup_build( _( \"Tab gutter menu\" ) );\n\tpopup_add_but( wsgview->gutter_menu, _( \"New Tab\" ),\n\t\tPOPUP_FUNC( workspacegroupview_add_workspace_cb2 ) ); \n\tpopup_add_but( wsgview->gutter_menu, _( \"Merge Into Workspace\" ),\n\t\tPOPUP_FUNC( workspacegroupview_load_workspace_cb2 ) ); \n\tpopup_attach( wsgview->notebook, wsgview->gutter_menu, wsgview );\n\n#ifdef USE_NOTEBOOK_ACTION\n{\n\tGtkWidget *but;\n\tGtkWidget *icon;\n\n        but = gtk_button_new();\n        gtk_button_set_relief( GTK_BUTTON( but ), GTK_RELIEF_NONE );\n        set_tooltip( but, _( \"Add a workspace\" ) );\n\ticon = gtk_image_new_from_stock( GTK_STOCK_ADD, GTK_ICON_SIZE_MENU );\n        gtk_container_add( GTK_CONTAINER( but ), icon );\n\tgtk_widget_show( icon );\n\tgtk_widget_show( but );\n\tgtk_notebook_set_action_widget( GTK_NOTEBOOK( wsgview->notebook ), \n\t\tbut, GTK_PACK_END );\n        g_signal_connect( but, \"clicked\",\n                G_CALLBACK( workspacegroupview_add_workspace_cb ), wsgview );\n}\n#endif /*USE_NOTEBOOK_ACTION*/\n\n\tgtk_box_pack_start( GTK_BOX( wsgview ), \n\t\twsgview->notebook, TRUE, TRUE, 0 );\n\tgtk_widget_show( wsgview->notebook );\n\n\twsgview->tab_menu = popup_build( _( \"Tab menu\" ) );\n\tpopup_add_but( wsgview->tab_menu, _( \"Rename\" ),\n\t\tPOPUP_FUNC( workspacegroupview_rename_cb ) ); \n\tpopup_add_but( wsgview->tab_menu, _( \"Select All\" ),\n\t\tPOPUP_FUNC( workspacegroupview_select_all_cb ) ); \n\tpopup_add_but( wsgview->tab_menu, STOCK_DUPLICATE,\n\t\tPOPUP_FUNC( workspacegroupview_duplicate_cb ) ); \n\tpopup_add_but( wsgview->tab_menu, _( \"Merge Into Tab\" ),\n\t\tPOPUP_FUNC( workspacegroupview_merge_cb ) ); \n\tpopup_add_but( wsgview->tab_menu, GTK_STOCK_SAVE_AS,\n\t\tPOPUP_FUNC( workspacegroupview_save_as_cb ) ); \n\tmenu_add_sep( wsgview->tab_menu );\n\tpopup_add_but( wsgview->tab_menu, GTK_STOCK_DELETE,\n\t\tPOPUP_FUNC( workspacegroupview_delete_cb ) ); \n}\n\nGtkType\nworkspacegroupview_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( WorkspacegroupviewClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) workspacegroupview_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Workspacegroupview ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) workspacegroupview_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_VIEW, \n\t\t\t\"Workspacegroupview\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nView *\nworkspacegroupview_new( void )\n{\n\tWorkspacegroupview *wsgview = gtk_type_new( TYPE_WORKSPACEGROUPVIEW );\n\n\treturn( VIEW( wsgview ) );\n}\n"
  },
  {
    "path": "src/workspacegroupview.h",
    "content": "/* A view for a Workspacegroup (a set of workspaces) ... display as a notebook.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_WORKSPACEGROUPVIEW (workspacegroupview_get_type())\n#define WORKSPACEGROUPVIEW( obj ) (GTK_CHECK_CAST( (obj), \\\n\tTYPE_WORKSPACEGROUPVIEW, Workspacegroupview ))\n#define WORKSPACEGROUPVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_WORKSPACEGROUPVIEW, WorkspacegroupviewClass ))\n#define IS_WORKSPACEGROUPVIEW( obj ) (GTK_CHECK_TYPE( (obj), \\\n\tTYPE_WORKSPACEGROUPVIEW ))\n#define IS_WORKSPACEGROUPVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_WORKSPACEGROUPVIEW ))\n\nstruct _Workspacegroupview {\n\tView parent_object;\n\n\tGtkWidget *tab_menu;\n\tGtkWidget *gutter_menu;\n\tGtkWidget *notebook;\n};\n\ntypedef struct _WorkspacegroupviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} WorkspacegroupviewClass;\n\nGType workspacegroupview_get_type( void );\nView *workspacegroupview_new( void );\n"
  },
  {
    "path": "src/workspaceroot.c",
    "content": "/* The root of all workspaces. A singleton all workspaces are children of.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/*\n#define DEBUG\n */\n\n#include \"ip.h\"\n\nstatic ModelClass *parent_class = NULL;\n\nstatic void\nworkspaceroot_dispose( GObject *gobject )\n{\n\tWorkspaceroot *wsr;\n\n#ifdef DEBUG\n\tprintf( \"workspaceroot_dispose\\n\" );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( gobject != NULL );\n\tg_return_if_fail( IS_WORKSPACEROOT( gobject ) );\n\n\twsr = WORKSPACEROOT( gobject );\n\n\twsr->sym = NULL;\n\n\tG_OBJECT_CLASS( parent_class )->dispose( gobject );\n}\n\nstatic void\nworkspaceroot_child_add( iContainer *parent, iContainer *child, int pos )\n{\n\tICONTAINER_CLASS( parent_class )->child_add( parent, child, pos );\n\n#ifdef DEBUG\n\tprintf( \"workspaceroot_child_add: added %s\\n\",\n\t\tIOBJECT( child )->name );\n#endif /*DEBUG*/\n}\n\nstatic void\nworkspaceroot_child_remove( iContainer *parent, iContainer *child )\n{\n\tICONTAINER_CLASS( parent_class )->child_remove( parent, child );\n}\n\nstatic void\nworkspaceroot_class_init( WorkspacerootClass *class )\n{\n\tGObjectClass *gobject_class = (GObjectClass *) class;\n\tiContainerClass *icontainer_class = (iContainerClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\t/* Create signals.\n\t */\n\n\t/* Init methods.\n\t */\n\tgobject_class->dispose = workspaceroot_dispose;\n\n\ticontainer_class->child_add = workspaceroot_child_add;\n\ticontainer_class->child_remove = workspaceroot_child_remove;\n}\n\nstatic void\nworkspaceroot_init( Workspaceroot *wsr )\n{\n\twsr->sym = NULL;\n}\n\nGType\nworkspaceroot_get_type( void )\n{\n\tstatic GType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GTypeInfo info = {\n\t\t\tsizeof( WorkspacerootClass ),\n\t\t\tNULL,           /* base_init */\n\t\t\tNULL,           /* base_finalize */\n\t\t\t(GClassInitFunc) workspaceroot_class_init,\n\t\t\tNULL,           /* class_finalize */\n\t\t\tNULL,           /* class_data */\n\t\t\tsizeof( Workspaceroot ),\n\t\t\t32,             /* n_preallocs */\n\t\t\t(GInstanceInitFunc) workspaceroot_init,\n\t\t};\n\n\t\ttype = g_type_register_static( TYPE_MODEL, \n\t\t\t\"Workspaceroot\", &info, 0 );\n\t}\n\n\treturn( type );\n}\n\nstatic void\nworkspaceroot_link( Workspaceroot *wsr, const char *name )\n{\n\tSymbol *sym;\n\n\tiobject_set( IOBJECT( wsr ), name, NULL );\n\n\twsr->sym = sym = symbol_new( symbol_root->expr->compile, name );\n\tsym->type = SYM_WORKSPACEROOT;\n\tsym->wsr = wsr;\n\tsym->expr = expr_new( sym );\n\t(void) compile_new( sym->expr );\n\tsymbol_made( sym );\n}\n\nWorkspaceroot *\nworkspaceroot_new( const char *name )\n{\n\tWorkspaceroot *wsr;\n\n\tif( compile_lookup( symbol_root->expr->compile, name ) ) {\n\t\terror_top( _( \"Name clash.\" ) );\n\t\terror_sub( _( \"Can't create workspaceroot \\\"%s\\\". \"\n\t\t\t\"A symbol with that name already exists.\" ), name );\n\t\treturn( NULL );\n\t}\n\n\twsr = WORKSPACEROOT( g_object_new( TYPE_WORKSPACEROOT, NULL ) );\n\tworkspaceroot_link( wsr, name );\n\n\treturn( wsr );\n}\n\n/* Make up a new workspace name.\n */\nvoid\nworkspaceroot_name_new( Workspaceroot *wsr, char *name )\n{\n\tCompile *compile = wsr->sym->expr->compile;\n\n\tstrcpy( name, \"tab1\" );\n\twhile( compile_lookup( compile, name ) )\n\t\tincrement_name( name );\n}\n"
  },
  {
    "path": "src/workspaceroot.h",
    "content": "/* The root of all workspaces. A singleton all workspaces are children of.\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n#define TYPE_WORKSPACEROOT (workspaceroot_get_type())\n#define WORKSPACEROOT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_CAST( (obj), TYPE_WORKSPACEROOT, \\\n\t\tWorkspaceroot ))\n#define WORKSPACEROOT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_CAST( (klass), TYPE_WORKSPACEROOT, \\\n\t\tWorkspacerootClass))\n#define IS_WORKSPACEROOT( obj ) \\\n\t(G_TYPE_CHECK_INSTANCE_TYPE( (obj), TYPE_WORKSPACEROOT ))\n#define IS_WORKSPACEROOT_CLASS( klass ) \\\n\t(G_TYPE_CHECK_CLASS_TYPE( (klass), TYPE_WORKSPACEROOT ))\n#define WORKSPACEROOT_GET_CLASS( obj ) \\\n\t(G_TYPE_INSTANCE_GET_CLASS( (obj), TYPE_WORKSPACEROOT, \\\n\t\tWorkspacerootClass ))\n\n/* A workspaceroot.\n */\nstruct _Workspaceroot {\n\tModel parent_object;\n\n\tSymbol *sym;\t\t\t/* Workspace in this group in this */\n};\n\ntypedef struct _WorkspacerootClass {\n\tModelClass parent_class;\n\n\t/* Methods.\n\t */\n} WorkspacerootClass;\n\nGType workspaceroot_get_type( void );\n\nWorkspaceroot *workspaceroot_new( const char *name );\n\nvoid workspaceroot_name_new( Workspaceroot *wsr, char *name );\n"
  },
  {
    "path": "src/workspaceview.c",
    "content": "/* a workspaceview button in a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n */\n\n/* \n#define DEBUG\n */\n\n/* Define to trace button press events.\n#define EVENT\n */\n\n#include \"ip.h\"\n\nstatic ViewClass *parent_class = NULL;\n\n/* Params for \"Align Columns\" function.\n */\nstatic const int workspaceview_layout_snap_threshold = 30;\nstatic const int workspaceview_layout_hspacing = 10;\nstatic const int workspaceview_layout_vspacing = 10;\nstatic const int workspaceview_layout_left = WORKSPACEVIEW_MARGIN_LEFT;\nstatic const int workspaceview_layout_top = WORKSPACEVIEW_MARGIN_TOP;\n\nstatic void\nworkspaceview_scroll_to( Workspaceview *wview, int x, int y )\n{\n\tGtkAdjustment *hadj = gtk_scrolled_window_get_hadjustment( \n\t\tGTK_SCROLLED_WINDOW( wview->window ) );\n\tGtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment( \n\t\tGTK_SCROLLED_WINDOW( wview->window ) );\n        int nx, ny;\n\n        nx = IM_CLIP( 0, x, wview->width - wview->vp.width );\n        ny = IM_CLIP( 0, y, wview->height - wview->vp.height );\n\n\tadjustments_set_value( hadj, vadj, nx, ny );\n}\n\n/* Scroll by an amount horizontally and vertically.\n */\nstatic void\nworkspaceview_displace( Workspaceview *wview, int u, int v )\n{\n\tworkspaceview_scroll_to( wview, wview->vp.left + u, wview->vp.top + v );\n}\n\n/* Scroll to make an xywh area visible. If the area is larger than the\n * viewport, position the view at the bottom left if the xywh area ... \n * this is usually right for workspaces.\n */\nvoid\nworkspaceview_scroll( Workspaceview *wview, int x, int y, int w, int h )\n{\n\tGtkAdjustment *hadj = gtk_scrolled_window_get_hadjustment( \n\t\tGTK_SCROLLED_WINDOW( wview->window ) );\n\tGtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment( \n\t\tGTK_SCROLLED_WINDOW( wview->window ) );\n        Rect *vp = &wview->vp;\n        int nx, ny;\n\n        nx = hadj->value;\n        if( x + w > IM_RECT_RIGHT( vp ) )\n                nx = IM_MAX( 0, (x + w) - vp->width );\n        if( x < nx )\n                nx = x;\n\n        ny = vadj->value;\n        if( y + h > IM_RECT_BOTTOM( vp ) )\n                ny = IM_MAX( 0, (y + h) - vp->height );\n        if( y < ny )\n                ny = y;\n\n#ifdef DEBUG\n        printf( \"workspaceview_scroll: x=%d, y=%d, w=%d, h=%d, \"\n                \"nx = %d, ny = %d\\n\", x, y, w, h, nx, ny );\n#endif /*DEBUG*/\n\n\tadjustments_set_value( hadj, vadj, nx, ny );\n}\n\n/* Update our geometry from the fixed widget.\n */\nstatic void\nworkspaceview_scroll_update( Workspaceview *wview )\n{\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\tGtkAdjustment *hadj = gtk_scrolled_window_get_hadjustment( \n\t\tGTK_SCROLLED_WINDOW( wview->window ) );\n\tGtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment( \n\t\tGTK_SCROLLED_WINDOW( wview->window ) );\n\n        wview->vp.left = hadj->value;\n        wview->vp.top = vadj->value;\n        wview->vp.width = hadj->page_size;\n        wview->vp.height = vadj->page_size;\n\n        wview->width = hadj->upper;\n        wview->height = vadj->upper;\n\n\t/* Update vp hint in model too.\n\t */\n\tws->vp = wview->vp;\n\n#ifdef DEBUG\n\tprintf( \"workspaceview_scroll_update: %s\\n\", IOBJECT( ws )->name );\n\tprintf( \"  wview->vp: l=%d, t=%d, w=%d, h=%d; fixed w=%d; h=%d\\n\",\n\t\twview->vp.left, wview->vp.top, \n\t\twview->vp.width, wview->vp.height,\n\t\twview->width, wview->height );\n#endif /*DEBUG*/\n}\n\nstatic void\nworkspaceview_watch_changed_cb( Watchgroup *watchgroup, Watch *watch, \n\tWorkspaceview *wview )\n{\n\t/* Names of prefs we watch. These are really rowview preferences, but\n\t * we follow them here to prevent every rowview having to have it's\n\t * own connection.\n\t */\n\tstatic char *watch_names[] = {\n\t\t\"CALC_DISPLAY_LED\"\n\t};\n\n\tint i;\n\n\tfor( i = 0; i < IM_NUMBER( watch_names ); i++ ) \n\t\tif( strcmp( IOBJECT( watch )->name, watch_names[i] ) == 0 ) {\n\t\t\tview_map_all( VIEW( wview ), \n\t\t\t\t(view_map_fn) vobject_refresh_queue, NULL );\n\t\t\tbreak;\n\t\t}\n}\n\n/* Scroll events ... handle mousewheel shortcuts here. Do this ourselves\n * (rather than just relying on the scrollbars) so we can do shift + wheel == \n * left/right.\n */\nstatic gboolean\nworkspaceview_scroll_event_cb( GtkWidget *widget, \n\tGdkEventScroll *ev, Workspaceview *wview )\n{\n\tgboolean handled = FALSE;\n\n\t/* Gimp uses page_incr / 4 I think, but then scroll speed varies with\n\t * window size, which is pretty odd. Just use a constant.\n\t */\n\tconst int incr = 50;\n\n\tif( ev->direction == GDK_SCROLL_UP || \n\t\tev->direction == GDK_SCROLL_DOWN ) {\n\t\tif( ev->state & GDK_SHIFT_MASK ) {\n\t\t\tif( ev->direction == GDK_SCROLL_UP )\n\t\t\t\tworkspaceview_scroll_to( wview, \n\t\t\t\t\twview->vp.left + incr, wview->vp.top );\n\t\t\telse\n\t\t\t\tworkspaceview_scroll_to( wview, \n\t\t\t\t\twview->vp.left - incr, wview->vp.top );\n\n\t\t\thandled = TRUE;\n\t\t}\n\t\telse {\n\t\t\tif( ev->direction == GDK_SCROLL_UP )\n\t\t\t\tworkspaceview_scroll_to( wview, \n\t\t\t\t\twview->vp.left, wview->vp.top - incr );\n\t\t\telse\n\t\t\t\tworkspaceview_scroll_to( wview, \n\t\t\t\t\twview->vp.left, wview->vp.top + incr );\n\n\t\t\thandled = TRUE;\n\t\t}\n\t}\n\n\treturn( handled );\n}\n\nstatic void\nworkspaceview_realize_cb( GtkWidget *wid, Workspaceview *wview )\n{\n\tg_assert( wid->window );\n\n\tgtk_widget_add_events( wid, GDK_BUTTON_PRESS_MASK );\n}\n\nvoid\nworkspaceview_set_cursor( Workspaceview *wview, iWindowShape shape )\n{\n\tif( !wview->context ) \n\t\twview->context = iwindow_cursor_context_new( \n\t\t\tIWINDOW( view_get_toplevel( VIEW( wview ) ) ), 0, \n\t\t\t\"workspaceview\" );\n\n\tiwindow_cursor_context_set_cursor( wview->context, shape );\n}\n\ntypedef struct _WorkspaceviewFindColumnview {\n\tWorkspaceview *wview;\n\tint x;\n\tint y;\n} WorkspaceviewFindColumnview;\n\nstatic void *\nworkspaceview_find_columnview_sub( View *view, \n\tWorkspaceviewFindColumnview *args )\n{\n\tColumnview *cview = COLUMNVIEW( view );\n\tRect col;\n\tint x, y, w, h;\n\n\tcolumnview_get_position( cview, &x, &y, &w, &h );\n\tcol.left = x;\n\tcol.top = y;\n\tcol.width = w;\n\tcol.height = h;\n\n\tif( im_rect_includespoint( &col, args->x, args->y ) )\n\t\treturn( cview );\n\n\treturn( NULL );\n}\n\n/* Test for a point is workspaceview background ... ie. is not enclosed by one\n * of our columns.\n */\nstatic Columnview *\nworkspaceview_find_columnview( Workspaceview *wview, int x, int y )\n{\n\tWorkspaceviewFindColumnview args;\n\tvoid *res;\n\n\targs.wview = wview;\n\targs.x = x;\n\targs.y = y;\n\n\tres = view_map( VIEW( wview ),\n\t\t(view_map_fn) workspaceview_find_columnview_sub, &args, NULL );\n\n\tif( res )\n\t\treturn( COLUMNVIEW( res ) );\n\telse\n\t\treturn( NULL );\n}\n\n/* Is this event on the workspaceview background.\n */\nstatic gboolean\nworkspaceview_is_background( Workspaceview *wview, \n\tGdkWindow *window, int x, int y )\n{\n\t/* If the event window is not our window, it must have occured in a\n\t * sub-GdkWindow (eg. an image thumbnail), so can't be a background\n\t * click.\n\t */\n\tif( window != wview->fixed->window )\n\t\treturn( FALSE );\n\n\t/* Could be a click in a non-window widget (eg. a label); search\n\t * all columnviews for a hit.\n\t */\n\treturn( !workspaceview_find_columnview( wview, x, y ) );\n}\n\nstatic gboolean\nworkspaceview_fixed_event_cb( GtkWidget *widget, \n\tGdkEvent *ev, Workspaceview *wview )\n{\n\tgboolean handled = FALSE;\n\n#ifdef EVENT\n\tprintf( \"workspaceview_fixed_event_cb: %d\\n\", ev->type );\n#endif /*EVENT*/\n\n        switch( ev->type ) {\n        case GDK_BUTTON_PRESS:\n                if( ev->button.button == 1 ) {\n\t\t\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\n\t\t\tif( workspaceview_is_background( wview, \n\t\t\t\tev->button.window, \n\t\t\t\tev->button.x, ev->button.y ) ) {\n\t\t\t\tworkspace_deselect_all( ws );\n\t\t\t\thandled = TRUE;\n\t\t\t}\n                }\n\t\telse if( ev->button.button == 2 ) {\n#ifdef EVENT\n\t\t\tprintf( \"workspaceview_fixed_event_cb: start drag\\n\" ); \n#endif /*EVENT*/\n\n\t\t\twview->drag_x = ev->button.x_root + wview->vp.left;\n\t\t\twview->drag_y = ev->button.y_root + wview->vp.top;\n\t\t\tworkspaceview_set_cursor( wview, IWINDOW_SHAPE_MOVE );\n\t\t\twview->dragging = TRUE;\n\n                        handled = TRUE;\n\t\t}\n\n                break;\n\n        case GDK_BUTTON_RELEASE:\n                if( ev->button.button == 2 ) {\n#ifdef EVENT\n\t\t\tprintf( \"workspaceview_fixed_event_cb: stop drag\\n\" ); \n#endif /*EVENT*/\n\n\t\t\tworkspaceview_set_cursor( wview, IWINDOW_SHAPE_NONE );\n\t\t\twview->dragging = FALSE;\n\n                        handled = TRUE;\n                }\n\n                break;\n\n        case GDK_MOTION_NOTIFY:\n                if( wview->dragging && ev->motion.state & GDK_BUTTON2_MASK ) {\n#ifdef EVENT\n\t\t\tprintf( \"workspaceview_fixed_event_cb: motion\\n\" ); \n#endif /*EVENT*/\n\n\t\t\t/* We're using hints.\n\t\t\t */\n\t\t\twidget_update_pointer( GTK_WIDGET( wview ), ev );\n\n\t\t\tworkspaceview_scroll_to( wview, \n\t\t\t\twview->drag_x - ev->motion.x_root,\n\t\t\t\twview->drag_y - ev->motion.y_root );\n\n                        handled = TRUE;\n                }\n\n                break;\n\n        default:\n                break;\n        }\n\n        return( handled );\n}\n\nstatic void\nworkspaceview_scroll_adjustment_cb( GtkAdjustment *adj, Workspaceview *wview )\n{\n\tworkspaceview_scroll_update( wview );\n}\n\n/* Timer callback for background scroll.\n */\nstatic gboolean\nworkspaceview_scroll_time_cb( Workspaceview *wview )\n{\n\t/* Perform scroll.\n\t */\n\tworkspaceview_scroll_update( wview );\n\tif( wview->u != 0 || wview->v != 0 ) \n\t\tworkspaceview_displace( wview, wview->u, wview->v );\n\n\t/* Start timer again.\n\t */\n\treturn( TRUE );\n}\n\n/* Stop the tally_scroll timer.\n */\nstatic void\nworkspaceview_scroll_stop( Workspaceview *wview )\n{\t\n        IM_FREEF( g_source_remove, wview->timer );\n}\n\n/* Start the tally_scroll timer.\n */\nstatic void\nworkspaceview_scroll_start( Workspaceview *wview )\n{\n\tworkspaceview_scroll_stop( wview );\n        wview->timer = g_timeout_add( 30,\n                (GSourceFunc) workspaceview_scroll_time_cb, wview );\n}\n\n/* Set a background scroll. Pass both zero to stop scroll.\n */\nvoid\nworkspaceview_scroll_background( Workspaceview *wview, int u, int v )\n{\n\twview->u = u;\n\twview->v = v;\n\n\tif( u == 0 && v == 0 )\n\t\tworkspaceview_scroll_stop( wview );\n\telse\n\t\tworkspaceview_scroll_start( wview );\n}\n\nstatic void\nworkspaceview_destroy( GtkObject *object )\n{\n\tWorkspaceview *wview;\n\n#ifdef DEBUG\n\tprintf( \"workspaceview_destroy: %p\\n\", object );\n#endif /*DEBUG*/\n\n\tg_return_if_fail( object != NULL );\n\tg_return_if_fail( IS_WORKSPACEVIEW( object ) );\n\n\twview = WORKSPACEVIEW( object );\n\n\t/* Instance destroy.\n\t */\n\tworkspaceview_scroll_stop( wview );\n\tIM_FREEF( iwindow_cursor_context_destroy, wview->context );\n\tFREESID( wview->watch_changed_sid, main_watchgroup );\n\tDESTROY_GTK( wview->popup );\n\n\tGTK_OBJECT_CLASS( parent_class )->destroy( object );\n}\n\nstatic void\nworkspaceview_realize( GtkWidget *widget )\n{\n#ifdef DEBUG\n{\n\tWorkspaceview *wview = WORKSPACEVIEW( widget );\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\n\tprintf( \"workspaceview_realize: %s\\n\", IOBJECT( ws )->name );\n}\n#endif /*DEBUG*/\n\n\tGTK_WIDGET_CLASS( parent_class )->realize( widget );\n\n\t/* Mark us as a symbol drag-to widget. \n\t */\n\tset_symbol_drag_type( widget );\n}\n\nstatic void\nworkspaceview_drag_data_received( GtkWidget *widget, GdkDragContext *context,\n\tgint x, gint y, GtkSelectionData *selection_data,\n\tguint info, guint time ) \n{\n\tWorkspaceview *wview = WORKSPACEVIEW( widget );\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\tconst char *from_row_path = (const char *) selection_data->data;\n\tRow *from_row;\n\n#ifdef DEBUG\n\tprintf( \"workspaceview_drag_data_received:\\n\" );\n#endif /*DEBUG*/\n\n\t/* We seem to rx drag events with x/y relative to the viewport.\n\t */\n\tx += wview->vp.left;\n\ty += wview->vp.top;\n\n\tif( info == TARGET_SYMBOL && selection_data->length > 0 && \n\t\tselection_data->format == 8 &&\n\t\tworkspaceview_is_background( wview, \n\t\t\tGTK_WIDGET( wview->fixed )->window, x, y ) &&\n\t\t(from_row = row_parse_name( main_workspaceroot->sym, \n\t\t\tfrom_row_path )) ) {\n\t\tchar new_name[MAX_STRSIZE];\n\t\tColumn *col;\n\t\tchar vips_buf_text[256];\n\t\tVipsBuf buf = VIPS_BUF_STATIC( vips_buf_text );\n\t\tSymbol *sym;\n\n\t\tworkspace_column_name_new( ws, new_name );\n\t\tcol = column_new( ws, new_name );\n\n\t\tcol->x = x;\n\t\tcol->y = y;\n\t\tworkspace_column_select( ws, col );\n\n\t\t/* Qualify relative to us. We don't want to embed\n\t\t * workspace names unless we have to.\n\t\t */\n\t\trow_qualified_name_relative( ws->sym, from_row, &buf );\n\n\t\tif( !(sym = workspace_add_def( ws, vips_buf_all( &buf ) )) ) \n\t\t\tiwindow_alert( widget, GTK_MESSAGE_ERROR );\n\n\t\tsymbol_recalculate_all();\n\n\t\t/* Usually the drag-from row will be selected, very\n\t\t * annoying. Select the drag-to row.\n\t\t */\n\t\tif( sym && \n\t\t\tsym->expr && \n\t\t\tsym->expr->row )\n\t\t\trow_select( sym->expr->row );\n\t}\n}\n\nstatic void *\nworkspaceview_child_size_sub( Columnview *cview, Rect *area )\n{\n\tint x, y, w, h;\n\tRect col;\n\n\tcolumnview_get_position( cview, &x, &y, &w, &h );\n\n\tcol.left = x;\n\tcol.top = y;\n\tcol.width = w;\n\tcol.height = h;\n\n\tim_rect_unionrect( area, &col, area );\n\n\treturn( NULL );\n}\n\nstatic void\nworkspaceview_child_size_cb( Columnview *cview, \n\tGtkAllocation *allocation, Workspaceview *wview )\n{\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\n\tint right, bottom;\n\n\tg_assert( IS_WORKSPACEVIEW( wview ) );\n\n\t/* Compute a new bounding box for our children.\n\t */\n\twview->bounding.left = 0;\n\twview->bounding.top = 0;\n\twview->bounding.width = 0;\n\twview->bounding.height = 0;\n\n\t(void) view_map( VIEW( wview ),\n\t\t(view_map_fn) workspaceview_child_size_sub, \n\t\t&wview->bounding, NULL );\n\n\twview->bounding.width += 1000;\n\twview->bounding.height += 1000;\n\n#ifdef DEBUG\n{\n\tColumn *col = COLUMN( VOBJECT( cview )->iobject );\n\n\tprintf( \"workspaceview_child_size_cb: cview %s \"\n\t\t\"bb left=%d, top=%d, width=%d, height=%d\\n\",\n\t\tIOBJECT( col )->name, \n\t\twview->bounding.left,\n\t\twview->bounding.top,\n\t\twview->bounding.width,\n\t\twview->bounding.height );\n}\n#endif /*DEBUG*/\n\n\t/* Resize our fixed if necessary.\n\t */\n\tright = IM_RECT_RIGHT( &wview->bounding );\n\tbottom = IM_RECT_BOTTOM( &wview->bounding );\n\tif( right != wview->width || bottom != wview->height ) {\n\t\tgtk_widget_set_size_request( GTK_WIDGET( wview->fixed ), \n\t\t\tright, bottom ); \n\n\t\t/* Update the model hints ... it uses bounding to position\n\t\t * loads and saves.\n\t\t */\n\t\tws->area = wview->bounding;\n\t\tfilemodel_set_offset( FILEMODEL( wsg ), \n\t\t\tws->area.left, ws->area.top );\n\t}\n}\n\n/* Pick an xy position for the next column.\n */\nstatic void\nworkspaceview_pick_xy( Workspaceview *wview, int *x, int *y )\n{\n\t/* Position already set? No change.\n\t */\n\tif( *x >= 0 )\n\t\treturn;\n\n\t/* Set this position.\n\t */\n\t*x = wview->next_x + wview->vp.left;\n\t*y = wview->next_y + wview->vp.top;\n\n\t/* And move on.\n\t */\n\twview->next_x += 30;\n\twview->next_y += 30;\n\tif( wview->next_x > 300 )\n\t\twview->next_x = 3;\n\tif( wview->next_y > 200 )\n\t\twview->next_y = 3;\n}\n\nstatic void\nworkspaceview_link( View *view, Model *model, View *parent )\n{\n\tWorkspaceview *wview = WORKSPACEVIEW( view );\n\tWorkspace *ws = WORKSPACE( model );\n\n\tVIEW_CLASS( parent_class )->link( view, model, parent );\n\n\tvobject_link( VOBJECT( wview->toolkitbrowser ), \n\t\tIOBJECT( ws->kitg ) );\n\tvobject_link( VOBJECT( wview->workspacedefs ), IOBJECT( ws ) );\n\n\ttoolkitbrowser_set_workspace( wview->toolkitbrowser, ws ); \n\n\tpane_set_state( wview->rpane, ws->rpane_open, ws->rpane_position ); \n\tpane_set_state( wview->lpane, ws->lpane_open, ws->lpane_position ); \n}\n\nstatic void\nworkspaceview_child_add( View *parent, View *child )\n{\n\tColumnview *cview = COLUMNVIEW( child );\n\tColumn *column = COLUMN( VOBJECT( cview )->iobject );\n\tWorkspaceview *wview = WORKSPACEVIEW( parent );\n\n\tgtk_signal_connect( GTK_OBJECT( child ), \"size_allocate\", \n\t\tGTK_SIGNAL_FUNC( workspaceview_child_size_cb ), parent );\n\n\tVIEW_CLASS( parent_class )->child_add( parent, child );\n\n\t/* Pick start xy pos. \n\t */\n        workspaceview_pick_xy( wview, &column->x, &column->y );\n\tgtk_fixed_put( GTK_FIXED( wview->fixed ),\n\t\tGTK_WIDGET( cview ), column->x, column->y );\n\tcview->lx = column->x;\n\tcview->ly = column->y;\n}\n\nstatic void\nworkspaceview_child_position( View *parent, View *child )\n{\n\tWorkspaceview *wview = WORKSPACEVIEW( parent );\n\tColumnview *cview = COLUMNVIEW( child );\n\n\tgtk_fixed_move( GTK_FIXED( wview->fixed ),\n\t\tGTK_WIDGET( cview ), cview->lx, cview->ly );\n\n\tVIEW_CLASS( parent_class )->child_position( parent, child );\n}\n\nstatic void\nworkspaceview_child_front( View *parent, View *child )\n{\n\tWorkspaceview *wview = WORKSPACEVIEW( parent );\n\tColumnview *cview = COLUMNVIEW( child );\n\n\t\tgtk_widget_ref( GTK_WIDGET( cview ) );\n\t\tgtk_container_remove( GTK_CONTAINER( wview->fixed ),\n\t\t\tGTK_WIDGET( cview ) );\n\t\tgtk_fixed_put( GTK_FIXED( wview->fixed ),\n\t\t\tGTK_WIDGET( cview ), cview->lx, cview->ly );\n\t\tgtk_widget_unref( GTK_WIDGET( cview ) );\n}\n\nstatic void \nworkspaceview_refresh( vObject *vobject )\n{\n\tWorkspaceview *wview = WORKSPACEVIEW( vobject );\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\n#ifdef DEBUG\n\tprintf( \"workspaceview_refresh: %p %s\\n\", ws, IOBJECT( ws )->name );\n#endif /*DEBUG*/\n\n\tgtk_widget_set_sensitive( GTK_WIDGET( wview ), !ws->locked );\n\n\tworkspace_jump_update( ws, wview->popup_jump );\n\n\tif( ws->rpane_open && !wview->rpane->open )\n\t\tpane_animate_open( wview->rpane );\n\tif( !ws->rpane_open && wview->rpane->open )\n\t\tpane_animate_closed( wview->rpane );\n\n\tif( ws->lpane_open && !wview->lpane->open )\n\t\tpane_animate_open( wview->lpane );\n\tif( !ws->lpane_open && wview->lpane->open )\n\t\tpane_animate_closed( wview->lpane );\n\n\tif( wview->label ) {\n\t\tgtk_label_set_text( GTK_LABEL( wview->label ),\n\t\t\tIOBJECT( ws )->name );\n\n\t\tif( IOBJECT( ws )->caption )\n\t\t\tset_tooltip( wview->label, \n\t\t\t\t\"%s\", IOBJECT( ws )->caption );\n\n\t\tif( ws->locked ) \n\t\t\tgtk_image_set_from_stock( GTK_IMAGE( wview->padlock ), \n\t\t\t\tSTOCK_LOCK, GTK_ICON_SIZE_MENU );\n\t\telse\n\t\t\tgtk_image_clear( GTK_IMAGE( wview->padlock ) );  \n\n\t\tif( ws->errors ) \n\t\t\tgtk_image_set_from_stock( GTK_IMAGE( wview->alert ), \n\t\t\t\tSTOCK_ALERT, GTK_ICON_SIZE_MENU );\n\t\telse\n\t\t\tgtk_image_clear( GTK_IMAGE( wview->alert ) );  \n\n\t}\n\n\tVOBJECT_CLASS( parent_class )->refresh( vobject );\n}\n\n/* What we track during a layout.\n */\ntypedef struct _WorkspaceLayout {\n\t/* Context.\n\t */\n\tWorkspaceview *wview;\n\n\t/* Set of columnviews still to be laid out.\n\t */\n\tGSList *undone_columns;\n\n\t/* Track the current set of columns here.\n\t */\n\tGSList *current_columns;\n\n\t/* Current position for write.\n\t */\n\tint out_x, out_y;\n\n\t/* Accumulate the size of the current set of columns here.\n\t */\n\tRect area;\n\n\t/* Track the current columnview here.\n\t */\n\tColumnview *cview;\n} WorkspaceLayout;\n\nstatic void *\nworkspaceview_layout_add( View *view, WorkspaceLayout *layout )\n{\n\tlayout->undone_columns = \n\t\tg_slist_prepend( layout->undone_columns, view );\n\n\treturn( NULL );\n}\n\nstatic void *\nworkspaceview_layout_find_leftmost( Columnview *cview, WorkspaceLayout *layout )\n{\n\tif( GTK_WIDGET( cview )->allocation.x < layout->area.left ) {\n\t\tlayout->area.left = GTK_WIDGET( cview )->allocation.x;\n\t\tlayout->cview = cview;\n\t}\n\n\treturn( NULL );\n}\n\nstatic void *\nworkspaceview_layout_find_similar_x( Columnview *cview, \n\tWorkspaceLayout *layout )\n{\n\tint x = GTK_WIDGET( cview )->allocation.x;\n\n\tgboolean snap;\n\n\tsnap = FALSE;\n\n\t/* Special case: a colum at zero makes a new column on the far left.\n\t */\n\tif( layout->area.left == 0 && \n\t\tx == 0 ) \n\t\tsnap = TRUE;\n\n\tif( layout->area.left > 0 &&\n\t\tABS( x - layout->area.left ) < \n\t\t\tworkspaceview_layout_snap_threshold ) \n\t\tsnap = TRUE;\n\t\n\tif( snap ) { \n\t\tlayout->current_columns = g_slist_prepend(\n\t\t\tlayout->current_columns, cview );\n\t\tlayout->area.width = IM_MAX( layout->area.width, \n\t\t\tGTK_WIDGET( cview )->allocation.width ); \n\t}\n\n\treturn( NULL );\n}\n\n/* Compare func for row recomp sort.\n */\nstatic int\nworkspaceview_layout_sort_y( Columnview *a, Columnview *b )\n{\n\treturn( GTK_WIDGET( a )->allocation.y - GTK_WIDGET( b )->allocation.y );\n}\n\nstatic void *\nworkspaceview_layout_set_pos( Columnview *cview, WorkspaceLayout *layout )\n{\n\tColumn *column = COLUMN( VOBJECT( cview )->iobject );\n\n\tgboolean changed;\n\n\tchanged = FALSE;\n\n\t/* If this column is being dragged, put the xy we allocate into the\n\t * shadow instead. \n\t */\n\tif( cview->shadow ) {\n\t\tif( cview->shadow->lx != layout->out_x ||\n\t\t\tcview->shadow->ly != layout->out_y ) {\n\t\t\tcview->shadow->lx = layout->out_x;\n\t\t\tcview->shadow->ly = layout->out_y;\n\t\t\tchanged = TRUE;\n\t\t}\n\t}\n\telse {\n\t\tif( column->x != layout->out_x ||\n\t\t\tcolumn->y != layout->out_y ) { \n\t\t\tcolumn->x = layout->out_x;\n\t\t\tcolumn->y = layout->out_y;\n\t\t\tchanged = TRUE;\n\t\t}\n\t}\n\n\tlayout->out_y += GTK_WIDGET( cview )->allocation.height +\n\t\tworkspaceview_layout_vspacing;\n\n\tif( changed ) \n\t\tiobject_changed( IOBJECT( column ) ); \n\n\treturn( NULL );\n}\n\nstatic void *\nworkspaceview_layout_strike( Columnview *cview, WorkspaceLayout *layout )\n{\n\tlayout->undone_columns = g_slist_remove( layout->undone_columns, \n\t\tcview );\n\n\treturn( NULL );\n}\n\nstatic void\nworkspaceview_layout_loop( WorkspaceLayout *layout )\n{\n\tlayout->cview = NULL;\n\tlayout->area.left = INT_MAX;\n\tslist_map( layout->undone_columns,\n\t\t(SListMapFn) workspaceview_layout_find_leftmost, layout );\n\n\tlayout->current_columns = NULL;\n\tlayout->area.width = GTK_WIDGET( layout->cview )->allocation.width;\n\tslist_map( layout->undone_columns,\n\t\t(SListMapFn) workspaceview_layout_find_similar_x, layout );\n\n\tlayout->current_columns = g_slist_sort( layout->current_columns,\n\t\t(GCompareFunc) workspaceview_layout_sort_y );\n\n\tlayout->out_y = workspaceview_layout_top;\n\tslist_map( layout->current_columns,\n\t\t(SListMapFn) workspaceview_layout_set_pos, layout );\n\n\tlayout->out_x += layout->area.width + workspaceview_layout_hspacing;\n\n\tslist_map( layout->current_columns,\n\t\t(SListMapFn) workspaceview_layout_strike, layout );\n\n\tIM_FREEF( g_slist_free, layout->current_columns );\n}\n\n/* Autolayout ... try to rearrange columns so they don't overlap. \n\n\tStrategy:\n\n\tsearch for left-most column\n\n\tsearch for all columns with a 'small' overlap\n\n\tlay those columns out vertically with some space between them ... keep\n\tthe vertical ordering we had before\n\n\tfind the width of the widest, move output over that much\n\n\tstrike that set of columns from the list of columns to be laid out\n */\nstatic void\nworkspaceview_layout( View *view )\n{\n\tWorkspaceview *wview = WORKSPACEVIEW( view );\n\tWorkspaceLayout layout;\n\n\tlayout.wview = wview;\n\tlayout.undone_columns = NULL;\n\tlayout.current_columns = NULL;\n\tlayout.out_x = workspaceview_layout_left;\n\n\tview_map( VIEW( wview ),\n\t\t(view_map_fn) workspaceview_layout_add, &layout, NULL );\n\n\twhile( layout.undone_columns )\n\t\tworkspaceview_layout_loop( &layout );\n}\n\nstatic void\nworkspaceview_class_init( WorkspaceviewClass *class )\n{\n\tGtkObjectClass *object_class = (GtkObjectClass *) class;\n\tGtkWidgetClass *widget_class = (GtkWidgetClass *) class;\n\tvObjectClass *vobject_class = (vObjectClass *) class;\n\tViewClass *view_class = (ViewClass *) class;\n\n\tparent_class = g_type_class_peek_parent( class );\n\n\tobject_class->destroy = workspaceview_destroy;\n\n\twidget_class->realize = workspaceview_realize;\n\twidget_class->drag_data_received = workspaceview_drag_data_received;\n\n\tvobject_class->refresh = workspaceview_refresh;\n\n\tview_class->link = workspaceview_link;\n\tview_class->child_add = workspaceview_child_add;\n\tview_class->child_position = workspaceview_child_position;\n\tview_class->child_front = workspaceview_child_front;\n\tview_class->layout = workspaceview_layout;\n}\n\n/* Can't use main_load(), we want to select wses after load.\n */\nstatic gboolean\nworkspaceview_load( Workspace *ws, const char *filename )\n{\n\tWorkspacegroup *wsg = workspace_get_workspacegroup( ws );\n\tWorkspaceroot *wsr = wsg->wsr; \n\n\tWorkspacegroup *new_wsg;\n\n\tif( (new_wsg = mainw_open_workspace( wsr, filename )) ) \n\t\treturn( TRUE );\n\n\terror_clear();\n\n\t/* workspace_load_file() needs to recalc to work, try to avoid that by\n\t * doing .defs first.\n\t */\n\tif( is_file_type( &filesel_dfile_type, filename ) ) {\n\t\tif( toolkit_new_from_file( main_toolkitgroup, filename ) )\n\t\t\treturn( TRUE );\n\n\t\terror_clear();\n\t}\n\n\t/* Try as matrix or image. Have to do these via definitions.\n\t */\n\tif( workspace_load_file( ws, filename ) ) \n\t\treturn( TRUE );\n\n\terror_clear();\n\n\terror_top( _( \"Unknown file type.\" ) );\n\terror_sub( _( \"Unable to load \\\"%s\\\".\" ), filename );\n\n\treturn( FALSE );\n}\n\nstatic void\nworkspaceview_lpane_changed_cb( Pane *pane, Workspaceview *wview )\n{\n\tWorkspace *ws;\n\n\tif( (ws = WORKSPACE( VOBJECT( wview )->iobject )) ) \n\t\tif( ws->lpane_open != pane->open ||\n\t\t\tws->lpane_position != pane->user_position ) {\n\t\t\tws->lpane_open = pane->open;\n\t\t\tws->lpane_position = pane->user_position;\n\n\t\t\tprefs_set( \"WORKSPACE_LPANE_OPEN\", \"%d\", \n\t\t\t\tws->lpane_open ); \n\t\t\tprefs_set( \"WORKSPACE_LPANE_POSITION\", \"%d\", \n\t\t\t\tws->lpane_position ); \n\n\t\t\tiobject_changed( IOBJECT( ws ) );\n\t\t}\n}\n\nstatic void\nworkspaceview_rpane_changed_cb( Pane *pane, Workspaceview *wview )\n{\n\tWorkspace *ws;\n\n\tif( (ws = WORKSPACE( VOBJECT( wview )->iobject )) ) \n\t\tif( ws->rpane_open != pane->open ||\n\t\t\tws->rpane_position != pane->user_position ) {\n\t\t\tws->rpane_open = pane->open;\n\t\t\tws->rpane_position = pane->user_position;\n\n\t\t\tprefs_set( \"WORKSPACE_RPANE_OPEN\", \"%d\", \n\t\t\t\tws->rpane_open ); \n\t\t\tprefs_set( \"WORKSPACE_RPANE_POSITION\", \"%d\", \n\t\t\t\tws->rpane_position ); \n\n\t\t\tiobject_changed( IOBJECT( ws ) );\n\t\t}\n}\n\nstatic gboolean\nworkspaceview_filedrop( Workspaceview *wview, const char *filename )\n{\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\n\tgboolean result;\n\n\tresult = workspaceview_load( ws, filename );\n\tif( result )\n\t\tsymbol_recalculate_all();\n\n\treturn( result );\n}\n\nstatic void\nworkspaceview_column_new_action_cb2( GtkWidget *wid, GtkWidget *host, \n\tWorkspaceview *wview )\n{\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\n\tif( !workspace_column_new( ws ) ) \n\t\tiwindow_alert( GTK_WIDGET( wview ), GTK_MESSAGE_ERROR );\n}\n\nstatic void\nworkspaceview_group_action_cb2( GtkWidget *wid, GtkWidget *host, \n\tWorkspaceview *wview )\n{\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\n\tworkspace_selected_group( ws );\n}\n\nstatic void\nworkspaceview_next_error_action_cb2( GtkWidget *wid, GtkWidget *host, \n\tWorkspaceview *wview )\n{\n\tWorkspace *ws = WORKSPACE( VOBJECT( wview )->iobject );\n\n\tif( !workspace_next_error( ws ) ) {\n\t\terror_top( _( \"No errors in tab.\" ) );\n\t\terror_sub( \"%s\", _( \"There are no errors (that I can see) \"\n\t\t\t\"in this tab.\" ) );\n\t\tiwindow_alert( GTK_WIDGET( wview ), GTK_MESSAGE_INFO );\n\t}\n}\n\nstatic void\nworkspaceview_init( Workspaceview *wview )\n{\n\tGtkAdjustment *hadj;\n\tGtkAdjustment *vadj;\n\tPanechild *panechild;\n\tGtkWidget *ebox;\n\n\twview->fixed = NULL;\n\twview->window = NULL;\n\n\twview->timer = 0;\n\twview->u = 0;\n\twview->v = 0;\n\n\twview->dragging = FALSE;\n\twview->drag_x = 0;\n\twview->drag_y = 0;\n\n\twview->vp.left = 0;\n\twview->vp.top = 0;\n\twview->vp.width = 0;\n\twview->vp.height = 0;\n\twview->width = -1;\n\twview->height = -1;\n\twview->bounding.left = 0;\n\twview->bounding.top = 0;\n\twview->bounding.width = 0;\n\twview->bounding.height = 0;\n\n\twview->next_x = 3;\n\twview->next_y = 3;\n\n\twview->context = NULL; \n\n\twview->watch_changed_sid = g_signal_connect( main_watchgroup, \n\t\t\"watch_changed\",\n\t\tG_CALLBACK( workspaceview_watch_changed_cb ), wview );\n\n\twview->rpane = pane_new( PANE_HIDE_RIGHT );\n\tg_signal_connect( wview->rpane, \"changed\",\n\t\tG_CALLBACK( workspaceview_rpane_changed_cb ), wview );\n\tgtk_box_pack_start( GTK_BOX( wview ), \n\t\tGTK_WIDGET( wview->rpane ), TRUE, TRUE, 2 );\n\tgtk_widget_show( GTK_WIDGET( wview->rpane ) );\n\n\twview->lpane = pane_new( PANE_HIDE_LEFT );\n\tg_signal_connect( wview->lpane, \"changed\",\n\t\tG_CALLBACK( workspaceview_lpane_changed_cb ), wview );\n\tgtk_paned_pack1( GTK_PANED( wview->rpane ), \n\t\tGTK_WIDGET( wview->lpane ), TRUE, FALSE );\n\tgtk_widget_show( GTK_WIDGET( wview->lpane ) );\n\n\t/* Ask for our own window so we can spot events on the window \n\t * background.\n\t */\n\twview->fixed = gtk_fixed_new();\n\tgtk_widget_add_events( GTK_WIDGET( wview->fixed ), \n\t\tGDK_POINTER_MOTION_MASK | \n\t\tGDK_POINTER_MOTION_HINT_MASK |\n\t\tGDK_BUTTON_PRESS_MASK | \n\t\tGDK_BUTTON_RELEASE_MASK ); \n\tgtk_fixed_set_has_window( GTK_FIXED( wview->fixed ), TRUE );\n\twview->window = gtk_scrolled_window_new( NULL, NULL );\n\tgtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( wview->window ), \n\t\tGTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );\n\tgtk_scrolled_window_add_with_viewport( \n\t\tGTK_SCROLLED_WINDOW( wview->window ), wview->fixed );\n\tgtk_viewport_set_shadow_type( \n\t\tGTK_VIEWPORT( GTK_BIN( wview->window )->child ), \n\t\tGTK_SHADOW_NONE );\n\tgtk_signal_connect( GTK_OBJECT( wview->window ), \"scroll_event\",\n\t\tGTK_SIGNAL_FUNC( workspaceview_scroll_event_cb ), wview );\n\tgtk_signal_connect( GTK_OBJECT( wview->fixed ), \"realize\", \n\t\tGTK_SIGNAL_FUNC( workspaceview_realize_cb ), wview );\n        gtk_signal_connect( GTK_OBJECT( wview->fixed ), \"event\",\n                GTK_SIGNAL_FUNC( workspaceview_fixed_event_cb ), wview );\n\tgtk_widget_add_events( GTK_WIDGET( wview->fixed ), \n\t\tGDK_BUTTON_MOTION_MASK | \n\t\tGDK_POINTER_MOTION_HINT_MASK |\n\t\tGDK_BUTTON_PRESS_MASK |\n\t\tGDK_BUTTON_RELEASE_MASK ); \n\n\thadj = gtk_scrolled_window_get_hadjustment( \n\t\tGTK_SCROLLED_WINDOW( wview->window ) );\n\tvadj = gtk_scrolled_window_get_vadjustment( \n\t\tGTK_SCROLLED_WINDOW( wview->window ) );\n\tgtk_signal_connect( GTK_OBJECT( hadj ), \"value_changed\", \n\t\tGTK_SIGNAL_FUNC( workspaceview_scroll_adjustment_cb ), wview );\n\tgtk_signal_connect( GTK_OBJECT( hadj ), \"changed\", \n\t\tGTK_SIGNAL_FUNC( workspaceview_scroll_adjustment_cb ), wview );\n\tgtk_signal_connect( GTK_OBJECT( vadj ), \"value_changed\", \n\t\tGTK_SIGNAL_FUNC( workspaceview_scroll_adjustment_cb ), wview );\n\tgtk_signal_connect( GTK_OBJECT( vadj ), \"changed\", \n\t\tGTK_SIGNAL_FUNC( workspaceview_scroll_adjustment_cb ), wview );\n\n        /* We can't use gtk_container_set_focus_hadjustment() etc. since our\n         * workspace contains a lot of nested structures, and hadjustment()\n         * only works for single-layer things. Instead, do focus scrolling\n         * ourselves .. see rowview.c.\n         */\n\n\tgtk_paned_pack2( GTK_PANED( wview->lpane ), \n\t\tGTK_WIDGET( wview->window ), TRUE, FALSE );\n\n\t/* Toolkit Browser pane.\n\t */\n\tpanechild = panechild_new( wview->rpane, _( \"Toolkit Browser\" ) );\n\n\t/* Have to put toolkitbrowser in an ebox so the search entry gets\n\t * clipped to the pane size.\n\t */\n\tebox = gtk_event_box_new();\n\tgtk_container_add( GTK_CONTAINER( panechild ), GTK_WIDGET( ebox ) );\n\tgtk_widget_show( ebox );\n\n\twview->toolkitbrowser = toolkitbrowser_new();\n\tgtk_container_add( GTK_CONTAINER( ebox ), \n\t\tGTK_WIDGET( wview->toolkitbrowser ) );\n\tgtk_widget_show( GTK_WIDGET( wview->toolkitbrowser ) );\n\n\t/* Workspace-local defs pane.\n\t */\n\tpanechild = panechild_new( wview->lpane, _( \"Tab Definitions\" ) );\n\n\twview->workspacedefs = workspacedefs_new();\n\tgtk_container_add( GTK_CONTAINER( panechild ), \n\t\tGTK_WIDGET( wview->workspacedefs ) );\n\tgtk_widget_show( GTK_WIDGET( wview->workspacedefs ) );\n\n\tfiledrop_register( GTK_WIDGET( wview ),\n\t\t(FiledropFunc) workspaceview_filedrop, wview );\n\n\twview->popup = popup_build( _( \"Workspace menu\" ) );\n\n\tpopup_add_but( wview->popup, _( \"New C_olumn\" ),\n\t\tPOPUP_FUNC( workspaceview_column_new_action_cb2 ) ); \n\twview->popup_jump = popup_add_pullright( wview->popup, \n\t\t_( \"Jump to _Column\" ) ); \n\tmenu_add_sep( wview->popup );\n\tpopup_add_but( wview->popup, _( \"_Group Selected\" ),\n\t\tPOPUP_FUNC( workspaceview_group_action_cb2 ) ); \n\tmenu_add_sep( wview->popup );\n\tpopup_add_but( wview->popup, STOCK_NEXT_ERROR,\n\t\tPOPUP_FUNC( workspaceview_next_error_action_cb2 ) ); \n\tpopup_attach( wview->fixed, wview->popup, wview );\n\n\tgtk_widget_show_all( wview->window );\n}\n\nGtkType\nworkspaceview_get_type( void )\n{\n\tstatic GtkType type = 0;\n\n\tif( !type ) {\n\t\tstatic const GtkTypeInfo info = {\n\t\t\t\"Workspaceview\",\n\t\t\tsizeof( Workspaceview ),\n\t\t\tsizeof( WorkspaceviewClass ),\n\t\t\t(GtkClassInitFunc) workspaceview_class_init,\n\t\t\t(GtkObjectInitFunc) workspaceview_init,\n\t\t\t/* reserved_1 */ NULL,\n\t\t\t/* reserved_2 */ NULL,\n\t\t\t(GtkClassInitFunc) NULL,\n\t\t};\n\n\t\ttype = gtk_type_unique( TYPE_VIEW, &info );\n\t}\n\n\treturn( type );\n}\n\nView *\nworkspaceview_new( void )\n{\n\tWorkspaceview *wview = gtk_type_new( TYPE_WORKSPACEVIEW );\n\n\treturn( VIEW( wview ) );\n}\n\nvoid\nworkspaceview_set_label( Workspaceview *wview, \n\tGtkWidget *label, GtkWidget *padlock, GtkWidget *alert )\n{\n\tg_assert( !wview->label );\n\tg_assert( !wview->padlock );\n\tg_assert( !wview->alert );\n\n\twview->label = label;\n\twview->padlock = padlock;\n\twview->alert = alert;\n}\n"
  },
  {
    "path": "src/workspaceview.h",
    "content": "/* a view of a workspace\n */\n\n/*\n\n    Copyright (C) 1991-2003 The National Gallery\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n\n */\n\n/*\n\n    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk\n\n*/\n\n#define TYPE_WORKSPACEVIEW (workspaceview_get_type())\n#define WORKSPACEVIEW( obj ) \\\n\t(GTK_CHECK_CAST( (obj), TYPE_WORKSPACEVIEW, Workspaceview ))\n#define WORKSPACEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_CAST( (klass), \\\n\t\tTYPE_WORKSPACEVIEW, WorkspaceviewClass ))\n#define IS_WORKSPACEVIEW( obj ) (GTK_CHECK_TYPE( (obj), TYPE_WORKSPACEVIEW ))\n#define IS_WORKSPACEVIEW_CLASS( klass ) \\\n\t(GTK_CHECK_CLASS_TYPE( (klass), TYPE_WORKSPACEVIEW ))\n\n/* Column margins.\n */\n#define WORKSPACEVIEW_MARGIN_LEFT (5)\n#define WORKSPACEVIEW_MARGIN_TOP (5)\n\nstruct _Workspaceview {\n\tView view;\n\n\tGtkWidget *fixed;\t\t/* GtkFixed for tally */\n\tGtkWidget *window;\t\t/* ScrolledWindow holding fixed */\n\tToolkitbrowser *toolkitbrowser;\n\tWorkspacedefs *workspacedefs;\n\tGtkWidget *label;\t\t/* Tab label */\n\tGtkWidget *padlock;\t\t/* The padlock icon */\n\tGtkWidget *alert;\t\t/* The alert icon */\n\n\t/* Left and right panes ... program window and toolkit browser.\n\t */\n\tPane *lpane;\n\tPane *rpane;\n\n\tGtkWidget *popup;\n\tGtkWidget *popup_jump;\n\n\t/* Background window scroll.\n\t */\n\tguint timer;\n\tint u;\t\t\t\t/* Set by columnview for bg scroll */\n\tint v;\n\n\t/* Middle button drag scroll.\n\t */\n\tgboolean dragging;\n\tint drag_x;\n\tint drag_y;\n\n\t/* Geometry.\n\t */\n\tRect vp;\t\t\t/* Viewport pos and size */\n\tint width;\t\t\t/* Size of fixed area */\n\tint height;\n\tRect bounding;\t\t\t/* Bounding box of columnviews */\n\n\t/* Placement hints for new columns.\n\t */\n\tint next_x;\n\tint next_y;\n\n\t/* Context we use to change cursor shape.\n\t */\n\tiWindowCursorContext *context;\n\n\t/* Follow prefs changes.\n\t */\n\tguint watch_changed_sid;\n\n\t/* Only show the compat warning once.\n\t */\n\tgboolean popped_compat;\n};\n\ntypedef struct _WorkspaceviewClass {\n\tViewClass parent_class;\n\n\t/* My methods.\n\t */\n} WorkspaceviewClass;\n\nvoid workspaceview_scroll( Workspaceview *wview, int x, int y, int w, int h );\nvoid workspaceview_scroll_background( Workspaceview *wview, int u, int v );\n\nvoid workspaceview_set_cursor( Workspaceview *wview, iWindowShape shape );\n\nGtkType workspaceview_get_type( void );\nView *workspaceview_new( void );\n\nvoid workspaceview_set_label( Workspaceview *wview, \n\tGtkWidget *label, GtkWidget *padlock, GtkWidget *alert );\n"
  },
  {
    "path": "test/Makefile.am",
    "content": "\nEXTRA_DIST = \\\n\tworkspaces \\\n\textras \\\n\timages \n\nTESTS = \\\n\ttest_all.sh \n\n"
  },
  {
    "path": "test/extras/test_magick2.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace window_x=\"0\" window_y=\"28\" window_width=\"1920\" window_height=\"1052\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" locked=\"false\" lpane_position=\"100\" lpane_open=\"false\" rpane_position=\"400\" rpane_open=\"false\" local_defs=\"// private definitions for this tab&#10;\" name=\"tab2\" caption=\"Default empty tab\" filename=\"$HOME/GIT/nip2/test/workspaces/test_magick2.ws\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"A\" caption=\"make some images\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"size\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"207\" value1=\"40\" value2=\"201\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_NewImageMenu_item.Magick_newcanvas_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"28\" window_width=\"494\" window_height=\"679\" image_left=\"232\" image_top=\"276\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"builtin\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Builtin\" labelsn=\"5\" labels0=\"rose:\" labels1=\"logo:\" labels2=\"wizard:\" labels3=\"granite:\" labels4=\"netscape:\" value=\"2\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_NewImageMenu_item.Magick_builtin_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"78\" top=\"135\" width=\"128\" height=\"128\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region A2 132 187 237 201\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"size\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"topColour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"205\" value1=\"13\" value2=\"13\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bottomColour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"202\" value1=\"233\" value2=\"91\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_NewImageMenu_item.Magick_gradient_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_NewImageMenu_item.Magick_hald_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_NewImageMenu_item.Magick_pattern_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_NewImageMenu_item.Magick_plasma_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"size\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"innerColour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"183\" value1=\"51\" value2=\"51\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"outerColour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"99\" value1=\"223\" value2=\"41\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_NewImageMenu_item.Magick_radialgradient_item.action\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"606\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"7\" name=\"B\" caption=\"All the A operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"28\" window_width=\"451\" window_height=\"182\" image_left=\"218\" image_top=\"35\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"imagetype\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Image type\" labelsn=\"16\" labels0=\"Bilevel\" labels1=\"ColorSeparation\" labels2=\"ColorSeparationAlpha\" labels3=\"ColorSeparationMatte\" labels4=\"Grayscale\" labels5=\"GrayscaleAlpha\" labels6=\"GrayscaleMatte\" labels7=\"Optimize\" labels8=\"Palette\" labels9=\"PaletteBilevelAlpha\" labels10=\"PaletteBilevelMatte\" labels11=\"PaletteAlpha\" labels12=\"PaletteMatte\" labels13=\"TrueColorAlpha\" labels14=\"TrueColorMatte\" labels15=\"TrueColor\" value=\"4\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_image_type_item.action B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"alpha\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Alpha\" labelsn=\"10\" labels0=\"On\" labels1=\"Off\" labels2=\"Set\" labels3=\"Opaque\" labels4=\"Transparent\" labels5=\"Extract\" labels6=\"Copy\" labels7=\"Shape\" labels8=\"Remove\" labels9=\"Background\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_alpha_item.action B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"28\" window_width=\"439\" window_height=\"182\" image_left=\"212\" image_top=\"35\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"text\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <String/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"font\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"geometry\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"gravity\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"foreground\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"227\" value1=\"189\" value2=\"189\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"undercol\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"antialias\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_annotate_item.action B3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_autoGamma_item.action B4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_autoLevel_item.action B5\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1290\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"17\" name=\"C\" caption=\"All the B operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C14\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_blurSharpMenu_item.Magick_adaptive_blur_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_blurSharpMenu_item.Magick_blur_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"radius\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Radius (0=auto)\" from=\"0\" to=\"100\" value=\"10\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sigma\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Sigma\" from=\"0.10000000000000001\" to=\"10\" value=\"2.98\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"virtpixback\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_blurSharpMenu_item.Magick_gaussianBlur_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"radius\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Radius (0=auto)\" from=\"0\" to=\"100\" value=\"10\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sigma\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Sigma\" from=\"0.10000000000000001\" to=\"10\" value=\"5.9500000000000002\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"angle\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"virtpixback\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_blurSharpMenu_item.Magick_motionBlur_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"virtpixback\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"angle\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"angle (degrees)\" from=\"-360\" to=\"360\" value=\"20\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_blurSharpMenu_item.Magick_rotationalBlur_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C15\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_blurSharpMenu_item.Magick_selectiveBlur_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C16\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_blurSharpMenu_item.Magick_adaptive_sharpen_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C10\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"radius\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Radius (0=auto)\" from=\"0\" to=\"100\" value=\"20\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sigma\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Sigma\" from=\"0.10000000000000001\" to=\"10\" value=\"1.99\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"virtpixback\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_blurSharpMenu_item.Magick_sharpen_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C11\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"radius\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Radius (0=auto)\" from=\"0\" to=\"100\" value=\"20\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sigma\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Sigma\" from=\"0.10000000000000001\" to=\"10\" value=\"1.99\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"gain\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Gain\" from=\"-10\" to=\"10\" value=\"3\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"threshold\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Threshold\" from=\"0\" to=\"1\" value=\"0.25\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"virtpixback\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_blurSharpMenu_item.Magick_unsharpen_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C12\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"compose\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Compose method\" labelsn=\"66\" labels0=\"Atop\" labels1=\"Blend\" labels2=\"Blur\" labels3=\"Bumpmap\" labels4=\"ChangeMask\" labels5=\"Clear\" labels6=\"ColorBurn\" labels7=\"ColorDodge\" labels8=\"Colorize\" labels9=\"CopyBlack\" labels10=\"CopyBlue\" labels11=\"CopyCyan\" labels12=\"CopyGreen\" labels13=\"Copy\" labels14=\"CopyMagenta\" labels15=\"CopyOpacity\" labels16=\"CopyRed\" labels17=\"CopyYellow\" labels18=\"Darken\" labels19=\"DarkenIntensity\" labels20=\"DivideDst\" labels21=\"DivideSrc\" labels22=\"Dst\" labels23=\"Difference\" labels24=\"Displace\" labels25=\"Dissolve\" labels26=\"Distort\" labels27=\"DstAtop\" labels28=\"DstIn\" labels29=\"DstOut\" labels30=\"DstOver\" labels31=\"Exclusion\" labels32=\"HardLight\" labels33=\"Hue\" labels34=\"In\" labels35=\"Lighten\" labels36=\"LightenIntensity\" labels37=\"LinearBurn\" labels38=\"LinearDodge\" labels39=\"LinearLight\" labels40=\"Luminize\" labels41=\"Mathematics\" labels42=\"MinusDst\" labels43=\"MinusSrc\" labels44=\"Modulate\" labels45=\"ModulusAdd\" labels46=\"ModulusSubtract\" labels47=\"Multiply\" labels48=\"None\" labels49=\"Out\" labels50=\"Overlay\" labels51=\"Over\" labels52=\"PegtopLight\" labels53=\"PinLight\" labels54=\"Plus\" labels55=\"Replace\" labels56=\"Saturate\" labels57=\"Screen\" labels58=\"SoftLight\" labels59=\"Src\" labels60=\"SrcAtop\" labels61=\"SrcIn\" labels62=\"SrcOut\" labels63=\"SrcOver\" labels64=\"VividLight\" labels65=\"Xor\" value=\"51\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"width\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Width\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bordercol\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"217\" value1=\"42\" value2=\"42\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_border_item.action C11\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C13\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bri\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"brightness\" from=\"-100\" to=\"100\" value=\"37.80160857908848\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"con\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"contrast\" from=\"-100\" to=\"100\" value=\"-60\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_brightCont_item.action C12\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2004\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"16\" name=\"D\" caption=\"All the C operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D13\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_charcoal_item.action D1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"352\" window_y=\"364\" window_width=\"626\" window_height=\"528\" image_left=\"38\" image_top=\"26\" image_mag=\"8\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"gravity\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Gravity\" labelsn=\"12\" labels0=\"None\" labels1=\"Center\" labels2=\"East\" labels3=\"Forget\" labels4=\"NorthEast\" labels5=\"North\" labels6=\"NorthWest\" labels7=\"SouthEast\" labels8=\"South\" labels9=\"SouthWest\" labels10=\"West\" labels11=\"Static\" value=\"3\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"geometry\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\">\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"x\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Expression caption=\"Width\"/>\n                        <Subcolumn vislevel=\"0\">\n                          <Row name=\"caption\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"expr\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText formula=\"10\"/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"super\">\n                            <Rhs vislevel=\"1\" flags=\"4\">\n                              <Subcolumn vislevel=\"0\"/>\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                        </Subcolumn>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"y\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Expression caption=\"Height\"/>\n                        <Subcolumn vislevel=\"0\">\n                          <Row name=\"caption\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"expr\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText formula=\"10\"/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"super\">\n                            <Rhs vislevel=\"1\" flags=\"4\">\n                              <Subcolumn vislevel=\"0\"/>\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                        </Subcolumn>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"hoffset\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Expression caption=\"Horizontal offset\"/>\n                        <Subcolumn vislevel=\"0\">\n                          <Row name=\"caption\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"expr\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText formula=\"12\"/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"super\">\n                            <Rhs vislevel=\"1\" flags=\"4\">\n                              <Subcolumn vislevel=\"0\"/>\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                        </Subcolumn>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"voffset\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Expression caption=\"Vertical offset\"/>\n                        <Subcolumn vislevel=\"0\">\n                          <Row name=\"caption\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"expr\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText formula=\"12\"/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"super\">\n                            <Rhs vislevel=\"1\" flags=\"4\">\n                              <Subcolumn vislevel=\"0\"/>\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                        </Subcolumn>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_chop_item.action D1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"foreground\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"223\" value1=\"35\" value2=\"224\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"val\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"value\" from=\"0\" to=\"100\" value=\"31.221719457013574\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_colorize_item.action D1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"28\" window_width=\"415\" window_height=\"182\" image_left=\"200\" image_top=\"35\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_colors_item.action D1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colsp\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Colorspace\" labelsn=\"34\" labels0=\"CIELab\" labels1=\"CMY\" labels2=\"CMYK\" labels3=\"Gray\" labels4=\"HCL\" labels5=\"HCLp\" labels6=\"HSB\" labels7=\"HSI\" labels8=\"HSL\" labels9=\"HSV\" labels10=\"HWB\" labels11=\"Lab\" labels12=\"LCH\" labels13=\"LCHab\" labels14=\"LCHuv\" labels15=\"LMS\" labels16=\"Log\" labels17=\"Luv\" labels18=\"OHTA\" labels19=\"Rec601Luma\" labels20=\"Rec601YCbCr\" labels21=\"Rec709Luma\" labels22=\"Rec709YCbCr\" labels23=\"RGB\" labels24=\"scRGB\" labels25=\"sRGB\" labels26=\"Transparent\" labels27=\"XYZ\" labels28=\"YCbCr\" labels29=\"YDbDr\" labels30=\"YCC\" labels31=\"YIQ\" labels32=\"YPbPr\" labels33=\"YUV\" value=\"11\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_colorspace_item.action D1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D14\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_colorspaceGray_item.action D1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D9\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"isReduce\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle caption=\"reduce contrast\" value=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_contrast_item.action D1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D15\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"intensity\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"blk\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"percent to make black\" from=\"0\" to=\"100\" value=\"10\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"wht\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"percent to make white\" from=\"0\" to=\"100\" value=\"10\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_contrastStretch_item.action D1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D11\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"gravity\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Gravity\" labelsn=\"12\" labels0=\"None\" labels1=\"Center\" labels2=\"East\" labels3=\"Forget\" labels4=\"NorthEast\" labels5=\"North\" labels6=\"NorthWest\" labels7=\"SouthEast\" labels8=\"South\" labels9=\"SouthWest\" labels10=\"West\" labels11=\"Static\" value=\"3\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"geometry\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_crop_item.action D9\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2710\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"E\" caption=\"All the D operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"E1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"threshold\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Threshold (percent)\" from=\"0\" to=\"100\" value=\"50\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_deskew_item.action E1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_despeckle_item.action E1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"virtpixback\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"distort\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Distort\" labelsn=\"16\" labels0=\"Affine\" labels1=\"AffineProjection\" labels2=\"ScaleRotateTranslate\" labels3=\"SRT\" labels4=\"Perspective\" labels5=\"PerspectiveProjection\" labels6=\"BilinearForward\" labels7=\"BilinearReverse\" labels8=\"Polynomial\" labels9=\"Arc\" labels10=\"Polar\" labels11=\"DePolar\" labels12=\"Barrel\" labels13=\"BarrelInverse\" labels14=\"Shepards\" labels15=\"Resize\" value=\"3\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"args\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <String/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"isPlus\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_distort_item.action E1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"28\" window_width=\"417\" window_height=\"182\" image_left=\"48\" image_top=\"8\" image_mag=\"4\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"foreground\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"182\" value1=\"76\" value2=\"149\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"args\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <String/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_draw_item.action E1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"3395\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"8\" name=\"F\" caption=\"All the E operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_edge_item.action F1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_emboss_item.action F1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_enhance_item.action F1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_equalize_item.action F1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_evaluate_item.action F1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"background\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"202\" value1=\"74\" value2=\"74\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"compose\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"gravity\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"geometry\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_extent_item.action F1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4128\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"14\" name=\"G\" caption=\"All the F operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_FlipFlopMenu_item.Magick_flip_item.action G1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_FlipFlopMenu_item.Magick_flop_item.action G1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_FlipFlopMenu_item.Magick_transpose_item.action G1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_FlipFlopMenu_item.Magick_transverse_item.action G1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"foreground\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"232\" value1=\"147\" value2=\"180\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fuzz\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Fuzz (percent)\" from=\"0\" to=\"100\" value=\"25\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"coordinate\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_floodfill_item.action G1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G11\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1\" window_y=\"56\" window_width=\"444\" window_height=\"231\" image_left=\"207\" image_top=\"60\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"border\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"compose\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"matte\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"geometry\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\">\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"x\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Expression caption=\"Width\"/>\n                        <Subcolumn vislevel=\"0\">\n                          <Row name=\"caption\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"expr\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText formula=\"32\"/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"super\">\n                            <Rhs vislevel=\"1\" flags=\"4\">\n                              <Subcolumn vislevel=\"0\"/>\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                        </Subcolumn>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"y\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Expression caption=\"Height\"/>\n                        <Subcolumn vislevel=\"0\">\n                          <Row name=\"caption\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"expr\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText formula=\"32\"/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"super\">\n                            <Rhs vislevel=\"1\" flags=\"4\">\n                              <Subcolumn vislevel=\"0\"/>\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                        </Subcolumn>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"outbev\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Expression caption=\"Outer bevel thickness\"/>\n                        <Subcolumn vislevel=\"0\">\n                          <Row name=\"caption\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"expr\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText formula=\"16\"/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"super\">\n                            <Rhs vislevel=\"1\" flags=\"4\">\n                              <Subcolumn vislevel=\"0\"/>\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                        </Subcolumn>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"inbev\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Expression caption=\"Inner bevel thickness\"/>\n                        <Subcolumn vislevel=\"0\">\n                          <Row name=\"caption\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"expr\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText formula=\"16\"/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"super\">\n                            <Rhs vislevel=\"1\" flags=\"4\">\n                              <Subcolumn vislevel=\"0\"/>\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                        </Subcolumn>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_frame_item.action G1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G12\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"function\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"values\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <String caption=\"values\" value=\"1.1,1.1,0,0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_function_item.action G1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G13\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_fx_item.action G1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4867\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"H\" caption=\"All the G operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_gamma_item.action H1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colourA\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"206\" value1=\"44\" value2=\"54\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colourB\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"28\" value1=\"233\" value2=\"66\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"position\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"colourA is at\" labelsn=\"8\" labels0=\"top\" labels1=\"bottom\" labels2=\"left\" labels3=\"right\" labels4=\"top-left\" labels5=\"top-right\" labels6=\"bottom-left\" labels7=\"bottom-right\" value=\"4\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_gradient_item.action H1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour_top_left\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"238\" value1=\"46\" value2=\"46\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour_top_right\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"231\" value1=\"220\" value2=\"45\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour_bottom_left\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"206\" value1=\"18\" value2=\"211\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour_bottom_right\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"46\" value1=\"159\" value2=\"222\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_gradientCorn_item.action H1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"5659\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"I\" caption=\"All the H operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_histogram_item.action I1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"6264\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"J\" caption=\"All the I operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"J1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"factor\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"factor\" from=\"0\" to=\"20\" value=\"1.1111111111111112\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"interpolate\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Interpolate\" labelsn=\"13\" labels0=\"default\" labels1=\"Average\" labels2=\"Average4\" labels3=\"Average9\" labels4=\"Average16\" labels5=\"Background\" labels6=\"Bilinear\" labels7=\"Blend\" labels8=\"Integer\" labels9=\"Mesh\" labels10=\"Nearest\" labels11=\"NearestNeighbor\" labels12=\"Spline\" value=\"12\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_implode_item.action J1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"6819\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"K\" caption=\"All the L operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"K1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_level_item.action K1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"blk\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"percent to make black\" from=\"0\" to=\"100\" value=\"18.928571428571427\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"wht\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"percent to make white\" from=\"0\" to=\"100\" value=\"22.857142857142858\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_linearStretch_item.action K2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour_black\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"120\" value1=\"20\" value2=\"20\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour_white\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"145\" value1=\"224\" value2=\"149\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"isInv\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle caption=\"Invert effect\" value=\"false\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_levelCols_item.action K4\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"7511\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"L\" caption=\"All the M - N operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"L1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"modcolsp\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bright\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"brightness\" from=\"0\" to=\"200\" value=\"120\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sat\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"hue\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_modulate_item.action L1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_monochrome_item.action L3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"method\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"iter\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Iterations (-1=repeat until done)\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"kernel\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Kernel\" labelsn=\"36\" labels0=\"Unity\" labels1=\"Gaussian\" labels2=\"DoG\" labels3=\"LoG\" labels4=\"Blur\" labels5=\"Comet\" labels6=\"Binomial\" labels7=\"Laplacian\" labels8=\"Sobel\" labels9=\"FreiChen\" labels10=\"Roberts\" labels11=\"Prewitt\" labels12=\"Compass\" labels13=\"Kirsch\" labels14=\"Diamond\" labels15=\"Square\" labels16=\"Rectangle\" labels17=\"Disk\" labels18=\"Octagon\" labels19=\"Plus\" labels20=\"Cross\" labels21=\"Ring\" labels22=\"Peaks\" labels23=\"Edges\" labels24=\"Corners\" labels25=\"Diagonals\" labels26=\"LineEnds\" labels27=\"LineJunctions\" labels28=\"Ridges\" labels29=\"ConvexHull\" labels30=\"ThinSe\" labels31=\"Skeleton\" labels32=\"Chebyshev\" labels33=\"Manhattan\" labels34=\"Octagonal\" labels35=\"Euclidean\" value=\"18\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"kernel_arg\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <String/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_morphology_item.action L4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_negate_item.action L1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"attenuate\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"attenuate\" from=\"0\" to=\"1\" value=\"0.88502673796791442\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"noise\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Noise\" labelsn=\"7\" labels0=\"Gaussian\" labels1=\"Impulse\" labels2=\"Laplacian\" labels3=\"Multiplicative\" labels4=\"Poisson\" labels5=\"Random\" labels6=\"Uniform\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_addNoise_item.action L1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_normalize_item.action L7\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"8212\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"M\" caption=\"All the O - R operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"M1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fill\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"195\" value1=\"205\" value2=\"43\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"changeColour\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\">\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"colour\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Colour colour_space=\"sRGB\" value0=\"55\" value1=\"64\" value2=\"213\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"fuzz\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Slider caption=\"Fuzz (percent)\" from=\"0\" to=\"100\" value=\"30.980392156862745\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"nonMatch\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Toggle caption=\"change non-matching colours\" value=\"false\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_opaque_item.action M1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_paint_item.action M1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_posterize_item.action M1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"28\" window_width=\"430\" window_height=\"182\" image_left=\"200\" image_top=\"35\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_raise_item.action M1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"filter\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Filter\" labelsn=\"31\" labels0=\"default\" labels1=\"Bartlett\" labels2=\"Blackman\" labels3=\"Bohman\" labels4=\"Box\" labels5=\"Catrom\" labels6=\"Cosine\" labels7=\"Cubic\" labels8=\"Gaussian\" labels9=\"Hamming\" labels10=\"Hann\" labels11=\"Hermite\" labels12=\"Jinc\" labels13=\"Kaiser\" labels14=\"Lagrange\" labels15=\"Lanczos\" labels16=\"Lanczos2\" labels17=\"Lanczos2Sharp\" labels18=\"LanczosRadius\" labels19=\"LanczosSharp\" labels20=\"Mitchell\" labels21=\"Parzen\" labels22=\"Point\" labels23=\"Quadratic\" labels24=\"Robidoux\" labels25=\"RobidouxSharp\" labels26=\"Sinc\" labels27=\"SincFast\" labels28=\"Spline\" labels29=\"Triangle\" labels30=\"Welch\" value=\"24\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Resize type\" labelsn=\"4\" labels0=\"resize\" labels1=\"scale\" labels2=\"sample\" labels3=\"adaptive-resize\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"width\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Width\" from=\"1\" to=\"100\" value=\"29.799999999999997\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"height\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"isPc\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle caption=\"Width and height are percent\" value=\"false\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_resize_item.action M6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_roll_item.action M7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M9\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"angle\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"angle (degrees)\" from=\"-360\" to=\"360\" value=\"-31.086350974930383\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"virtpixback\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_rotate_item.action M8\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"8949\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"16\" name=\"N\" caption=\"All the S operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_sepia_item.action N1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_shade_item.action N2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"28\" window_width=\"445\" window_height=\"182\" image_left=\"207\" image_top=\"100\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shadowCol\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"162\" value1=\"27\" value2=\"27\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"opacity\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Opacity (percent)\" from=\"0\" to=\"100\" value=\"40.35608308605341\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sigma\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"offsx\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"offsy\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"arePc\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_shadow_item.action N3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_shave_item.action N6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shearX\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"shear X (degrees)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"20\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shearY\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"shear Y (degrees)\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"background\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_shear_item.action N7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N9\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"contrast\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"contrast\" from=\"0\" to=\"30\" value=\"3\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"midpoint\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"mid-point (percent)\" from=\"0\" to=\"100\" value=\"86.36363636363636\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"isInv\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_sigmoid_item.action N8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N10\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_sketch_item.action N9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N11\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"channels\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"threshold\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Threshold (percent)\" from=\"0\" to=\"100\" value=\"61.094224924012153\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_solarize_item.action N1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N12\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"background\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"gravity\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Gravity\" labelsn=\"12\" labels0=\"None\" labels1=\"Center\" labels2=\"East\" labels3=\"Forget\" labels4=\"NorthEast\" labels5=\"North\" labels6=\"NorthWest\" labels7=\"SouthEast\" labels8=\"South\" labels9=\"SouthWest\" labels10=\"West\" labels11=\"Static\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"geometry\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_splice_item.action N11\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N13\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_spread_item.action N12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N14\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_statistic_item.action N13\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N15\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"angle\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Angle (degrees)\" from=\"-360\" to=\"360\" value=\"72\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_swirl_item.action N14\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"9682\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"O\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion window_x=\"0\" window_y=\"28\" window_width=\"365\" window_height=\"182\" image_left=\"167\" image_top=\"35\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_thresholdMenu_item.Magick_threshold_item.action O1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_thresholdMenu_item.Magick_blackThreshold_item.action O1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_thresholdMenu_item.Magick_whiteThreshold_item.action O1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_thresholdMenu_item.Magick_latThreshold_item.action O1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_thresholdMenu_item.Magick_randThreshold_item.action O1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_tile_item.action O1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"foreground\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Colour colour_space=\"sRGB\" value0=\"191\" value1=\"40\" value2=\"40\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"amount\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_tint_item.action O7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O9\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"changeColour\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\">\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"colour\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Colour/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"fuzz\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Slider caption=\"Fuzz (percent)\" from=\"0\" to=\"100\" value=\"13.461538461538462\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"nonMatch\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Toggle caption=\"change non-matching colours\" value=\"false\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_transparent_item.action O8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O10\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fuzz\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Fuzz (percent)\" from=\"0\" to=\"100\" value=\"10\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_trim_item.action O9\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"10328\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"5\" name=\"P\" caption=\"All the U - Z operations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"P1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"P2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_uniqueCols_item.action P1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"P3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Magick_vignette_item.action P1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"P4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"28\" window_width=\"431\" window_height=\"182\" image_left=\"200\" image_top=\"35\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"amplitude\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Amplitude (pixels)\" from=\"0\" to=\"100\" value=\"14.85148514851485\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"wavelength\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Wavelength (pixels)\" from=\"0\" to=\"100\" value=\"67.821782178217831\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"command\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Magick_wave_item.action P1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "test/extras/test_recomp_order.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace window_x=\"3\" window_y=\"84\" window_width=\"838\" window_height=\"871\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" locked=\"false\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"test\" caption=\"Default empty workspace\" filename=\"$HOME/GIT/nip2/test/extras/test.ws\" major=\"7\" minor=\"9\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"21\" name=\"D\" caption=\"untitled\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D10\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;this test has an adjust_scale_offset whose scale slider has a value&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;overwritten with the image mean&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D12\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;nip2 has to work to get the recomp order right, and has to be careful&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D13\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;that computation errors discovered during backtracking are overwritten&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D14\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;correctly when the true value is known&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D15\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;try duping the column or removing D6&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"220\" window_y=\"175\" window_width=\"1133\" window_height=\"876\" image_left=\"6\" image_top=\"5\" image_mag=\"80\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/test/extras/test-5x5.v&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Mean D3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1085\" window_height=\"957\" image_left=\"2\" image_top=\"2\" image_mag=\"184\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"scale\">\n                <Rhs vislevel=\"4\" flags=\"7\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"2\">\n                    <Row name=\"from\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"to\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"value\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"D6\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                        <Real/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"offset\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"image\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"value\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Adjust_scale_offset D3\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n"
  },
  {
    "path": "test/extras/test_transform.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace filename=\"test_transform.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" window_width=\"1279\" window_height=\"705\" lpane_position=\"0\" lpane_open=\"false\" rpane_position=\"1914\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"test_transform\" caption=\"Default empty workspace\">\n    <Column x=\"476\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"19\" name=\"FB\" caption=\"Image / Transform\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"FB1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"5\" window_y=\"54\" window_width=\"512\" window_height=\"729\" image_left=\"476\" image_top=\"596\" image_mag=\"-2\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB11\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"5\" window_y=\"54\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"355\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"dir\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Select distort direction\" labelsn=\"2\" labels0=\"Distort to points\" labels1=\"Distort to corners\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap1\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow>\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap2\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"480\" top=\"152\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap3\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"474\" top=\"504\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap4\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"20\" top=\"654\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Image_perspective_item.action FB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB13\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_transform_item.Image_rubber_item.Find_item.action FB11 FB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB14\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_transform_item.Image_rubber_item.Apply_item.action FB11 FB13\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB16\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_transform_item.Image_perspective_match_item.action FB11 FB1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1179\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"33\" name=\"BC\" caption=\"Tasks / Capture\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"BC21\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC22\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"625\" window_height=\"750\" image_left=\"296\" image_top=\"432\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"angle\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Angle\" from=\"-180\" to=\"180\" value=\"-3.8297872340425556\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_capture_item.Rotate_item.Free_item.action BC21\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC30\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region BC22 0 0 496 688\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC31\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"reference\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sample\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Matrix/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"order\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"interp\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"wrap\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"max_err\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Maximum error\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"max_iter\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Maximum iterations\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"100\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"transformed_image\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage window_x=\"5\" window_y=\"54\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"final_error\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_capture_item.Rubber_item.Find_item.action BC21 BC30\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC32\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"interp\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"wrap\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle caption=\"Wrap image edges\" value=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_capture_item.Rubber_item.Apply_item.action BC30 BC31\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1803\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"GC\" caption=\"untitled\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"GC5\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;$VIPSHOME/share/nip2/data/examples/framing/&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GC1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file (GC5 ++ &quot;framing_picture.jpg&quot;)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GC2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file (GC5 ++ &quot;framing_complex.png&quot;)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GC3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file (GC5 ++ &quot;framing_corner.png&quot;)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GC4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"2172\" window_y=\"197\" window_width=\"664\" window_height=\"802\" image_left=\"39\" image_top=\"446\" image_mag=\"8\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file (GC5 ++ &quot;framing_distorted_frame.png&quot;)\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1803\" y=\"411\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"HC\" caption=\"Straighten Frame\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"HC1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1710\" window_y=\"115\" window_width=\"710\" window_height=\"794\" image_left=\"347\" image_top=\"358\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"dir\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap1\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"23\" top=\"43\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap2\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"369\" top=\"8\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap3\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"388\" top=\"468\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap4\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"9\" top=\"485\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_frame_item.Straighten_frame_item.action GC4\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2323\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"IC\" caption=\"Painting with Simple Frame\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"IC1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1708\" window_y=\"57\" window_width=\"521\" window_height=\"430\" image_left=\"252\" image_top=\"176\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ppcm\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Number of pixels per cm\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"5\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"overlap\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Size of frame overlap in cm\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"variables\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"mount_options\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"frame\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_frame_item.Build_frame_item.Simple_frame_item.action HC1 GC1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2323\" y=\"387\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"JC\" caption=\"Painting with Complex Frame, with adjusted variables\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"JC1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1673\" window_y=\"48\" window_width=\"548\" window_height=\"445\" image_left=\"266\" image_top=\"183\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ppcm\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Number of pixels per cm\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"5\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"overlap\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Size of frame overlap in cm\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"variables\">\n                <Rhs vislevel=\"2\" flags=\"6\">\n                  <Subcolumn vislevel=\"1\">\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"scale_factor\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Expression caption=\"scale the size of the frame by\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"corner_section\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Slider caption=\"Corner section\" from=\"0.10000000000000001\" to=\"1\" value=\"0.5\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"edge_section\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Slider/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"middle_section\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Slider/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"blend_fraction\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Slider caption=\"Blend fraction\" from=\"0.10000000000000001\" to=\"0.90000000000000002\" value=\"0.10000000000000001\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"option\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Toggle/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"mount_options\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"frame\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_frame_item.Build_frame_item.Complex_frame_item.action GC2 GC1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"3002\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"KC\" caption=\"Painting with frame corner, and coloured mount\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"KC1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1669\" window_y=\"53\" window_width=\"640\" window_height=\"566\" image_left=\"312\" image_top=\"244\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ppcm\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Number of pixels per cm\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"5\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"overlap\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Size of frame overlap in cm\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"-10\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"variables\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"mount_options\">\n                <Rhs vislevel=\"2\" flags=\"6\">\n                  <Subcolumn vislevel=\"1\">\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"apply\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Toggle caption=\"Apply mount options\" value=\"false\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"ls\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Expression caption=\"Lower mount section bigger by (cm)\"/>\n                        <Subcolumn vislevel=\"0\">\n                          <Row name=\"caption\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"expr\">\n                            <Rhs vislevel=\"0\" flags=\"4\">\n                              <iText formula=\"5\"/>\n                            </Rhs>\n                          </Row>\n                          <Row name=\"super\">\n                            <Rhs vislevel=\"1\" flags=\"4\">\n                              <Subcolumn vislevel=\"0\"/>\n                              <iText/>\n                            </Rhs>\n                          </Row>\n                        </Subcolumn>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"mount_colour\">\n                      <Rhs vislevel=\"3\" flags=\"7\">\n                        <Colour colour_space=\"sRGB\" value0=\"0\" value1=\"0\" value2=\"0\"/>\n                        <Subcolumn vislevel=\"1\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"frame\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_frame_item.Build_frame_item.Frame_corner_item.action GC3 GC1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"2\" name=\"A\" caption=\"\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$VIPSHOME/share/nip2/data/examples/businesscard/slanted_oval_vase2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "test/test_all.sh.in",
    "content": "#!/bin/sh\n\n# set -x\n\nmain_result=0\n\ntest_result() {\n\tif [ $1 = 0 ]; then\n\t\techo ok\n\telse\n\t\techo failed\n\t\tmain_result=1\n\tfi\n}\n\ntest_result_fail() {\n\tif [ $1 = 0 ]; then\n\t\techo error: did not fail\n\t\tmain_result=1\n\telse\n\t\techo fail expected\n\tfi\n}\n\n# run the test workspaces\ntest_workspaces() {\n\tfor i in @TOP_SRCDIR@/test/workspaces/*.ws; do\n\t\tbase=$(basename $i)\n\t\techo -n \"testing $base ... \"\n\t\t@TOP_SRCDIR@/src/nip2 --prefix=@TOP_SRCDIR@ --test \"$i\"\n\t\tresult=$?\n\n\t\t# test_fail.ws is supposed to fail\n\t\tif [ x\"$base\" = x\"test_fail.ws\" ]; then\n\t\t\ttest_result_fail $result\n\t\telse\n\t\t\ttest_result $result\n\t\tfi\n\tdone\n}\n\n# run the test defs\ntest_defs() {\n\tfor i in @TOP_SRCDIR@/test/workspaces/*.def; do\n\t\tbase=$(basename $i)\n\t\techo -n \"testing $base ... \"\n\t\t@TOP_SRCDIR@/src/nip2 --prefix=@TOP_SRCDIR@ --test $i\n\t\ttest_result $?\n\tdone\n}\n\n# load all the example workspaces too\ntest_examples() {\n\tfor i in @TOP_SRCDIR@/share/nip2/data/examples/*/*.ws; do\n\t\tbase=$(basename $i)\n\n\t\t# have to skip these two, they use a non-free plugin\n\t\tif test x\"$base\" = x\"framing.ws\" ; then\n\t\t\tcontinue\n\t\tfi\n\t\tif test x\"$base\" = x\"registering.ws\" ; then\n\t\t\tcontinue\n\t\tfi\n\n\t\techo -n \"testing $base ... \"\n\t\t@TOP_SRCDIR@/src/nip2 --prefix=@TOP_SRCDIR@ --test $i \n\t\ttest_result $?\n\tdone\n}\n\ntest_workspaces\ntest_defs\ntest_examples\n\necho \"repeating tests with the vectorising system disabled\"\n\nexport IM_NOVECTOR=1\ntest_workspaces\ntest_defs\ntest_examples\n\nexit $main_result\n"
  },
  {
    "path": "test/workspaces/big_and_small_disks.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"770\" filename=\"$HOME/GIT/nip2/test/workspaces/big_and_small_disks.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"359\" lpane_open=\"false\" rpane_position=\"1274\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;summit in mask = class Image value {&#10;&#9;value = im_compass in mask;&#10;}&#10;&#10;main = WWWW7;\" name=\"big_and_small_disks\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"9\" name=\"J\" caption=\"input image\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"J3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1674\" window_height=\"999\" image_left=\"1807\" image_top=\"543\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$HOME/GIT/nip2/test/workspaces/gold_sample.v&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J6\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.Float_item.action J3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"dest\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"to\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Convert to\" labelsn=\"11\" labels0=\"Mono\" labels1=\"sRGB\" labels2=\"RGB16\" labels3=\"GREY16\" labels4=\"Lab\" labels5=\"LabQ\" labels6=\"LabS\" labels7=\"LCh\" labels8=\"XYZ\" labels9=\"Yxy\" labels10=\"UCS\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_convert_item.sRGB_item.action J3\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"655\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"H\" caption=\"(SMALL) THRESHOLD for &quot;darker in all but n directions&quot; (useable range: 0.-255.)\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"H2\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"15\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"1024\" image_left=\"1398\" image_top=\"944\" image_mag=\"-2\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"if H10 then T57 else J3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Toggle between initial image and threshold result in H11\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"caption\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText formula=\"&quot;Toggle between initial image and threshold result in H11&quot;\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Widget_toggle_item.action\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"6106\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"60\" name=\"T\" caption=\"(SMALL) disk average minus ranked average over each ring octant\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"T1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"O18\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"T4\">\n          <Rhs vislevel=\"4\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"25\" window_width=\"1280\" window_height=\"727\" image_left=\"1336\" image_top=\"604\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"2\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"select\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText formula=\"P1\"/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_rank_item.Image_rank_item.action T1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"T35\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Q21\"/>\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"T39\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"528\" window_y=\"25\" window_width=\"750\" window_height=\"722\" image_left=\"2218\" image_top=\"2185\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(T4-T35)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"T45\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"1024\" image_left=\"2011\" image_top=\"1392\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"T39 &gt; H2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"T59\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"T45 &amp; ~AAA5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"T56\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"1024\" image_left=\"2011\" image_top=\"472\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Dilate_item.Dilate4_item.action T59\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"T57\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Dilate_item.Dilate8_item.action T56\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4929\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"24\" name=\"N\" caption=\"(SMALL) ring octants convolution matrices\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action KB25\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"sum N1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N3\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(int) ( (65535/N2) * N1 )\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N17\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"sum N3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N15\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_con N17 0 N3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N4\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iText formula=\"take 8 (iterate rot45 N15)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N20\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action KB26\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N21\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(int) ( (65535/N2) * N20 )\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N22\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_con N17 0 N21.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N23\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"take 8 (iterate rot45 N22)\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"5493\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"19\" name=\"O\" caption=\"(SMALL) ring convolutions\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"25\" window_width=\"750\" window_height=\"722\" image_left=\"350\" image_top=\"307\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"J6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O9\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"N4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"map (converse conv O1) O9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O15\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"N23\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O16\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"map (converse conv O1) O15\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O17\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[ O11, O16 ]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O18\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Concat_item.action O17\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"3647\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"D\" caption=\"(SMALL) octant mask\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D14\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"OB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D1\">\n          <Rhs vislevel=\"3\" flags=\"4\">\n            <iText formula=\"2*D14-1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"D1\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"D1\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Xy_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"173\" window_y=\"308\" window_width=\"665\" window_height=\"627\" image_left=\"78\" image_top=\"62\" image_mag=\"4\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"9.7957272581564077\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"D2 - (D1 + 1) / 2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"1024\" image_left=\"19\" image_top=\"15\" image_mag=\"32\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"width\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText formula=\"D1\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"height\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText formula=\"D1\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"bands\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"format\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bits\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"coding\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"xres\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"yres\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"xoffset\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"yoffset\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"filename\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"rect\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"D3?0 - D3?1 &gt; 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"1024\" image_left=\"19\" image_top=\"15\" image_mag=\"32\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"width\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText formula=\"D1\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"height\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText formula=\"D1\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"bands\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"format\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bits\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"coding\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"xres\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"yres\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"xoffset\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"yoffset\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"filename\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"rect\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"D3?0 &lt; 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"1024\" image_left=\"38\" image_top=\"27\" image_mag=\"16\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"D4 &amp; D5\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"6771\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"R\" caption=\"(SMALL) centroids (computed with an indexed histogram)\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"R2\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_select_item.Segment_item.action ~R2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R4\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.U16_item.action R1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"23\" window_width=\"750\" window_height=\"750\" image_left=\"347\" image_top=\"335\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"R2.width\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"R2.height\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Xy_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R5\">\n          <Rhs vislevel=\"4\" flags=\"7\">\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n            <Subcolumn vislevel=\"2\"/>\n            <iText formula=\"Hist_find_item.Indexed_item.action R4 R3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Hist_find_item.Oned_item.action R4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Plot window_x=\"1412\" window_y=\"667\" window_width=\"500\" window_height=\"500\" plot_left=\"231\" plot_top=\"200\" plot_mag=\"100\" show_status=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"R5/R6 + .5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R8\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action R7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;the first two columns are 'unset' and background, delete them&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R10\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Matrix/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"first\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Delete from column\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"number\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Delete this many columns\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Matrix_delete_item.Columns_item.action R8\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"7261\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"29\" name=\"G\" caption=\"(SMALL) draw red crosses at centroid locations\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"R10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G2\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"J3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot; &quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;draw this on the image:&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"1\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"1\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nbands\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image bands\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"1\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"format_option\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type_option\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"pixel\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixel value\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"255\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_new_item.Image_black_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G17\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"G2.width\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"G2.height\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nbands\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image bands\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"format_option\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type_option\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"pixel\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixel value\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_new_item.Image_black_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G9\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"map (converse subtract (G5.width / 2)) G1.value?0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G10\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"map (converse subtract (G5.height / 2)) G1.value?1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"im_insertset G17.value G5.value G9 G10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G12\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"142\" window_y=\"165\" window_width=\"750\" window_height=\"750\" image_left=\"1043\" image_top=\"310\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image G11\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G27\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"1\" window_width=\"437\" window_height=\"349\" image_left=\"203\" image_top=\"118\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Dilate_item.Dilate4_item.action G12\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"7743\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"I\" caption=\"(SMALL) plot 3x3 crosses on original image\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"CB5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"G27\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot; &quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"264\" window_y=\"1\" window_width=\"750\" window_height=\"714\" image_left=\"368\" image_top=\"300\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"if I2 then Vector [255,0,0]  else I1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"774\" y=\"66\" open=\"true\" selected=\"false\" sform=\"false\" next=\"7\" name=\"E\" caption=\"FINAL IMAGE RESULT with small nanoparticles tagged with a 3x3 red cross and big disks tagged with a green cross\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"E1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"25\" window_width=\"1278\" window_height=\"722\" image_left=\"622\" image_top=\"332\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"if E3 then I5 else J7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Toggle the visibility of detected nanoparticles on or off in E1\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"caption\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText formula=\"&quot;Toggle the visibility of detected nanoparticles on or off in E1&quot;\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"2\" flags=\"6\">\n                  <Subcolumn vislevel=\"1\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Widget_toggle_item.action\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1900\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"L\" caption=\"(SMALL) number of regions\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"L1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"R1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2637\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"B\" caption=\"(SMALL) &quot;dark enough&quot; test\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"750\" window_height=\"750\" image_left=\"1746\" image_top=\"335\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"r\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Radius\" from=\"1\" to=\"100\" value=\"3\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fac\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shape\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Mask shape\" labelsn=\"2\" labels0=\"Square\" labels1=\"Gaussian\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"prec\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Precision\" labelsn=\"2\" labels0=\"Int\" labels1=\"Float\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"layers\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_conv_item.Custom_blur_item.action J6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1674\" window_height=\"999\" image_left=\"1808\" image_top=\"1429\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1 &lt; F1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1615\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"C\" caption=\"(SMALL) darker in most directions combined with dark at the center\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"T57 &amp; B2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"if C2 then C1 else J3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Toggle between initial image and combined threshold results in C3\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"caption\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText formula=\"&quot;Toggle between initial image and combined threshold results in C3&quot;\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Widget_toggle_item.action\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1201\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"F\" caption=\"(SMALL) THRESHOLD for &quot;dark enough&quot; test (useable range: 0.-255.)\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"145\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"261\" window_y=\"74\" window_width=\"750\" window_height=\"750\" image_left=\"1746\" image_top=\"2015\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"if F2 then B2 else J3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Toggle between initial image and threshold result in F3\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"caption\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText formula=\"&quot;Toggle between initial image and threshold result in F3&quot;\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Widget_toggle_item.action\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"523\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"P\" caption=\"(SMALL) NUMBER of directions to ignore in the &quot;darker in all but n directions&quot; test (useable range: 0-15)\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"P2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;There are 16 possible ranked directions because we symmetrized the family of sharp octants&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"P1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"994\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"U\" caption=\"(BIG) THRESHOLD for &quot;darker in all but n directions&quot; (useable range: 0.-255.)\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"U1\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"25\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"U10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"1024\" image_left=\"612\" image_top=\"1400\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"if U9 then W7 else J3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"U9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Toggle between initial image and threshold result in U10\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"caption\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText formula=\"&quot;Toggle between initial image and threshold result in U10&quot;\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Widget_toggle_item.action\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"11548\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"59\" name=\"W\" caption=\"(BIG) disk average minus the ranked wedge average\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"W1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Y3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"W2\">\n          <Rhs vislevel=\"4\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"1\" window_width=\"1680\" window_height=\"1050\" image_left=\"814\" image_top=\"450\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"2\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"select\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText formula=\"JB1\"/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_rank_item.Image_rank_item.action W1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"W3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"K12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"W4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"528\" window_y=\"25\" window_width=\"750\" window_height=\"722\" image_left=\"2218\" image_top=\"2185\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(W2-W3)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"W5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"1024\" image_left=\"2011\" image_top=\"1392\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"W4 &gt; U1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"W6\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"1024\" image_left=\"2011\" image_top=\"472\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Dilate_item.Dilate4_item.action W5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"W7\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Dilate_item.Dilate8_item.action W6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"10383\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"20\" name=\"X\" caption=\"(BIG) ring octants masks\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"X1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action SB10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"X2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"sum X1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"X3\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(int) ( (65535/X2) * X1 )\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"X4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"sum X3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"X5\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_con X4 0 X3.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"X6\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iText formula=\"take 8 (iterate rot45 X5)\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"10946\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"Y\" caption=\"(BIG) ring wedge averages\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"Y1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"750\" window_height=\"750\" image_left=\"349\" image_top=\"319\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"J6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"X6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"map (converse conv Y1) Y2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"9105\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"Z\" caption=\"(BIG) octant masks\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"Z13\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"QB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z14\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2*Z13-1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"Z14\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"Z14\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Xy_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"173\" window_y=\"308\" window_width=\"665\" window_height=\"627\" image_left=\"78\" image_top=\"62\" image_mag=\"4\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"9.7957272581564077\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Z2 - (Z14 + 1) / 2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"1024\" image_left=\"19\" image_top=\"15\" image_mag=\"32\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Z3?0 - Z3?1 &gt;= 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"1024\" image_left=\"19\" image_top=\"15\" image_mag=\"32\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"width\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText formula=\"Z14\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"height\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText formula=\"Z14\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"bands\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"format\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bits\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"coding\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"xres\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"yres\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"xoffset\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"yoffset\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"filename\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"rect\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Z3?0 &lt; 0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"1024\" image_left=\"38\" image_top=\"27\" image_mag=\"16\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Z4 &amp; Z5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Z3?0 == -1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Z3?0 == Z3?1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Z7 | Z8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z10\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"155\" window_y=\"63\" window_width=\"634\" window_height=\"651\" image_left=\"18\" image_top=\"16\" image_mag=\"16\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"128\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"if Z6 &amp; Z9 then 1 else if Z6 then 2 else 0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"12210\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"13\" name=\"AB\" caption=\"(BIG) region centroids (computed with indexed histogram)\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"AB1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"AAA3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"1\" window_width=\"750\" window_height=\"750\" image_left=\"175\" image_top=\"154\" image_mag=\"2\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"137.81365748984248\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_select_item.Segment_item.action ~AB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB3\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.U16_item.action AB2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"AB1.width\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"AB1.height\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Xy_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB5\">\n          <Rhs vislevel=\"4\" flags=\"7\">\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n            <Subcolumn vislevel=\"2\"/>\n            <iText formula=\"Hist_find_item.Indexed_item.action AB3 AB4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Hist_find_item.Oned_item.action AB3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Plot window_x=\"1412\" window_y=\"667\" window_width=\"500\" window_height=\"500\" plot_left=\"231\" plot_top=\"200\" plot_mag=\"100\" show_status=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"AB5/AB6 + .5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action AB7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB12\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;the first two columns are 'unset' and background, delete them&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB11\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Matrix/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"first\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Delete from column\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"number\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Delete this many columns\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Matrix_delete_item.Columns_item.action AB8\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"12849\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"29\" name=\"BB\" caption=\"(BIG) put 3x3 crosses centered at centroids\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"BB1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"AB11\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB2\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"J3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot; &quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;draw this on the image:&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"1\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"1\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nbands\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image bands\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"1\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"format_option\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type_option\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"pixel\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixel value\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"255\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_new_item.Image_black_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB6\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"BB2.width\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"BB2.height\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nbands\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image bands\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"format_option\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type_option\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"pixel\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixel value\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_new_item.Image_black_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB9\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"map (converse subtract (BB5.width / 2)) BB1.value?0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB10\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"map (converse subtract (BB5.height / 2)) BB1.value?1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"im_insertset BB6.value BB5.value BB9 BB10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB12\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"142\" window_y=\"165\" window_width=\"750\" window_height=\"750\" image_left=\"1043\" image_top=\"310\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image BB11\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB13\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"1\" window_width=\"437\" window_height=\"349\" image_left=\"203\" image_top=\"118\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Dilate_item.Dilate4_item.action BB12\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"13471\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"CB\" caption=\"(BIG) plot crosses on original\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"CB1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"J3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CB2\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"BB13\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CB3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot; &quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CB4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_convert_item.sRGB_item.action CB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CB5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"264\" window_y=\"1\" window_width=\"750\" window_height=\"714\" image_left=\"368\" image_top=\"300\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"if CB2 then Vector [0,255,0]  else CB4\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2395\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"EB\" caption=\"(BIG) number of regions\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"EB1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"1024\" image_left=\"1631\" image_top=\"472\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"AB2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"8120\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"GB\" caption=\"(BIG) &quot;dark enough&quot; test\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"GB1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"25\" window_width=\"750\" window_height=\"722\" image_left=\"1746\" image_top=\"324\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"r\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Radius\" from=\"1\" to=\"100\" value=\"12\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fac\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shape\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Mask shape\" labelsn=\"2\" labels0=\"Square\" labels1=\"Gaussian\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"prec\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Precision\" labelsn=\"2\" labels0=\"Int\" labels1=\"Float\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"layers\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_conv_item.Custom_blur_item.action J6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"GB1 &lt; IB1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2110\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"HB\" caption=\"(BIG) darker in most directions combined with dark at the center\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"HB1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"W7 &amp; GB2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"HB3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"if HB2 then HB1 else J3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"HB2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Toggle between initial image and combined threshold result in HB3\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"caption\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText formula=\"&quot;Toggle between initial image and combined threshold result in HB3&quot;\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Widget_toggle_item.action\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"1408\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"IB\" caption=\"(BIG) THRESHOLD for &quot;dark enough&quot; test (useable range: 0.-255.)\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"IB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"90\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IB3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"if IB2 then GB2 else J3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IB2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle caption=\"Toggle between intial image and threshold result in IB3\" value=\"true\"/>\n            <Subcolumn vislevel=\"0\">\n              <Row name=\"caption\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText formula=\"&quot;Toggle between intial image and threshold result in IB3&quot;\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Widget_toggle_item.action\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"862\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"JB\" caption=\"(BIG) NUMBER of directions to ignore in the &quot;darker in all but n directions&quot; test (useable range: 0-7)\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"JB4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;There are 8 ranked directions because we symmetrized the octants themselves&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2137\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"7\" name=\"AAA\" caption=\"exclude small centroids too close to big centroids\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"AAA6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"HB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AAA1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1680\" window_height=\"1050\" image_left=\"812\" image_top=\"485\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Dilate_item.Dilate4_item.action HB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AAA2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Dilate_item.Dilate8_item.action AAA1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AAA3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Dilate_item.Dilate4_item.action AAA2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AAA4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Dilate_item.Dilate8_item.action AAA3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AAA5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Dilate_item.Dilate4_item.action AAA4\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"3041\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"22\" name=\"Q\" caption=\"(SMALL) disk mask\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"Q2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"LB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2*Q2-1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q20\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"J6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"25\" window_width=\"117\" window_height=\"136\" image_left=\"42\" image_top=\"39\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"Q4\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"Q4\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Xy_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q12\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1674\" window_height=\"999\" image_left=\"205\" image_top=\"117\" image_mag=\"4\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(Q5?0+1-Q2)**2+(Q5?1+1-Q2)**2 &lt; Q2**2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action Q12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q15\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"sum Q14\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q16\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(int) ((65535/Q15)*Q14)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q17\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"sum Q16\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q18\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_con Q17 0 Q16.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q19\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"take 1 (iterate rot45 Q18)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q21\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"conv Q19?0 Q20\"/>\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"750\" window_height=\"750\" image_left=\"347\" image_top=\"335\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2671\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"LB\" caption=\"(SMALL) RADIUS of the inner disk\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"LB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"3\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2770\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"MB\" caption=\"(SMALL) inner RADIUS of the outer ring\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"MB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2869\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"OB\" caption=\"(SMALL) outer RADIUS of the outer ring\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"OB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"8\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4071\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"DB\" caption=\"(SMALL) outer radius of ring\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"DB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"OB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DB2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2*DB1-1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DB3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"J6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DB4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"DB2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"DB2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Xy_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DB7\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1674\" window_height=\"999\" image_left=\"205\" image_top=\"117\" image_mag=\"4\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(DB4?0+1-DB1)**2+(DB4?1+1-DB1)**2 &lt; DB1**2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4496\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"27\" name=\"KB\" caption=\"(SMALL) inner radius of ring\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"KB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"MB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2*KB1-1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB21\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"DB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB20\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"DB2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"J6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"KB20\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"KB20\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Xy_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB7\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1674\" window_height=\"999\" image_left=\"205\" image_top=\"117\" image_mag=\"4\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(KB4?0+1-KB21)**2+(KB4?1+1-KB21)**2 &lt; KB1**2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"DB7 &amp; ~KB7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB24\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"25\" window_width=\"364\" window_height=\"204\" image_left=\"166\" image_top=\"39\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"128\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"D6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB25\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"25\" window_width=\"388\" window_height=\"204\" image_left=\"178\" image_top=\"39\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"KB24*KB23\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_transform_item.Flip_item.Left_right_item.action KB25\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"8534\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"13\" name=\"K\" caption=\"(BIG) disk mask\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"K1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"PB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2*K1-1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"J6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"25\" window_width=\"117\" window_height=\"136\" image_left=\"42\" image_top=\"39\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"K2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"K2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Xy_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1674\" window_height=\"999\" image_left=\"205\" image_top=\"117\" image_mag=\"4\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(K4?0+1-K1)**2+(K4?1+1-K1)**2 &lt; K1**2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K6\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action K5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K7\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"sum K6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K8\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(int) ((65535/K7)*K6)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K9\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"sum K8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K10\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_con K9 0 K8.value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"take 1 (iterate rot45 K10)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K12\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"conv K11?0 K3\"/>\n            <iImage window_x=\"0\" window_y=\"25\" window_width=\"750\" window_height=\"722\" image_left=\"2022\" image_top=\"1367\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"3067\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"NB\" caption=\"(BIG) inner RADIUS of the outer ring\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"NB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"12\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2968\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"PB\" caption=\"(BIG) RADIUS of the inner disk\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"PB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"12\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"3166\" open=\"true\" selected=\"false\" sform=\"false\" next=\"2\" name=\"QB\" caption=\"(BIG) outer RADIUS of the outer ring\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"QB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"15\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"9528\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"RB\" caption=\"(BIG) outer radius of ring\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"RB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"QB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2*RB1-1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"J6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"RB2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"RB2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Xy_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1674\" window_height=\"999\" image_left=\"205\" image_top=\"117\" image_mag=\"4\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(RB4?0+1-RB1)**2+(RB4?1+1-RB1)**2 &lt; RB1**2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"9952\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"13\" name=\"SB\" caption=\"(BIG) inner radius of ring\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"SB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"NB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"SB2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"2*SB1-1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"SB3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"RB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"SB4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"RB2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"SB5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"J6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"SB6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"SB4\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"SB4\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Xy_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"SB7\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1674\" window_height=\"999\" image_left=\"205\" image_top=\"117\" image_mag=\"4\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(SB6?0+1-SB3)**2+(SB6?1+1-SB3)**2 &lt; SB1**2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"SB8\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"RB5 &amp; ~SB7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"SB9\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"25\" window_width=\"364\" window_height=\"208\" image_left=\"165\" image_top=\"39\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"128\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Z10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"SB10\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"1278\" window_height=\"970\" image_left=\"9\" image_top=\"6\" image_mag=\"64\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"0.39938338503447723\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"SB9*SB8\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"457\" open=\"true\" selected=\"false\" sform=\"false\" next=\"1\" name=\"ZZZZ\" caption=\"THE MAIN ADJUSTABLE PARAMETERS ARE FOUND BELOW\">\n      <Subcolumn vislevel=\"3\"/>\n    </Column>\n    <Column x=\"774\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"1\" name=\"YYYY\" caption=\"THE MAIN RESULTS ARE FOUND BELOW\">\n      <Subcolumn vislevel=\"3\"/>\n    </Column>\n    <Column x=\"1621\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"1\" name=\"XXXX\" caption=\"THE MAIN COMPUTATION STEPS ARE FOUND TO THE RIGHT\">\n      <Subcolumn vislevel=\"3\"/>\n    </Column>\n    <Column x=\"774\" y=\"240\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"WWWW\" caption=\"NANOPARTICLE COORDINATES\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"WWWW2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;coordinates of large blobs&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WWWW1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"AB11\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WWWW4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;coordinates of small blobs&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WWWW3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"R10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WWWW5\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot; &quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WWWW6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;verify that the correct number of blobs were detected&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WWWW7\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if WWWW1.width != 10 then error &quot;wrong number of large blobs detected&quot; else &quot;large ok!&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WWWW9\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if WWWW3.width != 3 then error &quot;wrong number of small blobs detected&quot; else &quot;small ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"2605\" open=\"true\" selected=\"false\" sform=\"false\" next=\"1\" name=\"VVVV\" caption=\"THE FOLLOWING PARAMETERS ARE GEOMETRICAL IN NATURE. HANDLE WITH CARE.\">\n      <Subcolumn vislevel=\"3\"/>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "test/workspaces/test_colour.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"1280\" window_height=\"771\" filename=\"$HOME/GIT/nip2/test/workspaces/test_colour.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"test_colour\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"A\" caption=\"Colour / New\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Colour/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_new_item.Widget_colour_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Colour/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_new_item.LAB_colour.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if A1.value != A2.value then error &quot;fail&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A9\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Colour/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_to_colour_item.action A8\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"386\" y=\"366\" open=\"true\" selected=\"false\" sform=\"false\" next=\"22\" name=\"B\" caption=\"Colour / Colourspace\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"FC1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B19\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.Mono_item.action B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B18\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1059\" window_y=\"312\" window_width=\"574\" window_height=\"727\" image_left=\"271\" image_top=\"308\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.GREY16_item.action B19\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B9\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.sRGB_item.action B8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B20\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"1059\" window_y=\"312\" window_width=\"574\" window_height=\"727\" image_left=\"271\" image_top=\"308\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.RGB16_item.action B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.Lab_item.action B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.LabQ_item.action B2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.LabS_item.action B3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.LCh_item.action B4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.XYZ_item.action B5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"dest\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"to\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Convert to\" labelsn=\"11\" labels0=\"Mono\" labels1=\"sRGB\" labels2=\"RGB16\" labels3=\"GREY16\" labels4=\"Lab\" labels5=\"LabQ\" labels6=\"LabS\" labels7=\"LCh\" labels8=\"XYZ\" labels9=\"Yxy\" labels10=\"UCS\" value=\"9\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_convert_item.Yxy_item.action B6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.UCS_item.action B7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B15\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;test max difference &lt; 2&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B12\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_dE_item.CIEdE76_item.action B1 B9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B13\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_stats_item.Max_item.action B12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B14\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if B13 &gt; 2 then error &quot;fail&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B10\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.Mono_item.action B9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B16\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if B10.bands != 1 then error &quot;fail&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1042\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"C\" caption=\"Colour / Tag As\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C12\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_tag_item.Mono_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C9\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_tag_item.sRGB_item.action C8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C13\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_tag_item.RGB16_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C14\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_tag_item.GREY16_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_tag_item.Lab_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_tag_item.LabQ_item.action C2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_tag_item.LabS_item.action C3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_tag_item.LCh_item.action C4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_tag_item.XYZ_item.action C5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_tag_item.Yxy_item.action C6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_tag_item.UCS_item.action C7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C11\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"if min (C9 == C1) != 255 then error &quot;fail&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1526\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"7\" name=\"D\" caption=\"Colour / Colour Temperature / Move Whitepoint\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.Lab_item.action D1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_temperature_item.Whitepoint_item.action D6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"old_white\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Old whitepoint\" labelsn=\"10\" labels0=\"D93\" labels1=\"D75\" labels2=\"D65\" labels3=\"D55\" labels4=\"D50\" labels5=\"A\" labels6=\"B\" labels7=\"C\" labels8=\"E\" labels9=\"D3250\" value=\"4\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"new_white\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"New whitepoint\" labelsn=\"10\" labels0=\"D93\" labels1=\"D75\" labels2=\"D65\" labels3=\"D55\" labels4=\"D50\" labels5=\"A\" labels6=\"B\" labels7=\"C\" labels8=\"E\" labels9=\"D3250\" value=\"2\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_temperature_item.Whitepoint_item.action D2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"660\" window_y=\"145\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"300\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"255\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_dE_item.CIEdE76_item.action D3 D1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D5\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if max D4 &gt; 0.01 then error &quot;fail&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2003\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"13\" name=\"E\" caption=\"Colour / Colour Temperature\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"E1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.Lab_item.action E1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_temperature_item.D65_to_D50_item.XYZ_minimal_item.action E2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_temperature_item.D50_to_D65_item.XYZ_minimal_item.action E3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_temperature_item.D65_to_D50_item.Bradford_item.action E4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_temperature_item.D50_to_D65_item.Bradford_item.action E5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_temperature_item.Lab_to_D50XYZ_item.action E6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_temperature_item.D50XYZ_to_Lab_item.action E7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E12\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_dE_item.CIEdE76_item.action E8 E2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if max E12 &gt; 0.01 then error &quot;fail&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2486\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"9\" name=\"F\" caption=\"Colour / ICC\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"profile\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Pathname/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"intent\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Render intent\" labelsn=\"4\" labels0=\"Perceptual\" labels1=\"Relative\" labels2=\"Saturation\" labels3=\"Absolute\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"embedded\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_icc_item.Import_item.action F1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"profile\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Pathname caption=\"Output profile\" value=\"$VIPSHOME/share/nip2/data/sRGB.icm\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"intent\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Render intent\" labelsn=\"4\" labels0=\"Perceptual\" labels1=\"Relative\" labels2=\"Saturation\" labels3=\"Absolute\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"depth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_icc_item.Export_item.action F2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"in_profile\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Pathname/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"out_profile\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Pathname caption=\"Output profile\" value=\"$VIPSHOME/share/nip2/data/sRGB.icm\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"intent\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_icc_item.Transform_item.action F1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F5\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_dE_item.CIEdE76_item.action F3 F4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F8\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"max F5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if F8 &gt; 3 then error &quot;fail&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2960\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"G\" caption=\"Colour / Difference\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.Lab_item.action G1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G8\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"G2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_dE_item.CIEdE76_item.action G1 G2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"max G3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_dE_item.UCS_item.action G2 G1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G7\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"max G6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_dE_item.CIEdE00_item.action G2 G8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G10\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"max G9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if G4 &gt; 0.01 || G7 &gt; 0.01 || G10 &gt; 0.01 then error &quot;fail&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"3445\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"28\" name=\"I\" caption=\"Colour / Adjust\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"matrix\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Matrix valuen=\"9\" value0=\"1.1000000000000001\" value1=\"0\" value2=\"0\" value3=\"0\" value4=\"0.90000000000000002\" value5=\"0\" value6=\"0\" value7=\"0\" value8=\"1\" width=\"3\" height=\"3\" scale=\"1\" offset=\"0\" filename=\"\" display=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_adjust_item.Recombination_item.action I1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"gr\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"\" from=\"-20\" to=\"20\" value=\"4\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"by\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"\" from=\"-20\" to=\"20\" value=\"-4\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_adjust_item.Cast_item.action I1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"h\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"\" from=\"0\" to=\"360\" value=\"90\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"s\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_adjust_item.HSB_item.action I1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"10\" top=\"10\" width=\"10\" height=\"10\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region I1 47 23 53 50\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Colour/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_to_colour_item.action I6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Colour/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"I8 * Vector [1.1, 0.9, 1]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"10\" top=\"10\" width=\"10\" height=\"10\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region I2 20 18 22 19\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Colour/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_to_colour_item.action I10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I12\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Colour_dE_item.CIEdE76_item.action I11 I9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I13\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if I12 &gt; 0.0001 then error &quot;fail&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I14\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Colour/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.Lab_item.action I8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I15\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Colour/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"I14 + Vector [0, 4, -4]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I16\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"10\" top=\"10\" width=\"10\" height=\"10\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region I3 34 27 23 17\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I17\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Colour/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_to_colour_item.action I16\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I18\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Colour/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.Lab_item.action I17\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I19\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Colour_dE_item.CIEdE76_item.action I18 I15\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I20\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if I19 &gt; 0.7 then error &quot;fail&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"10\" top=\"10\" width=\"10\" height=\"10\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region I5 19 27 26 33\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I22\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Colour/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_to_colour_item.action I21\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I23\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Colour/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.LCh_item.action I14\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I24\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Colour/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"I23 + Vector [0, 0, 90]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I25\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Colour/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_convert_item.sRGB_item.action I24\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I26\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Colour_dE_item.CIEdE76_item.action I25 I22\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I27\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if I26 &gt; 0.5 then error &quot;fail&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4049\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"7\" name=\"J\" caption=\"Colour / Similar Colour\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"J1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"879\" window_height=\"729\" image_left=\"423\" image_top=\"327\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"10\" top=\"10\" width=\"10\" height=\"10\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region J1 21 33 22 16\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Colour/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_to_colour_item.action J3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"target_colour\">\n                <Rhs vislevel=\"3\" flags=\"7\">\n                  <Colour/>\n                  <Subcolumn vislevel=\"1\"/>\n                  <iText formula=\"J4\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"t\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"dE threshold\" from=\"0\" to=\"100\" value=\"32\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_similar_item.action J1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"10\" top=\"10\" width=\"10\" height=\"10\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region J2 28 23 28 33\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"J6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if min J5 == 0 then error &quot;fail&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4519\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"L\" caption=\"Colour / Colour Chart\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"L1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"565\" window_height=\"750\" image_left=\"266\" image_top=\"328\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$VIPSHOME/share/nip2/data/examples/print_test_image.v&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"0\" top=\"1\" width=\"549\" height=\"365\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region L1 18 17 531 349\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L3\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_chart_to_matrix_item.action L2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_matrix_to_chart_item.action L3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L7\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_chart_to_matrix_item.action L4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L8\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"L3 - L7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L9\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"max L8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L10\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if L9 &gt; 0.001 then error &quot;fail&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"L11\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_plot_ab_scatter_item.action L2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"386\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"19\" name=\"FC\" caption=\"Colour / Colourspace\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"FC1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$VIPSHOME/share/nip2/data/examples/businesscard/slanted_oval_vase2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FC16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Colour/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_to_colour_item.action FC1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FC17\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FC18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Colour/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Colour_to_colour_item.action FC17\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "test/workspaces/test_conv.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.7.1\">\n  <Workspace window_x=\"0\" window_y=\"28\" window_width=\"1920\" window_height=\"1172\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" locked=\"false\" lpane_position=\"100\" lpane_open=\"false\" rpane_position=\"400\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"test_conv\" caption=\"Default empty workspace\" filename=\"$HOME/GIT/nip2/test/workspaces/test_conv.ws\" major=\"8\" minor=\"7\">\n    <Column x=\"0\" y=\"279\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"A\" caption=\"medium test matrix\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Matrix/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"s\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ma\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"integer\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle caption=\"Integer\" value=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Matrix_build_item.Matrix_gaussian_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(int) (A1/10)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"sum A2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix valuen=\"25\" value0=\"0\" value1=\"0\" value2=\"1\" value3=\"0\" value4=\"0\" value5=\"0\" value6=\"3\" value7=\"6\" value8=\"3\" value9=\"0\" value10=\"1\" value11=\"6\" value12=\"10\" value13=\"6\" value14=\"1\" value15=\"0\" value16=\"3\" value17=\"6\" value18=\"3\" value19=\"0\" value20=\"0\" value21=\"0\" value22=\"1\" value23=\"0\" value24=\"0\" width=\"5\" height=\"5\" scale=\"50\" offset=\"0\" filename=\"\" display=\"3\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_con A3 0 A2.value\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"3\" name=\"B\" caption=\"test image\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"449\" window_y=\"50\" window_width=\"547\" window_height=\"727\" image_left=\"141\" image_top=\"107\" image_mag=\"8\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$VIPSHOME/share/nip2/data/examples/businesscard/slanted_oval_vase2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"689\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"C\" caption=\"convolve with vips\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"1\" window_width=\"510\" window_height=\"727\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"conv G5 B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"1\" window_width=\"510\" window_height=\"727\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"conv A4 B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"1\" window_width=\"510\" window_height=\"727\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"conv F4 B1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1018\" y=\"586\" open=\"true\" selected=\"false\" sform=\"false\" next=\"20\" name=\"D\" caption=\"convolve by hand\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D19\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region B1 137 102 D19.width D19.height\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"D1?1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action D2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Matrix (map2 (map2 multiply) D19.value D3.value)\"/>\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D5\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"sum D4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"(int) ((D5 + D19.scale / 2) / D19.scale + D19.offset)\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1570\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"21\" name=\"E\" caption=\"check result\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"E16\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"H2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E17\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"H7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E19\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E18\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot; &quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E8\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region E19 E16.left E16.top E16.width E16.height\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E9\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"E8?1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E10\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action E9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"(int) (E16.width / 2)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E12\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"(int) (E16.height / 2)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E13\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"E10.value?E11?E12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E14\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot; &quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E20\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;don't test for an exact match: the uint8 vector path may miss slightly&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E15\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if E13 != E17 then error &quot;match failed&quot; else &quot;ok&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"806\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"F\" caption=\"large test matrix\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Matrix/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"s\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Sigma\" from=\"0.001\" to=\"10\" value=\"2.7010267062314539\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ma\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"integer\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle caption=\"Integer\" value=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Matrix_build_item.Matrix_gaussian_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(int) (F1/10)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"sum F2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_con F3 0 F2.value\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"0\" y=\"122\" open=\"true\" selected=\"false\" sform=\"false\" next=\"7\" name=\"G\" caption=\"small test matrix\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"G6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;some -ve coeffs in this one&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix valuen=\"9\" value0=\"-1\" value1=\"-1\" value2=\"-1\" value3=\"-1\" value4=\"16\" value5=\"-1\" value6=\"-1\" value7=\"-1\" value8=\"-1\" width=\"3\" height=\"3\" scale=\"8\" offset=\"0\" filename=\"\" display=\"3\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_build_item.Convolution_item.action\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1018\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"8\" name=\"H\" caption=\"convolve by hand\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"G5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region B1 137 102 H1.width H1.height\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"H2?1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action H3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Matrix (map2 (map2 multiply) H1.value H4.value)\"/>\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"sum H5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H7\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"(int) ((H6 + H1.scale / 2) / H1.scale + H1.offset)\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1018\" y=\"1280\" open=\"true\" selected=\"false\" sform=\"false\" next=\"8\" name=\"I\" caption=\"convolve by hand\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"I1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"F4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region B1 137 102 I1.width I1.height\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"I2?1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action I3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Matrix (map2 (map2 multiply) I1.value I4.value)\"/>\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"sum I5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"I7\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"(int) ((I6 + I1.scale / 2) / I1.scale + I1.offset)\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1570\" y=\"541\" open=\"true\" selected=\"false\" sform=\"false\" next=\"13\" name=\"N\" caption=\"check result\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"D1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"D6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"C2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot; &quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N5\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region N3 N1.left N1.top N1.width N1.height\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N6\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"N5?1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N7\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action N6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N8\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"(int) (N1.width / 2)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N9\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"(int) (N1.height / 2)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N10\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"N7.value?N8?N9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot; &quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N12\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if abs (N10 - N2) &gt; 2 then error &quot;match failed&quot; else &quot;ok&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1570\" y=\"1260\" open=\"true\" selected=\"true\" sform=\"false\" next=\"14\" name=\"O\" caption=\"check result\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"I2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"I7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O3\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"C3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot; &quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O5\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region O3 O1.left O1.top O1.width O1.height\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O6\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"O5?1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O7\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action O6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O8\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"(int) (O1.width / 2)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O9\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"(int) (O1.height / 2)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O10\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"O7.value?O8?O9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot; &quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O13\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;allow it to differ slightly because of rounding in vector conv&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O12\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if abs (O10 - O2) &gt; 1 then error &quot;match failed&quot; else &quot;ok&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n"
  },
  {
    "path": "test/workspaces/test_fail.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace filename=\"/home/john/GIT/nip2/test/workspaces/test_fail.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" window_width=\"680\" window_height=\"500\" lpane_position=\"100\" lpane_open=\"false\" rpane_position=\"400\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"untitled\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"4\" name=\"A\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if A1 == A2 then error &quot;sane!&quot; else &quot;i'm mad&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "test/workspaces/test_filter.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace window_x=\"6\" window_y=\"56\" window_width=\"1022\" window_height=\"605\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" locked=\"false\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"test_filter\" caption=\"Default empty workspace\" filename=\"$HOME/GIT/nip2/test/workspaces/test_filter.ws\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"17\" name=\"B\" caption=\"Colour / Colourspace\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$VIPSHOME/share/nip2/data/examples/businesscard/slanted_oval_vase2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"682\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"18\" name=\"H\" caption=\"Filter / Convolution\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"H1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_conv_item.Blur_item.action H1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_conv_item.Sharpen_item.action H1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_conv_item.Emboss_item.action H1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H12\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_conv_item.Laplacian_item.action H1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_conv_item.Sobel_item.action H1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_conv_item.Linedet_item.action H1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H15\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"size\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Radius\" labelsn=\"6\" labels0=\"3 pixels\" labels1=\"5 pixels\" labels2=\"7 pixels\" labels3=\"9 pixels\" labels4=\"11 pixels\" labels5=\"51 pixels\" value=\"4\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"st\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bm\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"dm\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fs\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"js\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_conv_item.Usharp_item.action H1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H16\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"r\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Radius\" from=\"1\" to=\"100\" value=\"27\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shape\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Mask shape\" labelsn=\"2\" labels0=\"Square\" labels1=\"Gaussian\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fac\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"prec\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"layers\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_conv_item.Custom_blur_item.action H1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"H17\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_conv_item.Custom_conv_item.action H1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1190\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"K\" caption=\"Filter / Rank\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"K1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_rank_item.Median_item.action K1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Group/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Group [K1,K2]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_rank_item.Image_rank_item.action K3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"K5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_rank_item.Custom_rank_item.action K1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1950\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"M\" caption=\"Filter / Morphology\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"M1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_select_item.Threshold_item.action M1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Dilate_item.Dilate8_item.action M2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Dilate_item.Dilate4_item.action M2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Erode_item.Erode8_item.action M2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Erode_item.Erode4_item.action M2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_morphology_item.Custom_morph_item.action M2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Open_item.action M2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Close_item.action M2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Clean_item.action M2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"M11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_morphology_item.Thin_item.action M2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2417\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"N\" caption=\"Filter / Fourier / Ideal\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"N1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"187\" top=\"158\" width=\"256\" height=\"256\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region N1 74 139 264 242\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sense\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Sense\" labelsn=\"2\" labels0=\"Pass\" labels1=\"Reject\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"visualize_mask\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fc\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_fourier_item.New_ideal_item.High_low_item.action N2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_fourier_item.New_ideal_item.Ring_item.action N2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"N5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sense\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"r\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Radius\" from=\"0.01\" to=\"0.98999999999999999\" value=\"0.90000000000000002\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"visualize_mask\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fcx\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fcy\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_fourier_item.New_ideal_item.Band_item.action N2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2983\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"O\" caption=\"Filter / Fourier / Gaussian\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"113\" top=\"79\" width=\"256\" height=\"256\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region O1 74 139 264 242\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sense\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Sense\" labelsn=\"2\" labels0=\"Pass\" labels1=\"Reject\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"visualize_mask\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fc\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ac\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_fourier_item.New_gaussian_item.High_low_item.action O2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_fourier_item.New_gaussian_item.Ring_item.action O2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_fourier_item.New_gaussian_item.Band_item.action O2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"3547\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"P\" caption=\"Filter / Fourier / Butterworth\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"P1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"P2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"113\" top=\"79\" width=\"256\" height=\"256\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region P1 74 139 264 242\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"P6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sense\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Sense\" labelsn=\"2\" labels0=\"Pass\" labels1=\"Reject\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"visualize_mask\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fc\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ac\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"o\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_fourier_item.New_butterworth_item.High_low_item.action P2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"P7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_fourier_item.New_butterworth_item.Ring_item.action P2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"P8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_fourier_item.New_butterworth_item.Band_item.action P2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4109\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"7\" name=\"Q\" caption=\"Filter / Enhance\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"Q1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Q1?1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_enhance_item.Falsecolour_item.action Q2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_enhance_item.Statistical_diff_item.action Q1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_enhance_item.Hist_equal_item.Global_item.action Q1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Q6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_enhance_item.Hist_equal_item.Local_item.action Q1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4974\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"7\" name=\"R\" caption=\"Filter / Tilt Brightness\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"R1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"tilt\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Left-right tilt\" from=\"-1\" to=\"1\" value=\"-0.60000000000000009\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_tilt_item.Left_right_item.action R1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"tilt\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Top-bottom tilt\" from=\"-1\" to=\"1\" value=\"0.40000000000000002\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_tilt_item.Top_bottom_item.action R1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"tilt\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Left-right tilt\" from=\"-1\" to=\"1\" value=\"-0.60000000000000009\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shift\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Shift by\" from=\"-1\" to=\"1\" value=\"0.60000000000000009\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_tilt_item.Left_right_cos_item.action R1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"tilt\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Top-bottom tilt\" from=\"-1\" to=\"1\" value=\"-0.60000000000000009\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shift\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Shift by\" from=\"-1\" to=\"1\" value=\"0.60000000000000009\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_tilt_item.Top_bottom_cos_item.action R1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"R6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"tilt\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Tilt\" from=\"-1\" to=\"1\" value=\"0.60000000000000009\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"hshift\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Horizontal shift by\" from=\"-1\" to=\"1\" value=\"-0.40000000000000002\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"vshift\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_tilt_item.Circular_item.action R1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"5414\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"S\" caption=\"Filter / Blend\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"S1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"388\" window_y=\"128\" window_width=\"547\" window_height=\"727\" image_left=\"257\" image_top=\"308\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"S2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Q3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"S3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"p\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Blend position\" from=\"0\" to=\"1\" value=\"0.79999999999999993\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_blend_item.Scale_blend_item.action S1 S2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"S4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"S3?1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"S9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.U8_item.action S4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"S5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Colour colour_space=\"sRGB\" value0=\"13\" value1=\"240\" value2=\"65\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"default_colour\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"default_value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Colour/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"space\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Colour space\" labelsn=\"6\" labels0=\"sRGB\" labels1=\"Lab\" labels2=\"LCh\" labels3=\"XYZ\" labels4=\"Yxy\" labels5=\"UCS\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Colour value\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_new_item.Widget_colour_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"S6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Colour colour_space=\"sRGB\" value0=\"231\" value1=\"21\" value2=\"13\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"default_colour\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"default_value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Colour/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"space\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Colour space\" labelsn=\"6\" labels0=\"sRGB\" labels1=\"Lab\" labels2=\"LCh\" labels3=\"XYZ\" labels4=\"Yxy\" labels5=\"UCS\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Colour value\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_new_item.Widget_colour_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"S10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"370\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_blend_item.Image_blend_item.action S9 S5 S6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"S11\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"orientation\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"blend_position\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Blend position\" from=\"0\" to=\"1\" value=\"0.59999999999999998\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"blend_width\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Blend width\" from=\"0\" to=\"1\" value=\"0.34999999999999998\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_blend_item.Line_blend_item.action S1 S2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"S13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"113\" top=\"79\" width=\"256\" height=\"256\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region N1 74 139 264 242\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"S14\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"bg\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fg\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"method\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Blend mode\" labelsn=\"17\" labels0=\"Normal\" labels1=\"If Lighter\" labels2=\"If Darker\" labels3=\"Multiply\" labels4=\"Add\" labels5=\"Subtract\" labels6=\"Screen\" labels7=\"Burn\" labels8=\"Soft Light\" labels9=\"Hard Light\" labels10=\"Lighten\" labels11=\"Darken\" labels12=\"Dodge\" labels13=\"Reflect\" labels14=\"Freeze\" labels15=\"Bitwise OR\" labels16=\"Bitwise AND\" value=\"14\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"opacity\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Opacity\" from=\"0\" to=\"255\" value=\"86.470588235294116\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"hmove\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Horizontal move by\" from=\"-256\" to=\"256\" value=\"25.688581314878888\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"vmove\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Vertical move by\" from=\"-256\" to=\"256\" value=\"50.491349480968836\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_blend_item.Blend_alpha_item.action N2 S13\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"5978\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"T\" caption=\"Filter / Overlay\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"T1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"T2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"T1?0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"T3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"T1?1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"T4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Colour overlay as\" labelsn=\"6\" labels0=\"Green over Red\" labels1=\"Blue over Red\" labels2=\"Red over Green\" labels3=\"Red over Blue\" labels4=\"Blue over Green\" labels5=\"Green over Blue\" value=\"3\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_overlay_header_item.action T2 T3\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"6391\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"U\" caption=\"Filter / Colorize\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"U1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"U2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"U1?0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"U3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Colour colour_space=\"Lab\" value0=\"61.977499999999999\" value1=\"-8.8122199999999999\" value2=\"59.229700000000001\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Colour_new_item.Widget_colour_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"U4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_colourize_item.action U2 U3\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"6833\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"V\" caption=\"Filter / Browse\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"V1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"V2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"image\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"band\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Band\" from=\"0\" to=\"2\" value=\"1.3999999999999999\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"display\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Display as\" labelsn=\"7\" labels0=\"Grey\" labels1=\"Green over Red\" labels2=\"Blue over Red\" labels3=\"Red over Green\" labels4=\"Red over Blue\" labels5=\"Blue over Green\" labels6=\"Green over Blue\" value=\"3\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_browse_multiband_item.Bandwise_item.action V1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"V3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bit\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Bit\" from=\"0\" to=\"7\" value=\"4\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_browse_multiband_item.Bitwise_item.action V1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"7290\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"9\" name=\"W\" caption=\"Filter / Photographic\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"W1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"965\" window_y=\"75\" window_width=\"547\" window_height=\"727\" image_left=\"257\" image_top=\"308\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"W2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_negative_item.action W1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"W3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"kink\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Kink\" from=\"0\" to=\"1\" value=\"0.30000000000000004\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_solarize_item.action W1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"W4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"4\" window_y=\"53\" window_width=\"512\" window_height=\"729\" image_left=\"249\" image_top=\"345\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"r\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Radius\" from=\"0\" to=\"50\" value=\"32.869080779944291\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"highlights\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Highlights\" from=\"0\" to=\"100\" value=\"96.378830083565461\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"glow\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Glow\" from=\"0\" to=\"1\" value=\"0.91922005571030641\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour\">\n                <Rhs vislevel=\"3\" flags=\"7\">\n                  <Colour colour_space=\"sRGB\" value0=\"236\" value1=\"17\" value2=\"22\"/>\n                  <Subcolumn vislevel=\"1\">\n                    <Row name=\"default_colour\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"default_value\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <Colour/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"space\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Option caption=\"Colour space\" labelsn=\"6\" labels0=\"sRGB\" labels1=\"Lab\" labels2=\"LCh\" labels3=\"XYZ\" labels4=\"Yxy\" labels5=\"UCS\" value=\"0\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"colour\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Expression caption=\"Colour value\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_diffuse_glow_item.action W1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"W5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"4\" window_y=\"53\" window_width=\"570\" window_height=\"750\" image_left=\"269\" image_top=\"319\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_drop_shadow_item.action W1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"W6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"8\" window_y=\"76\" window_width=\"636\" window_height=\"729\" image_left=\"302\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"text\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <String/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"font\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Fontname/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"align\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"dpi\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"DPI\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"500\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Text colour\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"place\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n                    <iRegiongroup/>\n                  </iRegion>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_paint_text_item.action W1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4609\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"8\" name=\"A\" caption=\"Spatial Correlation\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"1082\" window_y=\"29\" window_width=\"547\" window_height=\"1161\" image_left=\"266\" image_top=\"525\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"1406\" window_y=\"463\" window_width=\"510\" window_height=\"727\" image_left=\"239\" image_top=\"299\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A1?1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region A4 165 82 70 57\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"477\" window_y=\"232\" window_width=\"510\" window_height=\"727\" image_left=\"239\" image_top=\"299\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"255.00000000000043\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_correlate_item.Correlate_item.action A4 A5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"867\" window_y=\"355\" window_width=\"510\" window_height=\"727\" image_left=\"239\" image_top=\"299\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"3.0430978191621576e-06\" offset=\"-0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Filter_correlate_item.Correlate_fast_item.action A4 A5\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "test/workspaces/test_fourier.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"1005\" window_height=\"688\" filename=\"test_fourier.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"test_fourier\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"19\" name=\"B\" caption=\"Test images\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$VIPSHOME/share/nip2/data/examples/businesscard/slanted_oval_vase2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"701\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"O\" caption=\"Filter / Fourier / Gaussian\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"O1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"113\" top=\"79\" width=\"256\" height=\"256\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region O1 74 139 264 242\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sense\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Sense\" labelsn=\"2\" labels0=\"Pass\" labels1=\"Reject\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"visualize_mask\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fc\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ac\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_fourier_item.New_gaussian_item.High_low_item.action O2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_fourier_item.New_gaussian_item.Ring_item.action O2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"O8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Filter_fourier_item.New_gaussian_item.Band_item.action O2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1283\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"QB\" caption=\"Math / Fourier\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"QB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"QB2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"210\" top=\"249\" width=\"128\" height=\"128\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region QB1 127 171 205 188\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"QB3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_fourier_item.Forward_item.action QB2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"QB4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_fourier_item.Reverse_item.action QB3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"QB5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_fourier_item.Rotate_quadrants_item.action QB4\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1763\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"7\" name=\"A\" caption=\"polar / rectangular\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"256\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"256\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Pattern_images_item.Xy_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"(A1?0, A1?1)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_complex_item.Polar_item.action A2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"657\" window_y=\"874\" window_width=\"451\" window_height=\"295\" image_left=\"210\" image_top=\"109\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_complex_item.Rectangular_item.action A3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A5\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"max (re (A4 - A2))\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if A5 &gt; 0.0001 then error &quot;argh&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "test/workspaces/test_histogram.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace filename=\"/home/john/SVN/vips/nip2/trunk/test/workspaces/test_histogram.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" window_width=\"1920\" window_height=\"1165\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"test_histogram\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"17\" name=\"B\" caption=\"Colour / Colourspace\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$VIPSHOME/share/nip2/data/examples/businesscard/slanted_oval_vase2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"476\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"35\" name=\"Z\" caption=\"Histogram / Make, find, apply\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"Z1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"4\" window_y=\"53\" window_width=\"547\" window_height=\"729\" image_left=\"257\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Hist_new_item.Hist_item.action\"/>\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z19\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Matrix [[0,0],[128,20],[200,90],[255,255]]\"/>\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Hist_new_item.Hist_new_from_matrix.action Z19\"/>\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z22\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Hist_new_item.Hist_from_image_item.action Z21\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z23\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"d\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Depth\" labelsn=\"2\" labels0=\"8 bit\" labels1=\"16 bit\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"w\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sp\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"mp\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"hp\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Highlight point\" from=\"0.69999999999999996\" to=\"0.90000000000000002\" value=\"0.90000000000000002\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sa\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Shadow adjust\" from=\"-15\" to=\"15\" value=\"-12.25609756097561\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ma\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Mid-tone adjust\" from=\"-30\" to=\"30\" value=\"16.463414634146346\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ha\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Highlight adjust\" from=\"-15\" to=\"15\" value=\"-11.524390243902438\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Hist_new_item.Tone_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Hist_find_item.Oned_item.action Z1\"/>\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Hist_find_item.Nd_item.action Z1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"749\" window_y=\"29\" window_width=\"510\" window_height=\"727\" image_left=\"248\" image_top=\"344\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Hist_map_item.action Z1 Z23\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Hist_eq_item.Global_item.action Z24\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region Z24 48 326 45 46\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Z27\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Hist_eq_item.Local_item.action Z1\"/>\n            <iImage window_x=\"1050\" window_y=\"189\" window_width=\"510\" window_height=\"727\" image_left=\"248\" image_top=\"344\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"993\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"29\" name=\"A\" caption=\"Histogram / Maths\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"4\" window_y=\"53\" window_width=\"547\" window_height=\"729\" image_left=\"257\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A13\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Hist_cum_item.action Z3\"/>\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A14\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Hist_diff_item.action A13\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A15\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"if min (A14 == Z3) == 255 then &quot;ok!&quot; else error &quot;diff (cum a) != a&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A16\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Hist_norm_item.action A13\"/>\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A17\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Hist_match_item.action A13 Z3\"/>\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A27\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Hist_diff_item.action A14\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A28\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"r\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Radius\" from=\"1\" to=\"100\" value=\"10.9\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fac\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shape\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Mask shape\" labelsn=\"2\" labels0=\"Square\" labels1=\"Gaussian\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"prec\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Filter_conv_item.Custom_blur_item.action A27\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A26\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Hist_zerox_item.action A28\"/>\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1529\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"C\" caption=\"Histogram / Profile and Projection\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"4\" window_y=\"53\" window_width=\"547\" window_height=\"729\" image_left=\"257\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C7\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"C1?1 &gt; 128\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                  <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n                </Rhs>\n              </Row>\n              <Row name=\"edge\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Search from\" labelsn=\"4\" labels0=\"Top edge down\" labels1=\"Left edge to right\" labels2=\"Bottom edge up\" labels3=\"Right edge to left\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Hist_profile_item.action C7\"/>\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C9\">\n          <Rhs vislevel=\"2\" flags=\"6\">\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Hist_project_item.action C1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2136\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"D\" caption=\"Histogram / Extract, Plot\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"4\" window_y=\"53\" window_width=\"547\" window_height=\"729\" image_left=\"257\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"VGuide D1 135\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Hist_graph_item.action D5\"/>\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow left=\"395\" top=\"300\" width=\"-197\" height=\"121\">\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Arrow D1 417 184 (-197) 121\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"width\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Width\" from=\"1\" to=\"40\" value=\"9.1319148936170205\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"displace\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"vdisplace\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Extract_arrow_item.action D7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D9\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"format\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Format\" labelsn=\"3\" labels0=\"YYYY\" labels1=\"XYYY\" labels2=\"XYXY\" value=\"2\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"style\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Style\" labelsn=\"4\" labels0=\"Point\" labels1=\"Line\" labels2=\"Spline\" labels3=\"Bar\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"auto\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"xmin\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"X range minimum\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"xmax\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"X range maximum\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ymin\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Y range minimum\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ymax\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Y range maximum\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Hist_plot_item.action Z19\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "test/workspaces/test_image.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace window_x=\"36\" window_y=\"64\" window_width=\"1258\" window_height=\"1134\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" locked=\"false\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"test_image\" caption=\"Default empty workspace\" filename=\"$HOME/GIT/nip2/test/workspaces/test_image.ws\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"17\" name=\"B\" caption=\"Colour / Colourspace\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$VIPSHOME/share/nip2/data/examples/businesscard/slanted_oval_vase2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"517\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"AB\" caption=\"Image / New\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"AB1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nbands\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image bands\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"format_option\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Image format\" labelsn=\"10\" labels0=\"8-bit unsigned int - UCHAR\" labels1=\"8-bit signed int - CHAR\" labels2=\"16-bit unsigned int - USHORT\" labels3=\"16-bit signed int - SHORT\" labels4=\"32-bit unsigned int - UINT\" labels5=\"32-bit signed int - INT\" labels6=\"32-bit float - FLOAT\" labels7=\"64-bit complex - COMPLEX\" labels8=\"64-bit float - DOUBLE\" labels9=\"128-bit complex - DPCOMPLEX\" value=\"4\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"type_option\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Image type\" labelsn=\"17\" labels0=\"MULTIBAND\" labels1=\"B_W\" labels2=\"HISTOGRAM\" labels3=\"XYZ\" labels4=\"LAB\" labels5=\"CMYK\" labels6=\"LABQ\" labels7=\"RGB\" labels8=\"UCS\" labels9=\"LCH\" labels10=\"LABS\" labels11=\"sRGB\" labels12=\"YXY\" labels13=\"FOURIER\" labels14=\"RGB16\" labels15=\"GREY16\" labels16=\"ARRAY\" value=\"2\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"pixel\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixel value\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"Vector [42, 255, 42]\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_new_item.Image_black_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_new_item.Image_new_item.Image_new_item.Image_new_from_image_item.action AB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_new_item.Image_new_item.Image_new_item.Image_region_item.Region_item.action AB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_new_item.Image_new_item.Image_new_item.Image_region_item.Mark_item.action AB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_new_item.Image_new_item.Image_new_item.Image_region_item.Arrow_item.action AB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_new_item.Image_new_item.Image_new_item.Image_region_item.HGuide_item.action AB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_new_item.Image_new_item.Image_new_item.Image_region_item.VGuide_item.action AB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB8\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"99\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AB9\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_convert_to_image_item.action AB8\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1301\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"49\" name=\"BB\" caption=\"Image / Format\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"BB1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB28\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.U8_item.action BB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB29\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.U16_item.action BB28\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB30\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.U32_item.action BB29\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB38\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.S8_item.action BB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB39\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.S16_item.action BB38\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB40\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"749\" window_y=\"463\" window_width=\"510\" window_height=\"727\" image_left=\"239\" image_top=\"299\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.S32_item.action BB39\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB41\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.Float_item.action BB30\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB42\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.Double_item.action BB41\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB43\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"753\" window_y=\"463\" window_width=\"734\" window_height=\"727\" image_left=\"351\" image_top=\"308\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.Scmplxitem.action BB42\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB45\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"749\" window_y=\"463\" window_width=\"782\" window_height=\"727\" image_left=\"375\" image_top=\"308\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.Dcmplx_item.action BB43\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BB48\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"if min (BB45 == B1) == 255 then &quot;ok!&quot; else error &quot;cast uchar -&gt;complx != uchar&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"5933\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"CB\" caption=\"Image / Join\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"CB1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"4\" window_y=\"53\" window_width=\"547\" window_height=\"729\" image_left=\"257\" image_top=\"326\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CB2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"103\" top=\"67\" width=\"147\" height=\"122\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region CB1 44 189 147 154\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CB3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"275\" top=\"248\" width=\"136\" height=\"173\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region CB1 275 248 136 141\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CB10\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Colour colour_space=\"sRGB\" value0=\"114\" value1=\"73\" value2=\"230\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"default_colour\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"default_value\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Colour/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"space\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Colour space\" labelsn=\"6\" labels0=\"sRGB\" labels1=\"Lab\" labels2=\"LCh\" labels3=\"XYZ\" labels4=\"Yxy\" labels5=\"UCS\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Colour value\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Colour_new_item.Widget_colour_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CB4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shim\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Spacing\" from=\"0\" to=\"100\" value=\"78.880407124681938\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bg_colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Background colour\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"CB10\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                        <Colour/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"align\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_join_item.Left_right_item.action CB2 CB3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CB5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"553\" window_y=\"29\" window_width=\"510\" window_height=\"750\" image_left=\"239\" image_top=\"328\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shim\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Spacing\" from=\"0\" to=\"100\" value=\"35.368956743002542\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bg_colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Background colour\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"align\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_join_item.Top_bottom_item.action CB4 CB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CB6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region CB1 19 310 128 132\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CB7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region CB1 206 459 130 106\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CB8\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[[CB2, CB3],[CB6, CB7]]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"CB9\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"hshim\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Horizontal spacing\" from=\"-100\" to=\"100\" value=\"28.459530026109661\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"vshim\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Vertical spacing\" from=\"-100\" to=\"100\" value=\"25.848563968668415\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bg_colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Background colour\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"halign\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"valign\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_join_item.Array_item.action CB8\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"6636\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"DB\" caption=\"Image / Tile\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"DB1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DB2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Group/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_tile_item.Chop_item.action DB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DB3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"hshim\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Horizontal spacing\" from=\"-100\" to=\"100\" value=\"40\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"vshim\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Vertical spacing\" from=\"-100\" to=\"100\" value=\"40\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bg_colour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Background colour\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"halign\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"valign\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_join_item.Array_item.action DB2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"DB4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"default_type\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"across\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Tiles across\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"down\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Tiles down\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"repeat\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Tile type\" labelsn=\"2\" labels0=\"Replicate\" labels1=\"Four-way mirror\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_tile_item.Replicate_item.action DB1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2391\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"EB\" caption=\"Image / Levels\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"EB1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"EB3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_levels_item.Scale_item.action EB2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"EB2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"scale\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Scale\" from=\"0.001\" to=\"3\" value=\"1.5998000000000001\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"offset\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_levels_item.Linear_item.action EB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"EB4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"gamma\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Gamma\" from=\"0.001\" to=\"4\" value=\"2.2693403361344533\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"image_maximum_hint\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"im_mx\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Image maximum\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_levels_item.Gamma_item.action EB3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"EB5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"749\" window_y=\"29\" window_width=\"510\" window_height=\"727\" image_left=\"239\" image_top=\"299\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"w\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sp\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"mp\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"hp\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"sa\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Shadow adjust\" from=\"-15\" to=\"15\" value=\"-7.4594594594594597\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ma\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Mid-tone adjust\" from=\"-30\" to=\"30\" value=\"23.675675675675677\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ha\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Highlight adjust\" from=\"-15\" to=\"15\" value=\"-13.135135135135135\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"curve\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Plot window_x=\"491\" window_y=\"690\" window_width=\"500\" window_height=\"500\" plot_left=\"231\" plot_top=\"200\" plot_mag=\"100\" show_status=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_levels_item.Tone_item.action EB4\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"3191\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"20\" name=\"FB\" caption=\"Image / Transform\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"FB1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"5\" window_y=\"54\" window_width=\"512\" window_height=\"729\" image_left=\"476\" image_top=\"596\" image_mag=\"-2\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_transform_item.Rotate_item.Fixed_item.Rot90_item.action FB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"angle\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Angle\" from=\"-180\" to=\"180\" value=\"-59.754098360655732\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"interp\">\n                <Rhs vislevel=\"2\" flags=\"6\">\n                  <Subcolumn vislevel=\"1\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Rotate_item.Free_item.action FB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow left=\"142\" top=\"688\" width=\"36\" height=\"-634\">\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Arrow FB1 134 680 44 (-626)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_transform_item.Rotate_item.Straighten_item.action FB4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_transform_item.Flip_item.Left_right_item.action FB5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB7\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_transform_item.Flip_item.Top_bottom_item.action FB5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"xfactor\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Horizontal scale factor\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"0.5\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"yfactor\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Vertical scale factor\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"0.5\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"kernel\">\n                <Rhs vislevel=\"2\" flags=\"6\">\n                  <Subcolumn vislevel=\"1\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Resize_item.Scale_item.action FB7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB9\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_transform_item.Resize_item.Size_item.action FB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB19\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"516\" window_y=\"29\" window_width=\"475\" window_height=\"519\" image_left=\"221\" image_top=\"204\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"within\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Fit within (pixels)\" labelsn=\"9\" labels0=\"2048 x 1536\" labels1=\"1920 x 1200\" labels2=\"1600 x 1200\" labels3=\"1400 x 1050\" labels4=\"1280 x 1024\" labels5=\"1024 x 768\" labels6=\"800 x 600\" labels7=\"640 x 480\" labels8=\"Custom\" value=\"7\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"custom_width\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Custom width\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"custom_height\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Custom height\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"size\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"kernel\">\n                <Rhs vislevel=\"2\" flags=\"6\">\n                  <Subcolumn vislevel=\"1\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Resize_item.Size_within_item.action B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB17\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nwidth\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"New width (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"496 * 2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"nheight\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"New height (pixels)\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"688 * 2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bgcolour\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Background colour\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"position\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Position\" labelsn=\"10\" labels0=\"North-west\" labels1=\"North\" labels2=\"North-east\" labels3=\"West\" labels4=\"Centre\" labels5=\"East\" labels6=\"South-west\" labels7=\"South\" labels8=\"South-east\" labels9=\"Specify in pixels\" value=\"4\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"left\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixels from left\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"top\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Pixels from top\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Resize_item.Resize_item.Resize_item.Resize_canvas_item.action FB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"FB15\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"y\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap1\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow>\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bp1\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow>\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ap2\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow>\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"bp2\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow>\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"refine\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle caption=\"Refine selected tie-points\" value=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"lock\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_transform_item.Match_item.action FB1 FB5\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"7490\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"18\" name=\"GB\" caption=\"Image / Patterns\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"GB1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.Grey_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.Xy_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.Noise_item.Gaussian_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.Noise_item.Fractal_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.Checkerboard_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.Grid_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.Text_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.New_CIELAB_slice_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB9\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.New_ideal_item.High_low_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB10\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.New_ideal_item.Ring_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB11\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.New_ideal_item.Band_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB12\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.New_gaussian_item.High_low_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB13\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.New_gaussian_item.Ring_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB14\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.New_gaussian_item.Band_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB15\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.New_butterworth_item.High_low_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB16\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.New_butterworth_item.Ring_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"GB17\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Pattern_images_item.New_butterworth_item.Band_item.action\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"8081\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"8\" name=\"HB\" caption=\"Image / Test\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"HB1\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Test_images_item.Eye_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"HB2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Test_images_item.Zone_plate.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"HB3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Test_images_item.Frequency_test_chart_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"HB4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Test_images_item.CRT_test_chart_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"HB5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Test_images_item.Greyscale_chart_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"HB6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Test_images_item.CMYK_test_chart_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"HB7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"749\" window_y=\"29\" window_width=\"750\" window_height=\"750\" image_left=\"359\" image_top=\"328\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Test_images_item.Colour_atlas_item.action\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4021\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"23\" name=\"A\" caption=\"Image / Band\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"first\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Extract from band\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"1\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"number\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Extract this many bands\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"2 \"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_band_item.Extract_item.action A1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_band_item.Insert_item.action A1 A3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"289\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"first\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Delete from band\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"1\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"number\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Delete this many bands\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"2\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_band_item.Delete_item.action A4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_band_item.Bandwise_item.action A5 A4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A19\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"384\" window_y=\"52\" window_width=\"750\" window_height=\"727\" image_left=\"2208\" image_top=\"1848\" image_mag=\"-6\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"orientation\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Orientation\" labelsn=\"2\" labels0=\"Horizontal\" labels1=\"Vertical\" value=\"0\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_band_item.To_dimension_item.action A18\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"648\" top=\"0\" width=\"3\" height=\"688\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region A19 558 318 3410 54\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A22\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_band_item.To_bands_item.action A20\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_crop_item.action A5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"289\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"place\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"199\" top=\"34\" width=\"248\" height=\"344\">\n                    <iRegiongroup/>\n                  </iRegion>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_insert_item.action A5 A6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1771\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"9\" name=\"C\" caption=\"Image / Header\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"749\" window_y=\"29\" window_width=\"547\" window_height=\"727\" image_left=\"257\" image_top=\"308\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Real/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_header_item.Image_get_item.Width_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Real/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_header_item.Image_get_item.Yres_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"fname\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <String caption=\"Field\" value=\"test\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"val\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Expression caption=\"Value\"/>\n                  <Subcolumn vislevel=\"0\">\n                    <Row name=\"caption\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"expr\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText formula=\"&quot;12:12:12&quot;\"/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"1\" flags=\"4\">\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_header_item.Image_set_meta_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Real/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                  <Real/>\n                </Rhs>\n              </Row>\n              <Row name=\"field\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <String caption=\"Field\" value=\"test\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"parse\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Parse\" labelsn=\"4\" labels0=\"No parsing\" labels1=\"Parse string as integer\" labels2=\"Parse string as real\" labels3=\"Parse string as hh:mm:ss\" value=\"3\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_header_item.Image_get_item.Custom_item.action C6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_header_item.Image_edit_header_item.action C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_cache_item.action C7\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"5075\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"20\" name=\"D\" caption=\"Image / Select\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D17\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage window_x=\"337\" window_y=\"172\" window_width=\"547\" window_height=\"727\" image_left=\"257\" image_top=\"325\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow left=\"364\" top=\"301\" width=\"-250\" height=\"-238\">\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Arrow D17 367 303 (-250) (-238)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D9\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"131\" window_y=\"236\" window_width=\"510\" window_height=\"727\" image_left=\"239\" image_top=\"299\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"control\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Make\" labelsn=\"7\" labels0=\"Selection Brighter\" labels1=\"Selection Darker\" labels2=\"Selection Black\" labels3=\"Selection White\" labels4=\"Background Black\" labels5=\"Background White\" labels6=\"Mask\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"width\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Width\" from=\"0.01\" to=\"1\" value=\"0.30200000000000005\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_select_item.Elipse.action D8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow left=\"295\" top=\"128\" width=\"0\" height=\"0\">\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark D17 363 110\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark D17 71 268\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D12\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark D17 198 530\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow left=\"406\" top=\"411\" width=\"0\" height=\"0\">\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark D17 298 425\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D14\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"a\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"b\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"c\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"d\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"control\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Make\" labelsn=\"7\" labels0=\"Selection Brighter\" labels1=\"Selection Darker\" labels2=\"Selection Black\" labels3=\"Selection White\" labels4=\"Background Black\" labels5=\"Background White\" labels6=\"Mask\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_select_item.Tetragon.action D10 D11 D12 D13\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D15\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Group [D10, D11, D12]\"/>\n            <Group/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D16\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"pt_list\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"control\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Option caption=\"Make\" labelsn=\"7\" labels0=\"Selection Brighter\" labels1=\"Selection Darker\" labels2=\"Selection Black\" labels3=\"Selection White\" labels4=\"Background Black\" labels5=\"Background White\" labels6=\"Mask\" value=\"1\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_select_item.Polygon.action D15\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D18\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"t\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Threshold\" from=\"0\" to=\"255\" value=\"162.18390804597703\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_select_item.Threshold_item.action D17\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D19\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"t\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Percentage of pixels\" from=\"0\" to=\"100\" value=\"14.725274725274726\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Image_select_item.Threshold_percent_item.action D17\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4635\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"14\" name=\"F\" caption=\"Image / Alpha\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"F1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_alpha_item.Add_item.action F1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_alpha_item.Flatten_item.action F2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F4\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"if min (F3 == F1) == 255 then &quot;ok!&quot; else error &quot;erp&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_alpha_item.Extract_item.action F2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if min (F5 == 255) == 255 then &quot;ok!&quot; else error &quot;erp!&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F7\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_alpha_item.Drop_item.action F2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F8\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if min (F7 == F1) == 255 then &quot;ok!&quot; else error &quot;erp&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F9\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"72\" window_y=\"72\" window_width=\"570\" window_height=\"727\" image_left=\"272\" image_top=\"326\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_alpha_item.Premultiply_item.action F2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F11\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_alpha_item.Unpremultiply_item.action F9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F12\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_alpha_item.Drop_item.action F11\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F13\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if min (F12 == F1) == 255 then &quot;ok!&quot; else error &quot;erp&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n"
  },
  {
    "path": "test/workspaces/test_math.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace window_x=\"737\" window_y=\"125\" window_width=\"1280\" window_height=\"772\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" locked=\"false\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"test_math\" caption=\"Default empty workspace\" filename=\"$HOME/GIT/nip2/test/workspaces/test_math.ws\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"17\" name=\"B\" caption=\"Colour / Colourspace\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$VIPSHOME/share/nip2/data/examples/businesscard/slanted_oval_vase2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"453\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"17\" name=\"Y\" caption=\"Math / Arithmetic\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"Y1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_arithmetic_item.Add_item.action Y1 Y3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_arithmetic_item.Subtract_item.action Y4 Y3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y6\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_arithmetic_item.Multiply_item.action Y4 Y5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y7\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"500\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y8\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"289\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_arithmetic_item.Divide_item.action Y6 Y7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y10\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_arithmetic_item.Remainder_item.action Y4 Y7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y12\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_arithmetic_item.Absolute_value_item.action Y10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y11\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_arithmetic_item.Absolute_value_vector_item.action Y10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y13\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_arithmetic_item.Sign_item.action Y11\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y14\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_arithmetic_item.Negate_item.action Y13\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y15\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"max (abs (Y1 - (250 * Y8)**0.5))\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"Y16\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if Y15 &gt; 0.0001 then error &quot;argh&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"956\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"15\" name=\"JB\" caption=\"Math / Trig\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"JB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JB2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_trig_item.Sin_item.action JB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JB3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_trig_item.Cos_item.action JB2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JB4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_trig_item.Tan_item.action JB3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JB5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_trig_item.Atan_item.action JB4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JB6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_trig_item.Acos_item.action JB5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JB7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"289\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_trig_item.Asin_item.action JB6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JB8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_trig_item.Rad_item.action JB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JB9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_trig_item.Deg_item.action JB8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JB11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JB12\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"128\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JB13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"JB14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_trig_item.Angle_range_item.action JB11 JB12 JB13\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1424\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"KB\" caption=\"Math / Log\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"KB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_log_item.Log_natural_item.action KB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_log_item.Exponential_item.action KB4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_log_item.Log10_item.action KB5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_log_item.Exponential10_item.action KB6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB8\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"KB9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_log_item.Raise_to_power_item.action KB7 KB8\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1886\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"8\" name=\"LB\" caption=\"Math / Complex\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"LB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"(2,42)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"LB2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_complex_item.Complex_extract.Real_item.action LB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"LB3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_complex_item.Complex_extract.Imaginary_item.action LB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"LB4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_complex_item.Complex_build_item.action LB2 LB3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"LB5\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_complex_item.Polar_item.action LB4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"LB6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_complex_item.Rectangular_item.action LB5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"LB7\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_complex_item.Conjugate_item.action LB6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2690\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"19\" name=\"MB\" caption=\"Math / Boolean\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"MB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MB2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"MB1 &gt; 128\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MB3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"MB1 &lt; 200\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MB4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_boolean_item.And_item.action MB2 MB3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MB5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_boolean_item.Or_item.action MB2 MB3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MB6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_boolean_item.Eor_item.action MB2 MB3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MB7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_boolean_item.Not_item.action MB6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MB8\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MB9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_boolean_item.Right_shift_item.action MB1 MB8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MB13\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MB14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_boolean_item.Left_shift_item.action MB9 MB13\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MB15\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_boolean_item.Bandor_item.action MB2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MB16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_boolean_item.Bandand_item.action MB2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"MB18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_boolean_item.If_then_else_item.action MB16 MB7 MB6\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4346\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"23\" name=\"OB\" caption=\"Math / List \">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"OB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[1 .. 10]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Head_item.action OB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Tail_item.action OB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Cons_item.action OB2 OB3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB5\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Last_item.action OB4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB7\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Init_item.action OB4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB8\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[OB5]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB9\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Join_item.action OB7 OB8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB10\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Reverse_item.action OB9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Sort_item.action OB10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB12\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[OB11]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB13\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Transpose_list_item.action OB12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB14\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Concat_item.action OB13\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB15\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Length_item.action OB14\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB17\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB18\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Take_item.action OB17 OB14\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB19\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Drop_item.action OB17 OB14\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB20\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Zip_item.action OB18 OB19\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB21\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Transpose_list_item.action OB20\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"OB22\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_list_item.Concat_item.action OB21\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4687\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"PB\" caption=\"Math / Round\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"PB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"B1 + 0.5\"/>\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PB2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Math_round_item.Ceil_item.action PB1\"/>\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PB3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Math_round_item.Floor_item.action PB1\"/>\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"PB4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Math_round_item.Rint_item.action PB1\"/>\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"4998\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"13\" name=\"QB\" caption=\"Math / Fourier\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"QB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"QB3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_fourier_item.Forward_item.action QB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"QB4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_fourier_item.Reverse_item.action QB3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"QB6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"max (abs (QB4 - QB1))\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"QB7\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if QB6 &gt; 0.1 then error &quot;fft broken!&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"QB5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_fourier_item.Rotate_quadrants_item.action QB1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"5462\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"33\" name=\"RB\" caption=\"Math / Statistics\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"RB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_stats_item.Mean_item.action RB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB16\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_stats_item.Gmean_item.action RB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB17\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_stats_item.Zmean_item.action RB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_stats_item.Deviation_item.action RB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB18\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_stats_item.Zdeviation_item.action RB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_stats_item.Stats_item.action RB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB5\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_stats_item.Max_item.action RB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_stats_item.Min_item.action RB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB7\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_stats_item.Maxpos_item.action RB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB8\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_stats_item.Minpos_item.action RB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Hist_find_item.Oned_item.action RB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB25\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_stats_item.Gravity_item.action RB24\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB12\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"RB1?1 &gt; 128\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB21\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_stats_item.Count_set_item.action RB12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB22\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_stats_item.Count_clear_item.action RB12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB15\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Number/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Math_stats_item.Count_edges_item.action RB12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB26\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[1..10]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB28\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"(Vector RB26 * 1.2 + 42).value\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB30\">\n          <Rhs vislevel=\"2\" flags=\"6\">\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Math_stats_item.Linear_regression_item.action RB26 RB28\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB31\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"replicate 10 12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"RB32\">\n          <Rhs vislevel=\"2\" flags=\"6\">\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Math_stats_item.Weighted_linear_regression_item.action RB26 RB28 RB31\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"6055\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"8\" name=\"SB\" caption=\"Math / Base\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"SB1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"42\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"SB2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_base_item.Hexadecimal_item.action SB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"SB3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_base_item.Binary_item.action SB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"SB4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"Math_base_item.Octal_item.action SB1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"6240\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"C\" caption=\"Math / Cluster\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[1,2,3,12,14]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C4\">\n          <Rhs vislevel=\"2\" flags=\"6\">\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Math_stats_item.Cluster_item.action C1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"3164\" y=\"896\" open=\"true\" selected=\"false\" sform=\"false\" next=\"7\" name=\"A\" caption=\"test results of relational\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"[D4,D5,D6,D7,D8,D9]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"map max A4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A5\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if A2 != [255, 255, 0, 0, 255, 0] then error &quot;relational argh&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"3164\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"10\" name=\"D\" caption=\"Math / Relational\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"768\" window_y=\"40\" window_width=\"510\" window_height=\"727\" image_left=\"240\" image_top=\"316\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"if D1 == 255 then 0 else D1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D3\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"D2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_relational_item.Equal_item.action D2 D3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"768\" window_y=\"40\" window_width=\"510\" window_height=\"727\" image_left=\"240\" image_top=\"316\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_relational_item.Not_equal_item.action D3 D4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D6\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"768\" window_y=\"40\" window_width=\"510\" window_height=\"727\" image_left=\"240\" image_top=\"316\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_relational_item.More_item.action D4 D5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D7\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"768\" window_y=\"40\" window_width=\"510\" window_height=\"727\" image_left=\"240\" image_top=\"316\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_relational_item.Less_item.action D5 D6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D8\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_relational_item.Less_equal_item.action D6 D7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D9\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"768\" window_y=\"40\" window_width=\"510\" window_height=\"727\" image_left=\"240\" image_top=\"316\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_relational_item.More_equal_item.action D7 D8\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"3756\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"11\" name=\"E\" caption=\"Math / Relational constant\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"E1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"D2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E2\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"255\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Math_relational_item.Equal_item.action E2 E1\"/>\n            <iImage window_x=\"768\" window_y=\"40\" window_width=\"510\" window_height=\"727\" image_left=\"240\" image_top=\"316\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Math_relational_item.Not_equal_item.action E2 E1\"/>\n            <iImage window_x=\"768\" window_y=\"40\" window_width=\"510\" window_height=\"727\" image_left=\"256\" image_top=\"316\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E6\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"768\" window_y=\"40\" window_width=\"510\" window_height=\"727\" image_left=\"240\" image_top=\"316\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_relational_item.More_item.action E2 E1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E7\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"768\" window_y=\"40\" window_width=\"510\" window_height=\"727\" image_left=\"240\" image_top=\"316\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_relational_item.Less_item.action E2 E1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E8\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"768\" window_y=\"40\" window_width=\"510\" window_height=\"727\" image_left=\"240\" image_top=\"316\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_relational_item.Less_equal_item.action E2 E1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"E9\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"768\" window_y=\"40\" window_width=\"510\" window_height=\"727\" image_left=\"240\" image_top=\"316\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_relational_item.More_equal_item.action E2 E1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"3756\" y=\"784\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"F\" caption=\"test results of relational constant\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"F4\">\n          <Rhs vislevel=\"2\" flags=\"4\">\n            <iText formula=\"[E4,E5,E6,E7,E8,E9]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F2\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"map max F4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"F3\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if F2 != [0, 255, 255, 0, 0, 255] then error &quot;relational argh&quot; else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2172\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"G\" caption=\"Math / Complex\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"G1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"(B1,B1)\"/>\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Math_complex_item.Complex_extract.Real_item.action G1\"/>\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Math_complex_item.Complex_extract.Imaginary_item.action G1\"/>\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Math_complex_item.Complex_build_item.action G2 G3\"/>\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G5\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Math_complex_item.Polar_item.action G4\"/>\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G6\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Math_complex_item.Rectangular_item.action G5\"/>\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G7\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Math_complex_item.Conjugate_item.action G6\"/>\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G8\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Math_complex_item.Conjugate_item.action G7\"/>\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G10\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"max (abs (re (G8 - G1)))\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"G11\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if G10 &gt; 0.0001 then error (&quot;argh &quot; ++ print G10) else &quot;ok!&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "test/workspaces/test_matrix.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace filename=\"test_matrix.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" window_width=\"1920\" window_height=\"1165\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"test_matrix\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"17\" name=\"B\" caption=\"Colour / Colourspace\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$VIPSHOME/share/nip2/data/examples/businesscard/slanted_oval_vase2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"476\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"7\" name=\"TB\" caption=\"Matrix / New\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"TB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_build_item.Plain_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TB2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_build_item.Convolution_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TB3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_build_item.Recombination_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TB4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_build_item.Morphology_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TB5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Matrix_build_item.Matrix_gaussian_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"TB6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <Matrix/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"integer\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle caption=\"Integer\" value=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"s\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"ma\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Matrix_build_item.Matrix_laplacian_item.action\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1105\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"5\" name=\"VB\" caption=\"Matrix / Extract\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"VB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"TB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VB2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Matrix_extract_item.Rows_item.action VB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VB3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Matrix_extract_item.Columns_item.action VB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"VB4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Matrix_extract_item.Diagonal_item.action VB1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1486\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"WB\" caption=\"Matrix / Insert\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"WB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"TB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WB2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Matrix_insert_item.Rows_item.action WB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"WB3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Matrix_insert_item.Columns_item.action WB1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1879\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"XB\" caption=\"Matrix / Delete\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"XB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"TB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"XB2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Matrix_delete_item.Rows_item.action XB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"XB3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Matrix_delete_item.Columns_item.action XB1\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2795\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"YB\" caption=\"Matrix / Rotate\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"YB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"TB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"YB2\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Matrix_rotate_item.rot90.action XB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"YB3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Matrix_rotate_item.rot180.action YB2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"YB4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Matrix/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Matrix_rotate_item.rot270.action YB3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"YB5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_rotate_item.Matrix_rot45_item.action YB4\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"3206\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"4\" name=\"ZB\" caption=\"Matrix / Flip\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"ZB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"TB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"ZB2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_flip_item.Left_right_item.action ZB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"ZB3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_flip_item.Top_bottom_item.action ZB2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"3518\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"14\" name=\"AC\" caption=\"Matrix\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"AC1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix valuen=\"9\" value0=\"1\" value1=\"13\" value2=\"42\" value3=\"12\" value4=\"1\" value5=\"2\" value6=\"1\" value7=\"22\" value8=\"1\" width=\"3\" height=\"3\" scale=\"1\" offset=\"0\" filename=\"\" display=\"0\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"TB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AC2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_invert_item.action AC1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AC3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_transpose_item.action AC2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AC4\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Image_convert_to_image_item.action AC3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AC5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_to_matrix_item.action AC4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AC6\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[1, 10..360]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AC7\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"map sin AC6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AC10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iText formula=\"Matrix (zip2 AC6 AC7)\"/>\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AC12\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Matrix_plot_scatter_item.action AC10\"/>\n            <Plot plot_left=\"0\" plot_top=\"0\" plot_mag=\"100\" show_status=\"false\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"AC13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"561\" window_y=\"29\" window_width=\"472\" window_height=\"390\" image_left=\"220\" image_top=\"139\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_buildlut_item.action AC10\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2253\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"A\" caption=\"Matrix / Join\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"TB1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"0\" flags=\"4\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"TB2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_join.Left_right_item.action A1 A2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Matrix_join.Top_bottom_item.action A1 A2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "test/workspaces/test_snip.def",
    "content": "// all the image formats we test, and their matching number format\n// we can't use uchar as a number format directly since it'll become 'a' or\n// whatever and arithmetic ops will start failing\nfmts = [\n\t[\"uchar\", cast_unsigned_char, cast_unsigned_int @ cast_unsigned_char],\n\t[\"char\", cast_signed_char, cast_signed_int @ cast_signed_char],\n\t[\"ushort\", cast_unsigned_short, cast_unsigned_short],\n\t[\"short\", cast_signed_short, cast_signed_short],\n\t[\"uint\", cast_unsigned_int, cast_unsigned_int],\n\t[\"int\", cast_signed_int, cast_signed_int],\n\t[\"float\", cast_float, cast_float],\n\t[\"double\", cast_double, cast_double],\n\t[\"complex\", cast_complex, cast_complex],\n\t[\"dcomplex\", cast_double_complex, cast_double_complex]\n];\n\n// we need a to_real that does images as well\nto_real x\n\t= abs x, is_complex x\n\t= mean x, is_Image x\n\t= x;\n\n// numbers we test\nnumbers = [-10, 0, 1, 10, 3.1415927];\n\ntest_unary op_name fn\n\t= foldr1 logical_and\n\t\t[test fname ifmt nfmt x :: [fname, ifmt, nfmt] <- fmts; x <- numbers]\n{\n\t// image == number can fail due to rounding differences\n\ttest fname ifmt nfmt x\n\t\t= true, abs (image - number) < 0.001\n\t\t= error (join_sep \" \" (map print \n\t\t\t[\"unary\", fname, op_name, x, \"==\", image, number]))\n\t{\n\t\timage = (to_real @ fn @ ifmt @ to_image) x;\n\t\tnumber = (to_real @ fn @ nfmt) x;\n\t}\n}\n\ntest_binary op_name fn\n\t= foldr1 logical_and\n\t\t[test fname ifmt nfmt x y :: \n\t\t\t[fname, ifmt, nfmt] <- fmts; x <- numbers; y <- numbers]\n{\n\t// image == number can fail due to rounding differences\n\ttest fname ifmt nfmt x y\n\t\t= true, abs (image - number) < 0.001\n\t\t= error (join_sep \" \" (map print \n\t\t\t[\"binary\", fname, x, op_name, y, \"==\", image, number]))\n\t{\n\t\timage = to_real (fn ((ifmt @ to_image) x) ((ifmt @ to_image) y));\n\t\tnumber = to_real (fn (nfmt x) (nfmt y));\n\t}\n}\n\ntests = [\n\ttest_binary \"add\" add,\n\ttest_binary \"subtract\" subtract,\n\ttest_binary \"multiply\" multiply,\n\ttest_binary \"divide\" test_div,\n\ttest_unary \"square\" square,\n\ttest_unary \"constant plus\" (add 12),\n\ttest_unary \"plus constant\" (converse add 12),\n\ttest_unary \"divided by constant\" (converse test_div 3),\n\ttest_unary \"multiply constant\" (multiply 7),\n\ttest_unary \"constant multiplied by\" (converse multiply 7),\n\ttest_unary \"constant subtracted from\" (subtract 4),\n\ttest_unary \"subtract constant\" (converse subtract 4),\n\t\"\" ++ \"a\" == \"a\",\n\thd [1, error \"nope\"] == 1\n]\n{\n\t// libvips divide returns 0 for divide by zero\n\ttest_div a b\n\t\t= 0, is_real b && b == 0\n\t\t= 0, is_complex b && re b == 0 && im b == 0\n\t\t= divide a b;\n}\n\nmain \n\t= \"all tests pass\", fail == []\n\t= \"failed: \" ++ join_sep \", \" (map print fail_numbers)\n{\n\tnumbered = zip2 tests [1..];\n\tfail = filter (not @ extract 0) numbered;\n\tfail_numbers = map (extract 1) failed;\n}\n\n"
  },
  {
    "path": "test/workspaces/test_stats.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace window_x=\"0\" window_y=\"0\" window_width=\"928\" window_height=\"743\" filename=\"test_stats.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" lpane_position=\"100\" lpane_open=\"false\" rpane_position=\"400\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"test_stats\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"30\" name=\"A\" caption=\"make test image\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"2\" window_y=\"56\" window_width=\"526\" window_height=\"727\" image_left=\"4096\" image_top=\"5200\" image_mag=\"-16\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$VIPSHOME/share/nip2/data/examples/businesscard/slanted_oval_vase2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A1 * 8.1 - 100\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A3 ++ A3 * 0.6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A8 ++ (0.1 * A8)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A11\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A10 ++ (A10 * 1.3)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A12\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A11 ++ (A11 * 0.7)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"2\" window_y=\"56\" window_width=\"928\" window_height=\"727\" image_left=\"914\" image_top=\"650\" image_mag=\"-2\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_number_format_item.S32_item.action A12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"104\" top=\"80\" width=\"146\" height=\"162\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region A4 4018 3668 2184 1694\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1202\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"B\" caption=\"test max\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Vector (map max (bandsplit A4))\"/>\n            <Vector/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Vector (map max (bandsplit A13))\"/>\n            <Vector/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Vector/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B2 &lt;= B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"min B3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"B5\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if B4 == 0 then error &quot;max is broken!&quot; else &quot;ok&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1202\" y=\"276\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"C\" caption=\"test min\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"C1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Vector (map min (bandsplit A4))\"/>\n            <Vector/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iText formula=\"Vector (map min (bandsplit A13))\"/>\n            <Vector/>\n            <Subcolumn vislevel=\"0\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C3\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Vector/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"C2 &gt;= C1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"min C3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"C5\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if C4 == 0 then error &quot;max is broken!&quot; else &quot;ok&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"468\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"22\" name=\"D\" caption=\"test stats\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"D20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A4\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"A13\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D9\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_stats_item.Stats_item.action D20\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D10\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Math_stats_item.Stats_item.action D21\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D11\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iText formula=\"Vector (transpose (D9.extract 0 0 1 49).value)?0\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <Vector/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D12\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iText formula=\"Vector (transpose (D10.extract 0 0 1 49).value)?0\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <Vector/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D13\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"D12 &gt;= D11\"/>\n            <Vector/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D14\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"min D13\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D15\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iText formula=\"Vector (transpose (D9.extract 1 0 1 49).value)?0\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <Vector/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D16\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iText formula=\"Vector (transpose (D10.extract 1 0 1 49).value)?0\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <Vector/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D17\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"D16 &lt;= D15\"/>\n            <Vector/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D18\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"min D17\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"D19\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"if D14 != 255 || D18 != 255 then error &quot;VipsStats failed!&quot; else &quot;ok&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "test/workspaces/test_tasks.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace filename=\"test_tasks.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" window_width=\"1920\" window_height=\"1165\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"test_tasks\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"17\" name=\"B\" caption=\"Colour / Colourspace\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"B1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"229\" image_top=\"309\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"true\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file &quot;$VIPSHOME/share/nip2/data/examples/businesscard/slanted_oval_vase2.jpg&quot;\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"476\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"33\" name=\"BC\" caption=\"Tasks / Capture\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"BC2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC3\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Tasks_capture_item.Smooth_image_item.action BC2\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_capture_item.Light_correct_item.action BC2 BC3\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC5\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"[BC2,BC3,BC4]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC6\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Tasks_capture_item.Image_rank_item.action BC5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC7\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"tilt\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Left-right tilt\" from=\"-1\" to=\"1\" value=\"-0.40000000000000002\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_capture_item.Tilt_item.Left_right_item.action B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC8\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"tilt\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Top-bottom tilt\" from=\"-1\" to=\"1\" value=\"-0.40000000000000002\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_capture_item.Tilt_item.Top_bottom_item.action BC7\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC9\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"tilt\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Left-right tilt\" from=\"-1\" to=\"1\" value=\"-0.40000000000000002\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shift\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Shift by\" from=\"-1\" to=\"1\" value=\"0.40000000000000002\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_capture_item.Tilt_item.Left_right_cos_item.action BC8\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC10\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"tilt\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Top-bottom tilt\" from=\"-1\" to=\"1\" value=\"-0.40000000000000002\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"shift\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_capture_item.Tilt_item.Top_bottom_cos_item.action BC9\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC11\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"3\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"tilt\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Tilt\" from=\"-1\" to=\"1\" value=\"0.60000000000000009\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"hshift\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"vshift\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_capture_item.Tilt_item.Circular_item.action BC10\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC12\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region BC2 336 80 35 47\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC13\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Tasks_capture_item.White_balance_item.action BC11 BC12\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC16\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\"/>\n            <iText formula=\"Tasks_capture_item.Tone_item.action BC14\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC22\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"30\" window_width=\"625\" window_height=\"750\" image_left=\"296\" image_top=\"432\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"x\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"angle\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider caption=\"Angle\" from=\"-180\" to=\"180\" value=\"-3.8297872340425556\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_capture_item.Rotate_item.Free_item.action BC21\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"BC30\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iRegion image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region BC22 0 0 496 688\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1100\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"31\" name=\"UB\" caption=\"Tasks / Mosaic / Onepoint|Twopoint\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"UB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"5\" window_y=\"54\" window_width=\"512\" window_height=\"729\" image_left=\"240\" image_top=\"318\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"B1\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion window_x=\"193\" window_y=\"129\" window_width=\"613\" window_height=\"909\" image_left=\"299\" image_top=\"417\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"27\" top=\"54\" width=\"202\" height=\"453\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region UB1 50 171 202 228\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion window_x=\"848\" window_y=\"305\" window_width=\"613\" window_height=\"284\" image_left=\"72\" image_top=\"28\" image_mag=\"4\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\" left=\"180\" top=\"75\" width=\"180\" height=\"448\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region UB1 193 248 180 243\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark UB2 182 53\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow left=\"30\" top=\"31\" width=\"0\" height=\"0\">\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark UB3 11 22\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_1point_item.Left_right_item.action UB4 UB5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB10\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion window_x=\"0\" window_y=\"30\" window_width=\"613\" window_height=\"237\" image_left=\"290\" image_top=\"81\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region UB1 52 189 372 196\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB12\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion window_x=\"5\" window_y=\"54\" window_width=\"613\" window_height=\"249\" image_left=\"290\" image_top=\"87\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region UB1 12 250 433 208\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB13\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark UB10 318 104\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB14\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark UB12 362 47\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB15\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_1point_item.Top_bottom_item.action UB13 UB14\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB16\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_1point_item.Left_right_manual_item.action UB4 UB5\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB17\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_1point_item.Top_bottom_manual_item.action UB13 UB14\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB18\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"10\" window_y=\"78\" window_width=\"569\" window_height=\"750\" image_left=\"268\" image_top=\"328\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"BC22\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB19\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion window_x=\"463\" window_y=\"317\" window_width=\"446\" window_height=\"260\" image_left=\"378\" image_top=\"20\" image_mag=\"4\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region UB18 26 289 430 219\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB20\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark UB19 378 40\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB21\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow left=\"139\" top=\"42\" width=\"0\" height=\"0\">\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark UB19 150 23\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB22\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark UB10 81 131\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB23\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_2point_item.Top_bottom_item.action UB13 UB20 UB21 UB22\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB24\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iRegion window_x=\"849\" window_y=\"110\" window_width=\"374\" window_height=\"497\" image_left=\"171\" image_top=\"211\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\">\n              <iRegiongroup/>\n            </iRegion>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Region UB18 213 78 158 456\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB25\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark UB24 45 42\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB26\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark UB24 8 402\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB27\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iArrow>\n              <iRegiongroup/>\n            </iArrow>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Mark UB2 175 410\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"UB28\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"0\" image_top=\"0\" image_mag=\"0\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"0\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Mosaic_2point_item.Left_right_item.action UB4 UB27 UB26 UB25\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"1733\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"12\" name=\"IB\" caption=\"Tasks / Mosaic / Manual Balance\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"IB8\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;$VIPSHOME/share/nip2/data/examples/manual_balance/&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IB1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage window_x=\"602\" window_y=\"480\" window_width=\"745\" window_height=\"689\" image_left=\"364\" image_top=\"276\" image_mag=\"1\" show_status=\"true\" show_paintbox=\"false\" show_convert=\"true\" show_rulers=\"false\" scale=\"1\" offset=\"0\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file (IB8 ++ &quot;simp_base.png&quot;)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IB2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file (IB8 ++ &quot;mask_control.png&quot;)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IB3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file (IB8 ++ &quot;mask_01.png&quot;)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IB4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file (IB8 ++ &quot;mask_02.png&quot;)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IB5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file (IB8 ++ &quot;mask_03.png&quot;)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IB6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Group/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Group [IB3,IB4,IB5]\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IB9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Matrix/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Manual_balance_item.Balance_find_item.action IB1 IB2 IB6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IB10\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"im_in\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"m_matrix\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"m_group\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"blur\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Slider/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"adjust\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Matrix/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"Build\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <Toggle caption=\"Build Scale and Offset Correction Images\" value=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"Output\">\n                <Rhs vislevel=\"2\" flags=\"6\">\n                  <Subcolumn vislevel=\"1\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"value\">\n                <Rhs vislevel=\"1\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_mosaic_item.Manual_balance_item.Balance_check_item.action IB1 IB9 IB6\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"IB11\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"2997\" window_y=\"620\" window_width=\"516\" window_height=\"543\" image_left=\"240\" image_top=\"240\" image_mag=\"1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Tasks_mosaic_item.Manual_balance_item.Balance_apply_item.action IB1 IB10.Output.scale_im IB10.Output.offset_im\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n    <Column x=\"2568\" y=\"0\" open=\"true\" selected=\"false\" sform=\"false\" next=\"6\" name=\"EC\" caption=\"Tasks / Mosaic / Clone\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"EC4\">\n          <Rhs vislevel=\"1\" flags=\"4\">\n            <iText formula=\"&quot;$VIPSHOME/share/nip2/data/examples/clone/&quot;\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"EC1\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"225\" window_y=\"466\" window_width=\"1108\" window_height=\"532\" image_left=\"305\" image_top=\"70\" image_mag=\"4\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file (EC4 ++ &quot;example_im_01.png&quot;)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"EC2\">\n          <Rhs vislevel=\"2\" flags=\"5\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"478\" window_height=\"526\" image_left=\"58\" image_top=\"57\" image_mag=\"4\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Image_file (EC4 ++ &quot;example_im_02.png&quot;)\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"EC5\">\n          <Rhs vislevel=\"3\" flags=\"7\">\n            <iImage window_x=\"0\" window_y=\"0\" window_width=\"639\" window_height=\"532\" image_left=\"364\" image_top=\"90\" image_mag=\"4\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n            <Subcolumn vislevel=\"1\">\n              <Row name=\"im1\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"im2\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"super\">\n                <Rhs vislevel=\"0\" flags=\"4\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"r1\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iRegion image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\" left=\"406\" top=\"49\" width=\"28\" height=\"37\">\n                    <iRegiongroup/>\n                  </iRegion>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"p2\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iArrow left=\"86\" top=\"23\" width=\"0\" height=\"0\">\n                    <iRegiongroup/>\n                  </iArrow>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"mask\">\n                <Rhs vislevel=\"1\" flags=\"1\">\n                  <iImage image_left=\"-1\" image_top=\"-1\" image_mag=\"-1\" show_status=\"false\" show_paintbox=\"false\" show_convert=\"false\" show_rulers=\"false\" scale=\"-1\" offset=\"-1\" falsecolour=\"false\" type=\"true\"/>\n                  <Subcolumn vislevel=\"0\"/>\n                  <iText/>\n                </Rhs>\n              </Row>\n              <Row name=\"Options\">\n                <Rhs vislevel=\"3\" flags=\"6\">\n                  <Subcolumn vislevel=\"2\">\n                    <Row name=\"super\">\n                      <Rhs vislevel=\"0\" flags=\"4\">\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"pause\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Toggle caption=\"Pause process\" value=\"true\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"replace\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Option/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"balance\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Toggle/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"process\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Toggle caption=\"Replace area with Gaussian noise.\" value=\"false\"/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                    <Row name=\"sc\">\n                      <Rhs vislevel=\"1\" flags=\"1\">\n                        <Slider/>\n                        <Subcolumn vislevel=\"0\"/>\n                        <iText/>\n                      </Rhs>\n                    </Row>\n                  </Subcolumn>\n                  <iText/>\n                </Rhs>\n              </Row>\n            </Subcolumn>\n            <iText formula=\"Tasks_mosaic_item.Clone_area_item.action EC1 EC2\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  },
  {
    "path": "test/workspaces/test_widgets.ws",
    "content": "<?xml version=\"1.0\"?>\n<root xmlns=\"http://www.vips.ecs.soton.ac.uk/nip/8.5.0\">\n  <Workspace filename=\"test_widgets.ws\" view=\"WORKSPACE_MODE_REGULAR\" scale=\"1\" offset=\"0\" window_width=\"1920\" window_height=\"1165\" lpane_position=\"400\" lpane_open=\"false\" rpane_position=\"100\" rpane_open=\"false\" local_defs=\"// private definitions for this workspace&#10;\" name=\"test_widgets\" caption=\"Default empty workspace\">\n    <Column x=\"0\" y=\"0\" open=\"true\" selected=\"true\" sform=\"false\" next=\"10\" name=\"A\" caption=\"Widgets\">\n      <Subcolumn vislevel=\"3\">\n        <Row popup=\"false\" name=\"A1\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Slider/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Widget_slider_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A2\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Toggle/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Widget_toggle_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A3\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Option/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Widget_option_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A4\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <String/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Widget_string_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A5\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Number/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Widget_number_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A6\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Expression caption=\"Enter an expression\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Widget_expression_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A7\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Pathname/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Widget_pathname_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A8\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Fontname/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Widget_font_item.action\"/>\n          </Rhs>\n        </Row>\n        <Row popup=\"false\" name=\"A9\">\n          <Rhs vislevel=\"1\" flags=\"1\">\n            <Clock interval=\"1\" value=\"1966.4855685240002\"/>\n            <Subcolumn vislevel=\"0\"/>\n            <iText formula=\"Widget_clock_item.action\"/>\n          </Rhs>\n        </Row>\n      </Subcolumn>\n    </Column>\n  </Workspace>\n</root>\n\n\n\n"
  }
]